Added functions for fetching, configuring, and printing
NIC RSS configurations.

Signed-off-by: Matias Elo <matias....@nokia.com>
---
 platform/linux-generic/include/odp_packet_socket.h |  18 +++
 platform/linux-generic/pktio/socket.c              | 164 +++++++++++++++++++++
 2 files changed, 182 insertions(+)

diff --git a/platform/linux-generic/include/odp_packet_socket.h 
b/platform/linux-generic/include/odp_packet_socket.h
index a5e0eb3..4c78d0d 100644
--- a/platform/linux-generic/include/odp_packet_socket.h
+++ b/platform/linux-generic/include/odp_packet_socket.h
@@ -18,6 +18,7 @@
 #include <odp/debug.h>
 #include <odp/pool.h>
 #include <odp/packet.h>
+#include <odp/packet_io.h>
 
 #include <linux/version.h>
 
@@ -114,4 +115,21 @@ int promisc_mode_set_fd(int fd, const char *name, int 
enable);
  */
 int promisc_mode_get_fd(int fd, const char *name);
 
+/**
+ * Return RSS hash protocols of a packet socket
+ */
+void rss_conf_get_fd(int fd, const char *name,
+                    odp_pktin_hash_proto_t *hash_proto);
+
+/**
+ * Set RSS hash protocols of a packet socket
+ */
+int rss_conf_set_fd(int fd, const char *name,
+                   const odp_pktin_hash_proto_t *proto);
+
+/**
+ * Print enabled RSS hash protocols
+ */
+void rss_conf_print(const odp_pktin_hash_proto_t *hash_proto);
+
 #endif
diff --git a/platform/linux-generic/pktio/socket.c 
b/platform/linux-generic/pktio/socket.c
index d9baca3..8e87980 100644
--- a/platform/linux-generic/pktio/socket.c
+++ b/platform/linux-generic/pktio/socket.c
@@ -31,6 +31,8 @@
 #include <sys/ioctl.h>
 #include <errno.h>
 #include <sys/syscall.h>
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
 
 #include <odp.h>
 #include <odp_packet_socket.h>
@@ -182,6 +184,168 @@ int promisc_mode_get_fd(int fd, const char *name)
        return !!(ifr.ifr_flags & IFF_PROMISC);
 }
 
