+#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;
+}
+