lib/socket: autodetect RSS using ETHTOOL_GRXRINGS
authorStefan Metzmacher <metze@samba.org>
Thu, 7 May 2020 09:06:03 +0000 (11:06 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 7 May 2020 14:44:40 +0000 (14:44 +0000)
This is also used as part of 'ethtool -n rdma14' and
'ethtool -x rdma14'.

;#> ethtool -n rdma14
8 RX rings available
rxclass: Cannot get RX class rule count: Operation not supported
RX classification rule retrieval failed

;#> ethtool -x rdma14
RX flow hash indirection table for rdma14 with 8 RX ring(s):
    0:      0     1     2     3     4     5     6     7
    8:      0     1     2     3     4     5     6     7
RSS hash key:
Operation not supported
RSS hash function:
    toeplitz: on
    xor: off
    crc32: off

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
lib/socket/interfaces.c

index 497bd945984799bea32062b251a8d377aec212a1..3157e0cef12a37f12757158fd87a6d4089a0ea34 100644 (file)
@@ -170,6 +170,42 @@ static void query_iface_speed_from_name(const char *name, uint64_t *speed)
        }
        *speed = ((uint64_t)ethtool_cmd_speed(&ecmd)) * 1000 * 1000;
 
+done:
+       (void)close(fd);
+}
+
+static void query_iface_rx_queues_from_name(const char *name,
+                                           uint64_t *rx_queues)
+{
+       int ret = 0;
+       struct ethtool_rxnfc rxcmd;
+       struct ifreq ifr;
+       int fd;
+
+       fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+       if (fd == -1) {
+               DBG_ERR("Failed to open socket.");
+               return;
+       }
+
+       if (strlen(name) >= IF_NAMESIZE) {
+               DBG_ERR("Interface name too long.");
+               goto done;
+       }
+
+       ZERO_STRUCT(ifr);
+       strlcpy(ifr.ifr_name, name, IF_NAMESIZE);
+
+       ifr.ifr_data = (void *)&rxcmd;
+       ZERO_STRUCT(rxcmd);
+       rxcmd.cmd = ETHTOOL_GRXRINGS;
+       ret = ioctl(fd, SIOCETHTOOL, &ifr);
+       if (ret == -1) {
+               goto done;
+       }
+
+       *rx_queues = rxcmd.data;
+
 done:
        (void)close(fd);
 }
@@ -217,6 +253,7 @@ static int _get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
        /* Loop through interfaces, looking for given IP address */
        for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
                uint64_t if_speed = 1000 * 1000 * 1000; /* 1Gbps */
+               uint64_t rx_queues = 1;
 
                if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
                        continue;
@@ -278,9 +315,13 @@ static int _get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
 
 #ifdef HAVE_ETHTOOL
                query_iface_speed_from_name(ifptr->ifa_name, &if_speed);
+               query_iface_rx_queues_from_name(ifptr->ifa_name, &rx_queues);
 #endif
                ifaces[total].linkspeed = if_speed;
                ifaces[total].capability = FSCTL_NET_IFACE_NONE_CAPABLE;
+               if (rx_queues > 1) {
+                       ifaces[total].capability |= FSCTL_NET_IFACE_RSS_CAPABLE;
+               }
 
                if (strlcpy(ifaces[total].name, ifptr->ifa_name,
                        sizeof(ifaces[total].name)) >=