summaryrefslogtreecommitdiffstats
path: root/src/vnet
diff options
context:
space:
mode:
authorMatus Fabian <matfabia@cisco.com>2017-06-15 02:28:50 -0700
committerOle Trøan <otroan@employees.org>2017-06-19 11:08:47 +0000
commit029f3d2c1c6b04a6cfef17242cb36b304025fe23 (patch)
tree5036e25543b5d43deeb15fde31135a3531d864ce /src/vnet
parentacd4c63e3c6e70ea3f58527d9bace7c0e38df719 (diff)
NAT64: Hairpinning (VPP-699)
Change-Id: I83a6c277fa211ac2c2ca2d603650c992886af0a7 Signed-off-by: Matus Fabian <matfabia@cisco.com>
Diffstat (limited to 'src/vnet')
-rw-r--r--src/vnet/ip/ip4_to_ip6.h55
-rw-r--r--src/vnet/ip/ip6_to_ip4.h22
2 files changed, 49 insertions, 28 deletions
diff --git a/src/vnet/ip/ip4_to_ip6.h b/src/vnet/ip/ip4_to_ip6.h
index dad35230b12..cdd370723f2 100644
--- a/src/vnet/ip/ip4_to_ip6.h
+++ b/src/vnet/ip/ip4_to_ip6.h
@@ -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]);
diff --git a/src/vnet/ip/ip6_to_ip4.h b/src/vnet/ip/ip6_to_ip4.h
index 92f73ba165d..7a0d534959c 100644
--- a/src/vnet/ip/ip6_to_ip4.h
+++ b/src/vnet/ip/ip6_to_ip4.h
@@ -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
- csum =
- ip_csum_sub_even (csum, clib_host_to_net_u16 (IP_PROTOCOL_ICMP6));
+ //Recompute ICMP checksum
+ icmp46_header_t *inner_icmp = (icmp46_header_t *) inner_l4;
+ inner_icmp->checksum = 0;
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);
}