From: Matias Elo <[email protected]>

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

Signed-off-by: Matias Elo <[email protected]>
---
 platform/linux-generic/include/odp_packet_socket.h |  47 +++++
 platform/linux-generic/pktio/socket.c              | 234 +++++++++++++++++++++
 2 files changed, 281 insertions(+)

diff --git a/platform/linux-generic/include/odp_packet_socket.h 
b/platform/linux-generic/include/odp_packet_socket.h
index 1eaafb7..66c258f 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>
 
@@ -116,4 +117,50 @@ int promisc_mode_set_fd(int fd, const char *name, int 
enable);
  */
 int promisc_mode_get_fd(int fd, const char *name);
 
+/**
+ * Get enabled RSS hash protocols of a packet socket
+ *
+ * @param fd              Socket file descriptor
+ * @param name            Interface name
+ * @param hash_proto[out] Hash protocols
+ *
+ * @returns Number enabled hash protocols
+ */
+int rss_conf_get_fd(int fd, const char *name,
+                   odp_pktin_hash_proto_t *hash_proto);
+
+/**
+ * Get supported RSS hash protocols of a packet socket
+ *
+ * Can be both read and modified.
+ *
+ * @param fd              Socket file descriptor
+ * @param name            Interface name
+ * @param hash_proto[out] Hash protocols
+ *
+ * @returns Number of supported hash protocols
+ */
+int rss_conf_get_supported_fd(int fd, const char *name,
+                             odp_pktin_hash_proto_t *hash_proto);
+
+/**
+ * Set RSS hash protocols of a packet socket
+ *
+ * @param fd              Socket file descriptor
+ * @param name            Interface name
+ * @param hash_proto      Hash protocols
+ *
+ * @retval 0 on success
+ * @retval <0 on failure
+ */
+int rss_conf_set_fd(int fd, const char *name,
+                   const odp_pktin_hash_proto_t *proto);
+
+/**
+ * Print enabled RSS hash protocols
+ *
+ * @param hash_proto      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 0dd8ee7..ae5a2d6 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>
@@ -193,6 +195,238 @@ int promisc_mode_get_fd(int fd, const char *name)
        return !!(ifr.ifr_flags & IFF_PROMISC);
 }
 
+/**
+ * Get enabled hash options of a packet socket
+ *
+ * @param fd              Socket file descriptor
+ * @param name            Interface name
+ * @param flow_type       Packet flow type
+ * @param options[out]    Enabled hash options
+ *
+ * @retval 0 on success
+ * @retval <0 on failure
+ */
+static inline int get_rss_hash_options(int fd, const char *name,
+                                      uint32_t flow_type, uint64_t *options)
+{
+       struct ifreq ifr;
+       struct ethtool_rxnfc rsscmd;
+
+       memset(&rsscmd, 0, sizeof(rsscmd));
+       *options = 0;
+
+       snprintf(ifr.ifr_name, IF_NAMESIZE, "%s", name);
+
+       rsscmd.cmd = ETHTOOL_GRXFH;
+       rsscmd.flow_type = flow_type;
+
+       ifr.ifr_data = (caddr_t)&rsscmd;
+
+       if (ioctl(fd, SIOCETHTOOL, &ifr) < 0)
+               return -1;
+
+       *options = rsscmd.data;
+       return 0;
+}
+
+int rss_conf_get_fd(int fd, const char *name,
+                   odp_pktin_hash_proto_t *hash_proto)
+{
+       uint64_t options;
+       int rss_enabled = 0;
+
+       memset(hash_proto, 0, sizeof(odp_pktin_hash_proto_t));
+
+       get_rss_hash_options(fd, name, IPV4_FLOW, &options);
+       if ((options & RXH_IP_SRC) && (options & RXH_IP_DST)) {
+               hash_proto->proto.ipv4 = 1;
+               rss_enabled++;
+       }
+       get_rss_hash_options(fd, name, TCP_V4_FLOW, &options);
+       if ((options & RXH_IP_SRC) && (options & RXH_IP_DST) &&
+           (options & RXH_L4_B_0_1) && (options & RXH_L4_B_2_3)) {
+               hash_proto->proto.ipv4_tcp = 1;
+               rss_enabled++;
+       }
+       get_rss_hash_options(fd, name, UDP_V4_FLOW, &options);
+       if ((options & RXH_IP_SRC) && (options & RXH_IP_DST) &&
+           (options & RXH_L4_B_0_1) && (options & RXH_L4_B_2_3)) {
+               hash_proto->proto.ipv4_udp = 1;
+               rss_enabled++;
+       }
+       get_rss_hash_options(fd, name, IPV6_FLOW, &options);
+       if ((options & RXH_IP_SRC) && (options & RXH_IP_DST)) {
+               hash_proto->proto.ipv6 = 1;
+               rss_enabled++;
+       }
+       get_rss_hash_options(fd, name, TCP_V6_FLOW, &options);
+       if ((options & RXH_IP_SRC) && (options & RXH_IP_DST) &&
+           (options & RXH_L4_B_0_1) && (options & RXH_L4_B_2_3)) {
+               hash_proto->proto.ipv6_tcp = 1;
+               rss_enabled++;
+       }
+       get_rss_hash_options(fd, name, UDP_V6_FLOW, &options);
+       if ((options & RXH_IP_SRC) && (options & RXH_IP_DST) &&
+           (options & RXH_L4_B_0_1) && (options & RXH_L4_B_2_3)) {
+               hash_proto->proto.ipv6_udp = 1;
+               rss_enabled++;
+       }
+       return rss_enabled;
+}
+
+/**
+ * Set hash options of a packet socket
+ *
+ * @param fd              Socket file descriptor
+ * @param name            Interface name
+ * @param flow_type       Packet flow type
+ * @param options         Hash options
+ *
+ * @retval 0 on success
+ * @retval <0 on failure
+ */
+static inline int set_rss_hash(int fd, const char *name,
+                              uint32_t flow_type, uint64_t options)
+{
+       struct ifreq ifr;
+       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 = options;
+
+       ifr.ifr_data = (caddr_t)&rsscmd;
+
+       if (ioctl(fd, SIOCETHTOOL, &ifr) < 0)
+               return -1;
+
+       return 0;
+}
+
+int rss_conf_set_fd(int fd, const char *name,
+                   const odp_pktin_hash_proto_t *hash_proto)
+{
+       uint64_t options;
+       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) {
+               options = 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, options))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv4_tcp && !cur_hash.proto.ipv4_tcp) {
+               options = 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, options))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv6_udp && !cur_hash.proto.ipv6_udp) {
+               options = 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, options))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv6_tcp && !cur_hash.proto.ipv6_tcp) {
+               options = 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, options))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv4 && !cur_hash.proto.ipv4) {
+               options = RXH_IP_SRC | RXH_IP_DST;
+               if (set_rss_hash(fd, name, IPV4_FLOW, options))
+                       return -1;
+       }
+       if (hash_proto->proto.ipv6 && !cur_hash.proto.ipv6) {
+               options = RXH_IP_SRC | RXH_IP_DST;
+               if (set_rss_hash(fd, name, IPV6_FLOW, options))
+                       return -1;
+       }
+       return 0;
+}
+
+int rss_conf_get_supported_fd(int fd, const char *name,
+                             odp_pktin_hash_proto_t *hash_proto)
+{
+       uint64_t options;
+       int rss_supported = 0;
+
+       memset(hash_proto, 0, sizeof(odp_pktin_hash_proto_t));
+
+       if (!get_rss_hash_options(fd, name, IPV4_FLOW, &options)) {
+               if (!set_rss_hash(fd, name, IPV4_FLOW, options)) {
+                       hash_proto->proto.ipv4 = 1;
+                       rss_supported++;
+               }
+       }
+       if (!get_rss_hash_options(fd, name, TCP_V4_FLOW, &options)) {
+               if (!set_rss_hash(fd, name, TCP_V4_FLOW, options)) {
+                       hash_proto->proto.ipv4_tcp = 1;
+                       rss_supported++;
+               }
+       }
+       if (!get_rss_hash_options(fd, name, UDP_V4_FLOW, &options)) {
+               if (!set_rss_hash(fd, name, UDP_V4_FLOW, options)) {
+                       hash_proto->proto.ipv4_udp = 1;
+                       rss_supported++;
+               }
+       }
+       if (!get_rss_hash_options(fd, name, IPV6_FLOW, &options)) {
+               if (!set_rss_hash(fd, name, IPV6_FLOW, options)) {
+                       hash_proto->proto.ipv6 = 1;
+                       rss_supported++;
+               }
+       }
+       if (!get_rss_hash_options(fd, name, TCP_V6_FLOW, &options)) {
+               if (!set_rss_hash(fd, name, TCP_V6_FLOW, options)) {
+                       hash_proto->proto.ipv6_tcp = 1;
+                       rss_supported++;
+               }
+       }
+       if (!get_rss_hash_options(fd, name, UDP_V6_FLOW, &options)) {
+               if (!set_rss_hash(fd, name, UDP_V6_FLOW, options)) {
+                       hash_proto->proto.ipv6_udp = 1;
+                       rss_supported++;
+               }
+       }
+       return rss_supported;
+}
+
+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:
  */
-- 
2.6.3

_______________________________________________
lng-odp mailing list
[email protected]
https://lists.linaro.org/mailman/listinfo/lng-odp

Reply via email to