diff options
Diffstat (limited to 'src/plugins/af_packet/af_packet.c')
-rw-r--r-- | src/plugins/af_packet/af_packet.c | 101 |
1 files changed, 95 insertions, 6 deletions
diff --git a/src/plugins/af_packet/af_packet.c b/src/plugins/af_packet/af_packet.c index 6da6112c8a5..7ff30e0a722 100644 --- a/src/plugins/af_packet/af_packet.c +++ b/src/plugins/af_packet/af_packet.c @@ -19,6 +19,8 @@ #include <linux/if_ether.h> #include <linux/if_packet.h> +#include <linux/ethtool.h> +#include <linux/sockios.h> #include <sys/ioctl.h> #include <net/if.h> #include <dirent.h> @@ -59,6 +61,80 @@ VNET_HW_INTERFACE_CLASS (af_packet_ip_device_hw_interface_class, static) = { /*defined in net/if.h but clashes with dpdk headers */ unsigned int if_nametoindex (const char *ifname); +#define AF_PACKET_OFFLOAD_FLAG_RXCKSUM (1 << 0) +#define AF_PACKET_OFFLOAD_FLAG_TXCKSUM (1 << 1) +#define AF_PACKET_OFFLOAD_FLAG_SG (1 << 2) +#define AF_PACKET_OFFLOAD_FLAG_TSO (1 << 3) +#define AF_PACKET_OFFLOAD_FLAG_UFO (1 << 4) +#define AF_PACKET_OFFLOAD_FLAG_GSO (1 << 5) +#define AF_PACKET_OFFLOAD_FLAG_GRO (1 << 6) + +#define AF_PACKET_OFFLOAD_FLAG_MASK \ + (AF_PACKET_OFFLOAD_FLAG_RXCKSUM | AF_PACKET_OFFLOAD_FLAG_TXCKSUM | \ + AF_PACKET_OFFLOAD_FLAG_SG | AF_PACKET_OFFLOAD_FLAG_TSO | \ + AF_PACKET_OFFLOAD_FLAG_UFO | AF_PACKET_OFFLOAD_FLAG_GSO | \ + AF_PACKET_OFFLOAD_FLAG_GRO) + +#define AF_PACKET_IOCTL(fd, a, ...) \ + if (ioctl (fd, a, __VA_ARGS__) < 0) \ + { \ + err = clib_error_return_unix (0, "ioctl(" #a ")"); \ + vlib_log_err (af_packet_main.log_class, "%U", format_clib_error, err); \ + goto done; \ + } + +static u32 +af_packet_get_if_capabilities (u8 *host_if_name) +{ + struct ifreq ifr; + struct ethtool_value e; // { __u32 cmd; __u32 data; }; + clib_error_t *err = 0; + int ctl_fd = -1; + u32 oflags = 0; + + if ((ctl_fd = socket (AF_INET, SOCK_STREAM, 0)) == -1) + { + clib_warning ("Cannot open control socket"); + goto done; + } + + clib_memset (&ifr, 0, sizeof (ifr)); + clib_memcpy (ifr.ifr_name, host_if_name, + strlen ((const char *) host_if_name)); + ifr.ifr_data = (void *) &e; + + e.cmd = ETHTOOL_GRXCSUM; + AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr); + if (e.data) + oflags |= AF_PACKET_OFFLOAD_FLAG_RXCKSUM; + + e.cmd = ETHTOOL_GTXCSUM; + AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr); + if (e.data) + oflags |= AF_PACKET_OFFLOAD_FLAG_TXCKSUM; + + e.cmd = ETHTOOL_GTSO; + AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr); + if (e.data) + oflags |= AF_PACKET_OFFLOAD_FLAG_TSO; + + e.cmd = ETHTOOL_GGSO; + AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr); + if (e.data) + oflags |= AF_PACKET_OFFLOAD_FLAG_GSO; + + e.cmd = ETHTOOL_GGRO; + AF_PACKET_IOCTL (ctl_fd, SIOCETHTOOL, &ifr); + if (e.data) + oflags |= AF_PACKET_OFFLOAD_FLAG_GRO; + +done: + if (ctl_fd != -1) + close (ctl_fd); + + return oflags; +} + static clib_error_t * af_packet_eth_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi, u32 frame_size) @@ -572,7 +648,7 @@ af_packet_create_if (af_packet_create_if_arg_t *arg) u8 *host_if_name_dup = 0; int host_if_index = -1; int ret = 0; - u32 i = 0; + u32 oflags = 0, i = 0; p = mhash_get (&apm->if_index_by_host_if_name, arg->host_if_name); if (p) @@ -638,6 +714,9 @@ af_packet_create_if (af_packet_create_if_arg_t *arg) fd2 = -1; } + // check the host interface capabilities + oflags = af_packet_get_if_capabilities (arg->host_if_name); + ret = is_bridge (arg->host_if_name); if (ret == 0) /* is a bridge, ignore state */ host_if_index = -1; @@ -651,6 +730,7 @@ af_packet_create_if (af_packet_create_if_arg_t *arg) apif->host_if_name = host_if_name_dup; apif->per_interface_next_index = ~0; apif->mode = arg->mode; + apif->host_interface_oflags = oflags; if (arg->is_v2) apif->version = TPACKET_V2; @@ -710,12 +790,21 @@ af_packet_create_if (af_packet_create_if_arg_t *arg) (arg->flags & AF_PACKET_IF_FLAGS_QDISC_BYPASS); if (arg->flags & AF_PACKET_IF_FLAGS_CKSUM_GSO) - apif->is_cksum_gso_enabled = 1; - - if (apif->is_cksum_gso_enabled) - caps |= VNET_HW_IF_CAP_TCP_GSO | VNET_HW_IF_CAP_TX_IP4_CKSUM | - VNET_HW_IF_CAP_TX_TCP_CKSUM | VNET_HW_IF_CAP_TX_UDP_CKSUM; + { + if (apif->host_interface_oflags & AF_PACKET_OFFLOAD_FLAG_TXCKSUM) + { + apif->is_cksum_gso_enabled = 1; + caps |= VNET_HW_IF_CAP_TX_IP4_CKSUM | VNET_HW_IF_CAP_TX_TCP_CKSUM | + VNET_HW_IF_CAP_TX_UDP_CKSUM; + } + if (apif->host_interface_oflags & AF_PACKET_OFFLOAD_FLAG_GSO) + { + apif->is_cksum_gso_enabled = 1; + caps |= VNET_HW_IF_CAP_TCP_GSO | VNET_HW_IF_CAP_TX_IP4_CKSUM | + VNET_HW_IF_CAP_TX_TCP_CKSUM | VNET_HW_IF_CAP_TX_UDP_CKSUM; + } + } vnet_hw_if_set_caps (vnm, apif->hw_if_index, caps); vnet_hw_interface_set_flags (vnm, apif->hw_if_index, VNET_HW_INTERFACE_FLAG_LINK_UP); |