aboutsummaryrefslogtreecommitdiffstats
path: root/src/vnet/vxlan/encap.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/vxlan/encap.c')
-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) = {