+static inline uint64_t get_rss_hash(int fd, const char *name,
+                                   uint32_t flow_type)
+{
+       struct ifreq ifr;
+       int ret;
+       struct ethtool_rxnfc rsscmd;
+
+       memset(&rsscmd, 0, sizeof(rsscmd));
+
+       snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", name);
+
+       rsscmd.cmd = ETHTOOL_GRXFH;
+       rsscmd.flow_type = flow_type;
+
+       ifr.ifr_data = (caddr_t)&rsscmd;
+
+       ret = ioctl(fd, SIOCETHTOOL, &ifr);
+
+       if (ret < 0) {
+               __odp_errno = errno;
+               ODP_ERR("get_rss_hash(): %s\n", strerror(errno));
+               return 0;
+       }
+       return rsscmd.data;
+}
+
+void rss_conf_get_fd(int fd, const char *name,
+                    odp_pktin_hash_proto_t *hash_proto)
+{
+       uint64_t bitmap;
+
+       memset(hash_proto, 0, sizeof(odp_pktin_hash_proto_t));
+
+       bitmap = get_rss_hash(fd, name, IPV4_FLOW);
+       if ((bitmap & RXH_IP_SRC) && (bitmap & RXH_IP_DST))
+               hash_proto->proto.ipv4 = 1;
+
+       bitmap = get_rss_hash(fd, name, TCP_V4_FLOW);
+       if ((bitmap & RXH_IP_SRC) && (bitmap & RXH_IP_DST) &&
+           (bitmap & RXH_L4_B_0_1) && (bitmap & RXH_L4_B_2_3))
+               hash_proto->proto.ipv4_tcp = 1;
+
+       bitmap = get_rss_hash(fd, name, UDP_V4_FLOW);
+       if ((bitmap & RXH_IP_SRC) && (bitmap & RXH_IP_DST) &&
+           (bitmap & RXH_L4_B_0_1) && (bitmap & RXH_L4_B_2_3))
+               hash_proto->proto.ipv4_udp = 1;
+
+       bitmap = get_rss_hash(fd, name, IPV6_FLOW);
+       if ((bitmap & RXH_IP_SRC) && (bitmap & RXH_IP_DST))
+               hash_proto->proto.ipv6 = 1;
+
+       bitmap = get_rss_hash(fd, name, TCP_V6_FLOW);
+       if ((bitmap & RXH_IP_SRC) && (bitmap & RXH_IP_DST) &&
+           (bitmap & RXH_L4_B_0_1) && (bitmap & RXH_L4_B_2_3))
+               hash_proto->proto.ipv6_tcp = 1;
+
+       bitmap = get_rss_hash(fd, name, UDP_V6_FLOW);
+       if ((bitmap & RXH_IP_SRC) && (bitmap & RXH_IP_DST) &&
+           (bitmap & RXH_L4_B_0_1) && (bitmap & RXH_L4_B_2_3))
+               hash_proto->proto.ipv6_udp = 1;
+}
+
+static inline int set_rss_hash(int fd, const char *name,
+                              uint32_t flow_type, uint64_t data)
+{
+       struct ifreq ifr;
+       int ret;
+       struct ethtool_rxnfc rsscmd;
+
+       memset(&rsscmd, 0, sizeof(rsscmd));
+
+       snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", name);
+
+       rsscmd.cmd = ETHTOOL_SRXFH;
+       rsscmd.flow_type = flow_type;
+       rsscmd.data = data;
+
+       ifr.ifr_data = (caddr_t)&rsscmd;
+
+       ret = ioctl(fd, SIOCETHTOOL, &ifr);
+
+       if (ret < 0) {
+               __odp_errno = errno;
+               ODP_ERR("set_rss_hash(): %s\n", strerror(errno));
+               return -1;
+       }
+       return 0;
+}
+
+int rss_conf_set_fd(int fd, const char *name,
+                   const odp_pktin_hash_proto_t *hash_proto)
+{
+       uint64_t data;
+       odp_pktin_hash_proto_t cur_hash;
+
+       /* Compare to currently set hash protocols */
+       rss_conf_get_fd(fd, name, &cur_hash);
+
+       if (hash_proto->proto.ipv4_udp && !cur_hash.proto.ipv4_udp) {
+               data = RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               if (set_rss_hash(fd, name, UDP_V4_FLOW, data))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv4_tcp && !cur_hash.proto.ipv4_tcp) {
+               data = RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               if (set_rss_hash(fd, name, TCP_V4_FLOW, data))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv6_udp && !cur_hash.proto.ipv6_udp) {
+               data = RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               if (set_rss_hash(fd, name, UDP_V6_FLOW, data))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv6_tcp && !cur_hash.proto.ipv6_tcp) {
+               data = RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3;
+               if (set_rss_hash(fd, name, TCP_V6_FLOW, data))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv4 && !cur_hash.proto.ipv4) {
+               data = RXH_IP_SRC | RXH_IP_DST;
+               if (set_rss_hash(fd, name, IPV4_FLOW, data))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv6 && !cur_hash.proto.ipv6) {
+               data = RXH_IP_SRC | RXH_IP_DST;
+               if (set_rss_hash(fd, name, IPV6_FLOW, data))
+                       return -1;
+       }
+       return 0;
+}
+
+void rss_conf_print(const odp_pktin_hash_proto_t *hash_proto)
+{      int max_len = 512;
+       char str[max_len];
+       int len = 0;
+       int n = max_len - 1;
+
+       len += snprintf(&str[len], n - len, "RSS conf\n");
+
+       if (hash_proto->proto.ipv4)
+               len += snprintf(&str[len], n - len,
+                               "  IPV4\n");
+       if (hash_proto->proto.ipv4_tcp)
+               len += snprintf(&str[len], n - len,
+                               "  IPV4 TCP\n");
+       if (hash_proto->proto.ipv4_udp)
+               len += snprintf(&str[len], n - len,
+                               "  IPV4 UDP\n");
+       if (hash_proto->proto.ipv6)
+               len += snprintf(&str[len], n - len,
+                               "  IPV6\n");
+       if (hash_proto->proto.ipv6_tcp)
+               len += snprintf(&str[len], n - len,
+                               "  IPV6 TCP\n");
+       if (hash_proto->proto.ipv6_udp)
+               len += snprintf(&str[len], n - len,
+                               "  IPV6 UDP\n");
+       str[len] = '\0';
+
+       ODP_PRINT("\n%s\n", str);
+}
+
 /*
  * ODP_PACKET_SOCKET_MMSG:
  */
-- 
1.9.1

_______________________________________________
lng-odp mailing list
lng-odp@lists.linaro.org
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to