NAT64: Hairpinning (VPP-699)
Change-Id: I83a6c277fa211ac2c2ca2d603650c992886af0a7 Signed-off-by: Matus Fabian <matfabia@cisco.com>
This commit is contained in:
@ -95,7 +95,10 @@ nat64_add_del_pool_addr (ip4_address_t * addr, u32 vrf_id, u8 is_add)
|
||||
|
||||
vec_add2 (nm->addr_pool, a, 1);
|
||||
a->addr = *addr;
|
||||
a->fib_index = ip4_fib_index_from_table_id (vrf_id);
|
||||
a->fib_index = 0;
|
||||
if (vrf_id != ~0)
|
||||
a->fib_index =
|
||||
fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, vrf_id);
|
||||
#define _(N, i, n, s) \
|
||||
clib_bitmap_alloc (a->busy_##n##_port_bitmap, 65535);
|
||||
foreach_snat_protocol
|
||||
@ -218,7 +221,7 @@ nat64_alloc_out_addr_and_port (u32 fib_index, snat_protocol_t proto,
|
||||
nat64_main_t *nm = &nat64_main;
|
||||
snat_main_t *sm = &snat_main;
|
||||
int i;
|
||||
snat_address_t *a;
|
||||
snat_address_t *a, *ga = 0;
|
||||
u32 portnum;
|
||||
|
||||
for (i = 0; i < vec_len (nm->addr_pool); i++)
|
||||
@ -230,22 +233,27 @@ nat64_alloc_out_addr_and_port (u32 fib_index, snat_protocol_t proto,
|
||||
case SNAT_PROTOCOL_##N: \
|
||||
if (a->busy_##n##_ports < (65535-1024)) \
|
||||
{ \
|
||||
while (1) \
|
||||
if (a->fib_index == fib_index) \
|
||||
{ \
|
||||
portnum = random_u32 (&sm->random_seed); \
|
||||
portnum &= 0xFFFF; \
|
||||
if (portnum < 1024) \
|
||||
continue; \
|
||||
if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
|
||||
portnum)) \
|
||||
continue; \
|
||||
clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
|
||||
portnum, 1); \
|
||||
a->busy_##n##_ports++; \
|
||||
*port = portnum; \
|
||||
addr->as_u32 = a->addr.as_u32; \
|
||||
return 0; \
|
||||
} \
|
||||
while (1) \
|
||||
{ \
|
||||
portnum = random_u32 (&sm->random_seed); \
|
||||
portnum &= 0xFFFF; \
|
||||
if (portnum < 1024) \
|
||||
continue; \
|
||||
if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
|
||||
portnum)) \
|
||||
continue; \
|
||||
clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
|
||||
portnum, 1); \
|
||||
a->busy_##n##_ports++; \
|
||||
*port = portnum; \
|
||||
addr->as_u32 = a->addr.as_u32; \
|
||||
return 0; \
|
||||
} \
|
||||
} \
|
||||
else if (a->fib_index == 0) \
|
||||
ga = a; \
|
||||
} \
|
||||
break;
|
||||
foreach_snat_protocol
|
||||
@ -254,8 +262,39 @@ nat64_alloc_out_addr_and_port (u32 fib_index, snat_protocol_t proto,
|
||||
clib_warning ("unknown protocol");
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (ga)
|
||||
{
|
||||
switch (proto)
|
||||
{
|
||||
#define _(N, j, n, s) \
|
||||
case SNAT_PROTOCOL_##N: \
|
||||
while (1) \
|
||||
{ \
|
||||
portnum = random_u32 (&sm->random_seed); \
|
||||
portnum &= 0xFFFF; \
|
||||
if (portnum < 1024) \
|
||||
continue; \
|
||||
if (clib_bitmap_get_no_check (a->busy_##n##_port_bitmap, \
|
||||
portnum)) \
|
||||
continue; \
|
||||
clib_bitmap_set_no_check (a->busy_##n##_port_bitmap, \
|
||||
portnum, 1); \
|
||||
a->busy_##n##_ports++; \
|
||||
*port = portnum; \
|
||||
addr->as_u32 = a->addr.as_u32; \
|
||||
return 0; \
|
||||
}
|
||||
break;
|
||||
foreach_snat_protocol
|
||||
#undef _
|
||||
default:
|
||||
clib_warning ("unknown protocol");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Totally out of translations to use... */
|
||||
//TODO: IPFix
|
||||
return 1;
|
||||
|
@ -107,7 +107,7 @@ nat64_cli_pool_walk (snat_address_t * ap, void *ctx)
|
||||
if (ap->fib_index != ~0)
|
||||
{
|
||||
fib_table_t *fib;
|
||||
fib = fib_table_get (ap->fib_index, FIB_PROTOCOL_IP4);
|
||||
fib = fib_table_get (ap->fib_index, FIB_PROTOCOL_IP6);
|
||||
if (!fib)
|
||||
return -1;
|
||||
vlib_cli_output (vm, " %U tenant VRF: %u", format_ip4_address,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -27,8 +27,9 @@ static u8 well_known_prefix[] = {
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
};
|
||||
/* *INDENT-ON* */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u32 sw_if_index;
|
||||
@ -95,10 +96,13 @@ nat64_out2in_tcp_udp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6,
|
||||
ip46_address_t saddr, daddr;
|
||||
ip6_address_t ip6_saddr;
|
||||
udp_header_t *udp = ip4_next_header (ip4);
|
||||
tcp_header_t *tcp = ip4_next_header (ip4);
|
||||
snat_protocol_t proto = ip_proto_to_snat_proto (ip4->protocol);
|
||||
u16 dport = udp->dst_port;
|
||||
u16 sport = udp->src_port;
|
||||
u32 sw_if_index, fib_index;
|
||||
u16 *checksum;
|
||||
ip_csum_t csum;
|
||||
|
||||
sw_if_index = vnet_buffer (ctx->b)->sw_if_index[VLIB_RX];
|
||||
fib_index = ip4_fib_table_get_index_for_sw_if_index (sw_if_index);
|
||||
@ -142,6 +146,16 @@ nat64_out2in_tcp_udp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6,
|
||||
ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
|
||||
udp->dst_port = bibe->in_port;
|
||||
|
||||
if (proto == SNAT_PROTOCOL_UDP)
|
||||
checksum = &udp->checksum;
|
||||
else
|
||||
checksum = &tcp->checksum;
|
||||
csum = ip_csum_sub_even (*checksum, dport);
|
||||
csum = ip_csum_add_even (csum, udp->dst_port);
|
||||
*checksum = ip_csum_fold (csum);
|
||||
|
||||
vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -205,6 +219,7 @@ nat64_out2in_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6, void *arg)
|
||||
ip6->dst_address.as_u64[1] = bibe->in_addr.as_u64[1];
|
||||
((u16 *) (icmp))[2] = bibe->in_port;
|
||||
|
||||
vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -269,12 +284,17 @@ nat64_out2in_inner_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6,
|
||||
ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
|
||||
ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
|
||||
((u16 *) (icmp))[2] = bibe->in_port;
|
||||
|
||||
vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
udp_header_t *udp = ip4_next_header (ip4);
|
||||
tcp_header_t *tcp = ip4_next_header (ip4);
|
||||
u16 dport = udp->dst_port;
|
||||
u16 sport = udp->src_port;
|
||||
u16 *checksum;
|
||||
ip_csum_t csum;
|
||||
|
||||
ste =
|
||||
nat64_db_st_entry_find (&nm->db, &saddr, &daddr, sport, dport, proto,
|
||||
@ -291,6 +311,19 @@ nat64_out2in_inner_icmp_set_cb (ip4_header_t * ip4, ip6_header_t * ip6,
|
||||
ip6->src_address.as_u64[0] = bibe->in_addr.as_u64[0];
|
||||
ip6->src_address.as_u64[1] = bibe->in_addr.as_u64[1];
|
||||
udp->src_port = bibe->in_port;
|
||||
|
||||
if (proto == SNAT_PROTOCOL_UDP)
|
||||
checksum = &udp->checksum;
|
||||
else
|
||||
checksum = &tcp->checksum;
|
||||
if (*checksum)
|
||||
{
|
||||
csum = ip_csum_sub_even (*checksum, sport);
|
||||
csum = ip_csum_add_even (csum, udp->src_port);
|
||||
*checksum = ip_csum_fold (csum);
|
||||
}
|
||||
|
||||
vnet_buffer (ctx->b)->sw_if_index[VLIB_TX] = bibe->fib_index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1245,7 +1245,7 @@ static void *vl_api_nat64_add_del_pool_addr_range_t_print
|
||||
{
|
||||
u8 *s;
|
||||
|
||||
s = format (0, "SCRIPT: nat64_add_del_pool_addr_range");
|
||||
s = format (0, "SCRIPT: nat64_add_del_pool_addr_range ");
|
||||
s = format (s, "%U - %U vrf_id %u %s\n",
|
||||
format_ip4_address, mp->start_addr,
|
||||
format_ip4_address, mp->end_addr,
|
||||
@ -1273,7 +1273,7 @@ nat64_api_pool_walk (snat_address_t * a, void *arg)
|
||||
clib_memcpy (rmp->address, &(a->addr), 4);
|
||||
if (a->fib_index != ~0)
|
||||
{
|
||||
fib_table_t *fib = fib_table_get (a->fib_index, FIB_PROTOCOL_IP4);
|
||||
fib_table_t *fib = fib_table_get (a->fib_index, FIB_PROTOCOL_IP6);
|
||||
if (!fib)
|
||||
return -1;
|
||||
rmp->vrf_id = ntohl (fib->ft_table_id);
|
||||
|
@ -321,17 +321,9 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx,
|
||||
//We have an ICMP inside an ICMP
|
||||
//It needs to be translated, but not for error ICMP messages
|
||||
icmp46_header_t *inner_icmp = (icmp46_header_t *) (inner_ip4 + 1);
|
||||
csum = inner_icmp->checksum;
|
||||
//Only types ICMP4_echo_request and ICMP4_echo_reply are handled by icmp_to_icmp6_header
|
||||
csum = ip_csum_sub_even (csum, *((u16 *) inner_icmp));
|
||||
inner_icmp->type = (inner_icmp->type == ICMP4_echo_request) ?
|
||||
ICMP6_echo_request : ICMP6_echo_reply;
|
||||
csum = ip_csum_add_even (csum, *((u16 *) inner_icmp));
|
||||
csum =
|
||||
ip_csum_add_even (csum, clib_host_to_net_u16 (IP_PROTOCOL_ICMP6));
|
||||
csum =
|
||||
ip_csum_add_even (csum, inner_ip4->length - sizeof (*inner_ip4));
|
||||
inner_icmp->checksum = ip_csum_fold (csum);
|
||||
inner_L4_checksum = &inner_icmp->checksum;
|
||||
inner_ip4->protocol = IP_PROTOCOL_ICMP6;
|
||||
}
|
||||
@ -341,8 +333,6 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx,
|
||||
os_panic ();
|
||||
}
|
||||
|
||||
csum = *inner_L4_checksum; //Initial checksum of the inner L4 header
|
||||
|
||||
inner_ip6->ip_version_traffic_class_and_flow_label =
|
||||
clib_host_to_net_u32 ((6 << 28) + (inner_ip4->tos << 20));
|
||||
inner_ip6->payload_length =
|
||||
@ -367,14 +357,42 @@ icmp_to_icmp6 (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx,
|
||||
sizeof (*inner_frag));
|
||||
}
|
||||
|
||||
/* UDP checksum is optional */
|
||||
if (csum)
|
||||
csum = *inner_L4_checksum;
|
||||
if (inner_ip6->protocol == IP_PROTOCOL_ICMP6)
|
||||
{
|
||||
csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[0]);
|
||||
csum = ip_csum_add_even (csum, inner_ip6->src_address.as_u64[1]);
|
||||
csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[0]);
|
||||
csum = ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[1]);
|
||||
*inner_L4_checksum = ip_csum_fold (csum);
|
||||
//Recompute ICMP checksum
|
||||
icmp46_header_t *inner_icmp = (icmp46_header_t *) (inner_ip4 + 1);
|
||||
|
||||
inner_icmp->checksum = 0;
|
||||
csum = ip_csum_with_carry (0, inner_ip6->payload_length);
|
||||
csum =
|
||||
ip_csum_with_carry (csum,
|
||||
clib_host_to_net_u16 (inner_ip6->protocol));
|
||||
csum = ip_csum_with_carry (csum, inner_ip6->src_address.as_u64[0]);
|
||||
csum = ip_csum_with_carry (csum, inner_ip6->src_address.as_u64[1]);
|
||||
csum = ip_csum_with_carry (csum, inner_ip6->dst_address.as_u64[0]);
|
||||
csum = ip_csum_with_carry (csum, inner_ip6->dst_address.as_u64[1]);
|
||||
csum =
|
||||
ip_incremental_checksum (csum, inner_icmp,
|
||||
clib_net_to_host_u16
|
||||
(inner_ip6->payload_length));
|
||||
inner_icmp->checksum = ~ip_csum_fold (csum);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* UDP checksum is optional */
|
||||
if (csum)
|
||||
{
|
||||
csum =
|
||||
ip_csum_add_even (csum, inner_ip6->src_address.as_u64[0]);
|
||||
csum =
|
||||
ip_csum_add_even (csum, inner_ip6->src_address.as_u64[1]);
|
||||
csum =
|
||||
ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[0]);
|
||||
csum =
|
||||
ip_csum_add_even (csum, inner_ip6->dst_address.as_u64[1]);
|
||||
*inner_L4_checksum = ip_csum_fold (csum);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -518,6 +536,7 @@ ip4_to_ip6_tcp_udp (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx)
|
||||
|
||||
csum = ip_csum_sub_even (*checksum, ip4->src_address.as_u32);
|
||||
csum = ip_csum_sub_even (csum, ip4->dst_address.as_u32);
|
||||
*checksum = ip_csum_fold (csum);
|
||||
|
||||
// Deal with fragmented packets
|
||||
if (PREDICT_FALSE (ip4->flags_and_fragment_offset &
|
||||
@ -558,7 +577,7 @@ ip4_to_ip6_tcp_udp (vlib_buffer_t * p, ip4_to_ip6_set_fn_t fn, void *ctx)
|
||||
if ((rv = fn (ip4, ip6, ctx)) != 0)
|
||||
return rv;
|
||||
|
||||
csum = ip_csum_add_even (csum, ip6->src_address.as_u64[0]);
|
||||
csum = ip_csum_add_even (*checksum, ip6->src_address.as_u64[0]);
|
||||
csum = ip_csum_add_even (csum, ip6->src_address.as_u64[1]);
|
||||
csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[0]);
|
||||
csum = ip_csum_add_even (csum, ip6->dst_address.as_u64[1]);
|
||||
|
@ -314,13 +314,9 @@ icmp6_to_icmp (vlib_buffer_t * p, ip6_to_ip4_set_fn_t fn, void *ctx,
|
||||
else if (inner_protocol == IP_PROTOCOL_ICMP6)
|
||||
{
|
||||
icmp46_header_t *inner_icmp = (icmp46_header_t *) inner_l4;
|
||||
csum = inner_icmp->checksum;
|
||||
csum = ip_csum_sub_even (csum, *((u16 *) inner_icmp));
|
||||
//It cannot be of a different type as ip6_icmp_to_icmp6_in_place succeeded
|
||||
inner_icmp->type = (inner_icmp->type == ICMP6_echo_request) ?
|
||||
ICMP4_echo_request : ICMP4_echo_reply;
|
||||
csum = ip_csum_add_even (csum, *((u16 *) inner_icmp));
|
||||
inner_icmp->checksum = ip_csum_fold (csum);
|
||||
inner_protocol = IP_PROTOCOL_ICMP; //Will be copied to ip6 later
|
||||
inner_L4_checksum = &inner_icmp->checksum;
|
||||
}
|
||||
@ -334,6 +330,7 @@ icmp6_to_icmp (vlib_buffer_t * p, ip6_to_ip4_set_fn_t fn, void *ctx,
|
||||
csum = ip_csum_sub_even (csum, inner_ip6->src_address.as_u64[1]);
|
||||
csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[0]);
|
||||
csum = ip_csum_sub_even (csum, inner_ip6->dst_address.as_u64[1]);
|
||||
*inner_L4_checksum = ip_csum_fold (csum);
|
||||
|
||||
if ((rv = inner_fn (inner_ip6, inner_ip4, inner_ctx)) != 0)
|
||||
return rv;
|
||||
@ -353,19 +350,23 @@ icmp6_to_icmp (vlib_buffer_t * p, ip6_to_ip4_set_fn_t fn, void *ctx,
|
||||
|
||||
if (inner_ip4->protocol == IP_PROTOCOL_ICMP)
|
||||
{
|
||||
//Remove remainings of the pseudo-header in the csum
|
||||
//Recompute ICMP checksum
|
||||
icmp46_header_t *inner_icmp = (icmp46_header_t *) inner_l4;
|
||||
inner_icmp->checksum = 0;
|
||||
csum =
|
||||
ip_csum_sub_even (csum, clib_host_to_net_u16 (IP_PROTOCOL_ICMP6));
|
||||
csum =
|
||||
ip_csum_sub_even (csum, inner_ip4->length - sizeof (*inner_ip4));
|
||||
ip_incremental_checksum (0, inner_icmp,
|
||||
clib_net_to_host_u16 (inner_ip4->length)
|
||||
- sizeof (*inner_ip4));
|
||||
inner_icmp->checksum = ~ip_csum_fold (csum);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Update to new pseudo-header
|
||||
csum = *inner_L4_checksum;
|
||||
csum = ip_csum_add_even (csum, inner_ip4->src_address.as_u32);
|
||||
csum = ip_csum_add_even (csum, inner_ip4->dst_address.as_u32);
|
||||
*inner_L4_checksum = ip_csum_fold (csum);
|
||||
}
|
||||
*inner_L4_checksum = ip_csum_fold (csum);
|
||||
|
||||
//Move up icmp header
|
||||
ip4 = (ip4_header_t *) u8_ptr_add (inner_l4, -2 * sizeof (*ip4) - 8);
|
||||
@ -512,6 +513,7 @@ ip6_to_ip4_tcp_udp (vlib_buffer_t * p, ip6_to_ip4_set_fn_t fn, void *ctx,
|
||||
csum = ip_csum_sub_even (csum, ip6->src_address.as_u64[1]);
|
||||
csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[0]);
|
||||
csum = ip_csum_sub_even (csum, ip6->dst_address.as_u64[1]);
|
||||
*checksum = ip_csum_fold (csum);
|
||||
|
||||
no_csum:
|
||||
ip4 = (ip4_header_t *) u8_ptr_add (ip6, l4_offset - sizeof (*ip4));
|
||||
@ -552,7 +554,7 @@ no_csum:
|
||||
}
|
||||
else
|
||||
{
|
||||
csum = ip_csum_add_even (csum, ip4->dst_address.as_u32);
|
||||
csum = ip_csum_add_even (*checksum, ip4->dst_address.as_u32);
|
||||
csum = ip_csum_add_even (csum, ip4->src_address.as_u32);
|
||||
*checksum = ip_csum_fold (csum);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user