diff --git a/lib/format_linux_helpers.c b/lib/format_linux_helpers.c index e70f4cb4..d31bbffe 100644 --- a/lib/format_linux_helpers.c +++ b/lib/format_linux_helpers.c @@ -203,6 +203,51 @@ int linux_get_nic_flow_rule_count(char *ifname) return nfccmd.rule_cnt; } +int linux_get_nic_fw_lldp_enabled(char *ifname) +{ + + struct ethtool_drvinfo drvinfo = {}; + struct ethtool_gstrings *strings; + struct ethtool_value flags = {}; + uint32_t i; + int ret = -1; + + drvinfo.cmd = ETHTOOL_GDRVINFO; + if (linux_send_ioctl_ethtool(&drvinfo, ifname) != 0) + return -1; + + /* the private flags bitmap ioctl only carries 32 flags */ + if (drvinfo.n_priv_flags == 0 || drvinfo.n_priv_flags > 32) + return -1; + + strings = + calloc(1, sizeof(*strings) + drvinfo.n_priv_flags * ETH_GSTRING_LEN); + if (strings == NULL) + return -1; + + strings->cmd = ETHTOOL_GSTRINGS; + strings->string_set = ETH_SS_PRIV_FLAGS; + strings->len = drvinfo.n_priv_flags; + if (linux_send_ioctl_ethtool(strings, ifname) != 0) + goto out; + + flags.cmd = ETHTOOL_GPFLAGS; + if (linux_send_ioctl_ethtool(&flags, ifname) != 0) + goto out; + + for (i = 0; i < drvinfo.n_priv_flags; i++) { + char *name = (char *)strings->data + i * ETH_GSTRING_LEN; + if (strncmp(name, "disable-fw-lldp", ETH_GSTRING_LEN) == 0) { + ret = (flags.data & (1U << i)) ? 0 : 1; + break; + } + } + +out: + free(strings); + return ret; +} + static struct ethtool_ringparam * linux_get_nic_rings(struct ethtool_ringparam *ering, char *ifname) { diff --git a/lib/format_linux_helpers.h b/lib/format_linux_helpers.h index 904037a6..9d9249f6 100644 --- a/lib/format_linux_helpers.h +++ b/lib/format_linux_helpers.h @@ -36,6 +36,7 @@ int linux_get_nic_queues(char *ifname); int linux_set_nic_queues(char *ifname, int queues); int linux_set_nic_hasher(char *ifname, enum hasher_types hasher); int linux_get_nic_flow_rule_count(char *ifname); +int linux_get_nic_fw_lldp_enabled(char *ifname); int linux_get_nic_rx_rings(char *ifname); int linux_get_nic_tx_rings(char *ifname); int linux_get_nic_max_rx_rings(char *ifname); diff --git a/lib/format_linux_xdp.c b/lib/format_linux_xdp.c index 7d0a902d..63b31212 100644 --- a/lib/format_linux_xdp.c +++ b/lib/format_linux_xdp.c @@ -684,6 +684,16 @@ static int linux_xdp_pstart_input(libtrace_t *libtrace) libtrace->perpkt_thread_count = max_nic_queues; } + if (linux_get_nic_fw_lldp_enabled(XDP_FORMAT_DATA->cfg.ifname) == 1) { + fprintf(stderr, + "Linux XDP: firmware LLDP agent is enabled on %s, on some " + "NICs (e.g. Intel i40e) this limits RSS to half the receive " + "queues! If some processing threads receive no packets " + "disable it with: ethtool --set-priv-flags %s " + "disable-fw-lldp on\n", + XDP_FORMAT_DATA->cfg.ifname, XDP_FORMAT_DATA->cfg.ifname); + } + /* set the number of nic queues to match number of threads */ if (linux_set_nic_queues(XDP_FORMAT_DATA->cfg.ifname, libtrace->perpkt_thread_count) !=