From 92b0275a364022af6ab828dfac83e38c0117cfe6 Mon Sep 17 00:00:00 2001 From: Jakub Grajciar Date: Fri, 20 Oct 2017 13:37:28 +0200 Subject: af_packet: invalid TCP/UDP offload checksum on RX node recalculation Change-Id: I1075e5d2a1b6dfe3a443b40b41b8458a30505680 Signed-off-by: Jakub Grajciar Signed-off-by: Jakub.Grajciar@pantheon.tech --- src/vnet/devices/af_packet/af_packet.api | 13 ++++++ src/vnet/devices/af_packet/af_packet.c | 16 +++++++ src/vnet/devices/af_packet/af_packet.h | 2 + src/vnet/devices/af_packet/af_packet_api.c | 19 +++++++-- src/vnet/devices/af_packet/cli.c | 56 ++++++++++++++++++++++++ src/vnet/devices/af_packet/node.c | 68 ++++++++++++++++++++++++++++++ 6 files changed, 171 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/vnet/devices/af_packet/af_packet.api b/src/vnet/devices/af_packet/af_packet.api index f815042ad55..a1b30d5eb3c 100644 --- a/src/vnet/devices/af_packet/af_packet.api +++ b/src/vnet/devices/af_packet/af_packet.api @@ -56,6 +56,19 @@ autoreply define af_packet_delete u8 host_if_name[64]; }; +/** \brief Set l4 offload ckecksum calculation + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +autoreply define af_packet_set_l4_cksum_offload +{ + u32 client_index; + u32 context; + + u8 sw_if_index; + u8 set; +}; + /* * Local Variables: * eval: (c-set-style "gnu") diff --git a/src/vnet/devices/af_packet/af_packet.c b/src/vnet/devices/af_packet/af_packet.c index 32696014727..e7bbdfd86ae 100644 --- a/src/vnet/devices/af_packet/af_packet.c +++ b/src/vnet/devices/af_packet/af_packet.c @@ -406,6 +406,22 @@ af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name) return 0; } +int +af_packet_set_l4_cksum_offload (vlib_main_t * vm, u32 sw_if_index, u8 set) +{ + vnet_main_t *vnm = vnet_get_main (); + vnet_hw_interface_t *hw; + + hw = vnet_get_sup_hw_interface (vnm, sw_if_index); + + if (set) + hw->flags &= ~VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD; + else + hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD; + + return 0; +} + static clib_error_t * af_packet_init (vlib_main_t * vm) { diff --git a/src/vnet/devices/af_packet/af_packet.h b/src/vnet/devices/af_packet/af_packet.h index 95c7e7cf5a7..66e2dea5169 100644 --- a/src/vnet/devices/af_packet/af_packet.h +++ b/src/vnet/devices/af_packet/af_packet.h @@ -63,6 +63,8 @@ extern vlib_node_registration_t af_packet_input_node; int af_packet_create_if (vlib_main_t * vm, u8 * host_if_name, u8 * hw_addr_set, u32 * sw_if_index); int af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name); +int af_packet_set_l4_cksum_offload (vlib_main_t * vm, u32 sw_if_index, + u8 set); /* * fd.io coding-style-patch-verification: ON diff --git a/src/vnet/devices/af_packet/af_packet_api.c b/src/vnet/devices/af_packet/af_packet_api.c index 414c838cdf7..c7dfabc2ebd 100644 --- a/src/vnet/devices/af_packet/af_packet_api.c +++ b/src/vnet/devices/af_packet/af_packet_api.c @@ -42,9 +42,10 @@ #include -#define foreach_vpe_api_msg \ -_(AF_PACKET_CREATE, af_packet_create) \ -_(AF_PACKET_DELETE, af_packet_delete) +#define foreach_vpe_api_msg \ +_(AF_PACKET_CREATE, af_packet_create) \ +_(AF_PACKET_DELETE, af_packet_delete) \ +_(AF_PACKET_SET_L4_CKSUM_OFFLOAD, af_packet_set_l4_cksum_offload) static void vl_api_af_packet_create_t_handler (vl_api_af_packet_create_t * mp) @@ -90,6 +91,18 @@ vl_api_af_packet_delete_t_handler (vl_api_af_packet_delete_t * mp) REPLY_MACRO (VL_API_AF_PACKET_DELETE_REPLY); } +static void + vl_api_af_packet_set_l4_cksum_offload_t_handler + (vl_api_af_packet_set_l4_cksum_offload_t * mp) +{ + vlib_main_t *vm = vlib_get_main (); + vl_api_af_packet_delete_reply_t *rmp; + int rv = 0; + + rv = af_packet_set_l4_cksum_offload (vm, mp->sw_if_index, mp->set); + REPLY_MACRO (VL_API_AF_PACKET_SET_L4_CKSUM_OFFLOAD_REPLY); +} + /* * af_packet_api_hookup * Add vpe's API message handlers to the table. diff --git a/src/vnet/devices/af_packet/cli.c b/src/vnet/devices/af_packet/cli.c index 44dc517911b..29c0e060a91 100644 --- a/src/vnet/devices/af_packet/cli.c +++ b/src/vnet/devices/af_packet/cli.c @@ -194,6 +194,62 @@ VLIB_CLI_COMMAND (af_packet_delete_command, static) = { }; /* *INDENT-ON* */ +static clib_error_t * +af_packet_set_l4_cksum_offload_command_fn (vlib_main_t * vm, + unformat_input_t * input, + vlib_cli_command_t * cmd) +{ + unformat_input_t _line_input, *line_input = &_line_input; + u8 set = 0; + clib_error_t *error = NULL; + vnet_main_t *vnm = vnet_get_main (); + u32 sw_if_index; + + if (!unformat_user (input, unformat_line_input, line_input)) + return 0; + + while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) + { + if (unformat + (line_input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index)) + ; + else if (unformat (line_input, "on")) + set = 1; + else if (unformat (line_input, "off")) + set = 0; + else + { + error = clib_error_return (0, "unknown input '%U'", + format_unformat_error, line_input); + goto done; + } + } + + af_packet_set_l4_cksum_offload (vm, sw_if_index, set); + +done: + unformat_free (line_input); + return error; +} + +/*? + * Set TCP/UDP offload checksum calculation. Use interface + * name to identify the interface to set TCP/UDP offload checksum + * calculation. + * + * @cliexpar + * Example of how to set TCP/UDP offload checksum calculation on host-vpp0: + * @cliexcmd{set host-interface l4-cksum-offload host-vpp0 off} + * @cliexcmd{set host-interface l4-cksum-offload host-vpp0 on} +?*/ +/* *INDENT-OFF* */ +VLIB_CLI_COMMAND (af_packet_set_l4_cksum_offload_command, static) = { + .path = "set host-interface l4-cksum-offload", + .short_help = "set host-interface l4-cksum-offload ", + .function = af_packet_set_l4_cksum_offload_command_fn, +}; +/* *INDENT-ON* */ + clib_error_t * af_packet_cli_init (vlib_main_t * vm) { diff --git a/src/vnet/devices/af_packet/node.c b/src/vnet/devices/af_packet/node.c index 8539ff56b5c..b627cfcb036 100644 --- a/src/vnet/devices/af_packet/node.c +++ b/src/vnet/devices/af_packet/node.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -106,6 +107,71 @@ buffer_add_to_chain (vlib_main_t * vm, u32 bi, u32 first_bi, u32 prev_bi) b->next_buffer = 0; } +static_always_inline void +mark_tcp_udp_cksum_calc (vlib_buffer_t * b) +{ + ethernet_header_t *eth = vlib_buffer_get_current (b); + if (clib_net_to_host_u16 (eth->type) == ETHERNET_TYPE_IP4) + { + ip4_header_t *ip4 = + (vlib_buffer_get_current (b) + sizeof (ethernet_header_t)); + b->flags |= VNET_BUFFER_F_IS_IP4; + if (ip4->protocol == IP_PROTOCOL_TCP) + { + b->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM; + ((tcp_header_t + *) (vlib_buffer_get_current (b) + + sizeof (ethernet_header_t) + + ip4_header_bytes (ip4)))->checksum = 0; + } + else if (ip4->protocol == IP_PROTOCOL_UDP) + { + b->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM; + ((udp_header_t + *) (vlib_buffer_get_current (b) + + sizeof (ethernet_header_t) + + ip4_header_bytes (ip4)))->checksum = 0; + } + vnet_buffer (b)->l3_hdr_offset = sizeof (ethernet_header_t); + vnet_buffer (b)->l4_hdr_offset = + sizeof (ethernet_header_t) + ip4_header_bytes (ip4); + } + else if (clib_net_to_host_u16 (eth->type) == ETHERNET_TYPE_IP6) + { + ip6_header_t *ip6 = + (vlib_buffer_get_current (b) + sizeof (ethernet_header_t)); + b->flags |= VNET_BUFFER_F_IS_IP6; + u16 ip6_hdr_len = sizeof (ip6_header_t); + if (ip6_ext_hdr (ip6->protocol)) + { + ip6_ext_header_t *p = (void *) (ip6 + 1); + ip6_hdr_len += ip6_ext_header_len (p); + while (ip6_ext_hdr (p->next_hdr)) + { + ip6_hdr_len += ip6_ext_header_len (p); + p = ip6_ext_next_header (p); + } + } + if (ip6->protocol == IP_PROTOCOL_TCP) + { + b->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM; + ((tcp_header_t + *) (vlib_buffer_get_current (b) + + sizeof (ethernet_header_t) + ip6_hdr_len))->checksum = 0; + } + else if (ip6->protocol == IP_PROTOCOL_UDP) + { + b->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM; + ((udp_header_t + *) (vlib_buffer_get_current (b) + + sizeof (ethernet_header_t) + ip6_hdr_len))->checksum = 0; + } + vnet_buffer (b)->l3_hdr_offset = sizeof (ethernet_header_t); + vnet_buffer (b)->l4_hdr_offset = + sizeof (ethernet_header_t) + ip6_hdr_len; + } +} + always_inline uword af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame, af_packet_if_t * apif) @@ -211,6 +277,8 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node, vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; first_bi0 = bi0; first_b0 = vlib_get_buffer (vm, first_bi0); + if (tph->tp_status & TP_STATUS_CSUMNOTREADY) + mark_tcp_udp_cksum_calc (first_b0); } else buffer_add_to_chain (vm, bi0, first_bi0, prev_bi0); -- cgit 1.2.3-korg