aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohn Lo <loj@cisco.com>2017-09-18 00:20:05 -0400
committerDave Barach <openvpp@barachs.net>2017-09-19 10:46:50 +0000
commitf4215a65cb5858b276b0b096273270e7c017209d (patch)
tree3e7cebdf5513d432894be4d6d575d6ac0f542978 /src
parent057704ebb51a006fbfd18dba570df1ca504b4277 (diff)
Implement VXLAN encap tx checksum offload
Checksum offload is implemented in VXLAN encap over both IPv4 and IPv6. It is enabled, however, only for VXLAN over IPv6 because UDP checksum is needed only for IPv6 and optional for IPv4. Change-Id: Ib879f4f6da7346ba5e079d321c1dfd630f5058b8 Signed-off-by: John Lo <loj@cisco.com>
Diffstat (limited to 'src')
-rw-r--r--src/vnet/vxlan/encap.c147
1 files changed, 108 insertions, 39 deletions
diff --git a/src/vnet/vxlan/encap.c b/src/vnet/vxlan/encap.c
index 4cfbbc233c0..87e75e5db2d 100644
--- a/src/vnet/vxlan/encap.c
+++ b/src/vnet/vxlan/encap.c
@@ -69,7 +69,7 @@ always_inline uword
vxlan_encap_inline (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * from_frame,
- u32 is_ip4)
+ u8 is_ip4, u8 csum_offload)
{
u32 n_left_from, next_index, * from, * to_next;
vxlan_main_t * vxm = &vxlan_main;
@@ -200,20 +200,36 @@ vxlan_encap_inline (vlib_main_t * vm,
copy_dst_last1[0] = copy_src_last1[0];
/* Fix the IP4 checksum and length */
- sum0 = ip4_0->checksum;
- new_l0 = /* old_l0 always 0, see the rewrite setup */
- clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
- sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
- length /* changed member */);
- ip4_0->checksum = ip_csum_fold (sum0);
- ip4_0->length = new_l0;
- sum1 = ip4_1->checksum;
- new_l1 = /* old_l1 always 0, see the rewrite setup */
- clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
- sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
- length /* changed member */);
- ip4_1->checksum = ip_csum_fold (sum1);
- ip4_1->length = new_l1;
+ if (csum_offload)
+ {
+ ip4_0->length = clib_host_to_net_u16
+ (vlib_buffer_length_in_chain (vm, b0));
+ b0->flags |=
+ VNET_BUFFER_F_OFFLOAD_IP_CKSUM | VNET_BUFFER_F_IS_IP4;
+ vnet_buffer (b0)->l3_hdr_offset = (u8 *) ip4_0 - b0->data;
+ ip4_1->length = clib_host_to_net_u16
+ (vlib_buffer_length_in_chain (vm, b1));
+ b1->flags |=
+ VNET_BUFFER_F_OFFLOAD_IP_CKSUM | VNET_BUFFER_F_IS_IP4;
+ vnet_buffer (b1)->l3_hdr_offset = (u8 *) ip4_1 - b1->data;
+ }
+ else
+ {
+ sum0 = ip4_0->checksum;
+ new_l0 = /* old_l0 always 0, see the rewrite setup */
+ clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+ sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
+ length /* changed member */);
+ ip4_0->checksum = ip_csum_fold (sum0);
+ ip4_0->length = new_l0;
+ sum1 = ip4_1->checksum;
+ new_l1 = /* old_l1 always 0, see the rewrite setup */
+ clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
+ sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
+ length /* changed member */);
+ ip4_1->checksum = ip_csum_fold (sum1);
+ ip4_1->length = new_l1;
+ }
/* Fix UDP length and set source port */
udp0 = (udp_header_t *)(ip4_0+1);
@@ -226,6 +242,15 @@ vxlan_encap_inline (vlib_main_t * vm,
- sizeof (*ip4_1));
udp1->length = new_l1;
udp1->src_port = flow_hash1;
+
+ /* UDP checksum only if checksum offload is used */
+ if (csum_offload)
+ {
+ b0->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+ vnet_buffer (b0)->l4_hdr_offset = (u8 *) udp0 - b0->data;
+ b1->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+ vnet_buffer (b1)->l4_hdr_offset = (u8 *) udp1 - b1->data;
+ }
}
else /* ipv6 */
{
@@ -269,16 +294,28 @@ vxlan_encap_inline (vlib_main_t * vm,
udp1->src_port = flow_hash1;
/* IPv6 UDP checksum is mandatory */
- udp0->checksum = ip6_tcp_udp_icmp_compute_checksum(vm, b0,
- ip6_0, &bogus);
- ASSERT(bogus == 0);
- if (udp0->checksum == 0)
- udp0->checksum = 0xffff;
- udp1->checksum = ip6_tcp_udp_icmp_compute_checksum(vm, b1,
- ip6_1, &bogus);
- ASSERT(bogus == 0);
- if (udp1->checksum == 0)
- udp1->checksum = 0xffff;
+ if (csum_offload)
+ {
+ b0->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+ vnet_buffer (b0)->l3_hdr_offset = (u8 *) ip6_0 - b0->data;
+ vnet_buffer (b0)->l4_hdr_offset = (u8 *) udp0 - b0->data;
+ b1->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+ vnet_buffer (b1)->l3_hdr_offset = (u8 *) ip6_1 - b1->data;
+ vnet_buffer (b1)->l4_hdr_offset = (u8 *) udp1 - b1->data;
+ }
+ else
+ {
+ udp0->checksum = ip6_tcp_udp_icmp_compute_checksum
+ (vm, b0, ip6_0, &bogus);
+ ASSERT(bogus == 0);
+ if (udp0->checksum == 0)
+ udp0->checksum = 0xffff;
+ udp1->checksum = ip6_tcp_udp_icmp_compute_checksum
+ (vm, b1, ip6_1, &bogus);
+ ASSERT(bogus == 0);
+ if (udp1->checksum == 0)
+ udp1->checksum = 0xffff;
+ }
}
pkts_encapsulated += 2;
@@ -398,13 +435,24 @@ vxlan_encap_inline (vlib_main_t * vm,
copy_dst_last0[0] = copy_src_last0[0];
/* Fix the IP4 checksum and length */
- sum0 = ip4_0->checksum;
- new_l0 = /* old_l0 always 0, see the rewrite setup */
- clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
- sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
- length /* changed member */);
- ip4_0->checksum = ip_csum_fold (sum0);
- ip4_0->length = new_l0;
+ if (csum_offload)
+ {
+ ip4_0->length =
+ clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+ b0->flags |=
+ VNET_BUFFER_F_OFFLOAD_IP_CKSUM | VNET_BUFFER_F_IS_IP4;
+ vnet_buffer (b0)->l3_hdr_offset = (u8 *) ip4_0 - b0->data;
+ }
+ else
+ {
+ sum0 = ip4_0->checksum;
+ new_l0 = /* old_l0 always 0, see the rewrite setup */
+ clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
+ sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
+ length /* changed member */);
+ ip4_0->checksum = ip_csum_fold (sum0);
+ ip4_0->length = new_l0;
+ }
/* Fix UDP length and set source port */
udp0 = (udp_header_t *)(ip4_0+1);
@@ -412,6 +460,13 @@ vxlan_encap_inline (vlib_main_t * vm,
- sizeof (*ip4_0));
udp0->length = new_l0;
udp0->src_port = flow_hash0;
+
+ /* UDP checksum only if checksum offload is used */
+ if (csum_offload)
+ {
+ b0->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+ vnet_buffer (b0)->l4_hdr_offset = (u8 *) udp0 - b0->data;
+ }
}
else /* ip6 path */
@@ -441,11 +496,20 @@ vxlan_encap_inline (vlib_main_t * vm,
udp0->src_port = flow_hash0;
/* IPv6 UDP checksum is mandatory */
- udp0->checksum = ip6_tcp_udp_icmp_compute_checksum(vm, b0,
- ip6_0, &bogus);
- ASSERT(bogus == 0);
- if (udp0->checksum == 0)
- udp0->checksum = 0xffff;
+ if (csum_offload)
+ {
+ b0->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+ vnet_buffer (b0)->l3_hdr_offset = (u8 *) ip6_0 - b0->data;
+ vnet_buffer (b0)->l4_hdr_offset = (u8 *) udp0 - b0->data;
+ }
+ else
+ {
+ udp0->checksum = ip6_tcp_udp_icmp_compute_checksum
+ (vm, b0, ip6_0, &bogus);
+ ASSERT(bogus == 0);
+ if (udp0->checksum == 0)
+ udp0->checksum = 0xffff;
+ }
}
pkts_encapsulated ++;
@@ -508,7 +572,10 @@ vxlan4_encap (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
{
- return vxlan_encap_inline (vm, node, from_frame, /* is_ip4 */ 1);
+ /* Disable chksum offload as setup overhead in tx node is not worthwhile
+ for ip4 header checksum only, unless udp checksum is also required */
+ return vxlan_encap_inline (vm, node, from_frame, /* is_ip4 */ 1,
+ /* csum_offload */ 0);
}
static uword
@@ -516,7 +583,9 @@ vxlan6_encap (vlib_main_t * vm,
vlib_node_runtime_t * node,
vlib_frame_t * from_frame)
{
- return vxlan_encap_inline (vm, node, from_frame, /* is_ip4 */ 0);
+ /* Enable checksum offload for ip6 as udp checksum is mandatory, */
+ return vxlan_encap_inline (vm, node, from_frame, /* is_ip4 */ 0,
+ /* csum_offload */ 1);
}
VLIB_REGISTER_NODE (vxlan4_encap_node) = {