This patch configures RSS hash filter in DPDK in order to include
source and destination MAC addresses into RSS hash calculation.
This configuration considerably improves performance for flows
with overlapping IP address spaces and non-overlapping Ethernet
address spaces.
Here is the example test result (throughput in frames per second)
I have done for 16 flows (fixed IP addresses and changing source
MAC addresses) on X710 for 10GbE SFP+:

1. original hash calculation:                    4870667 fps
2. expanded hash calculation (with this patch): 12740258 fps

Signed-off-by: Robert Wojciechowicz <robertx.wojciechow...@intel.com>
---
 INSTALL.DPDK.md   |  11 ++++
 lib/netdev-dpdk.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 162 insertions(+)

diff --git a/INSTALL.DPDK.md b/INSTALL.DPDK.md
index 9ec8bf6..0a8d67f 100644
--- a/INSTALL.DPDK.md
+++ b/INSTALL.DPDK.md
@@ -446,6 +446,17 @@ Performance Tuning:
        See below information on dpdkvhostcuse and dpdkvhostuser ports.
        See [DPDK Docs] for more information on `testpmd`.
 
+  12. RSS Hash Filter input set expanding by MAC addresses
+
+    For some DPDK drivers (e.g. it works with i40e driver on XL710)
+    it is possible to expand RSS hash filter input set by source
+    and destination MAC address. It improves significantly performance
+    for traffic with overlapping IP address spaces and non-overlapping
+    ethernet address spaces. Such configuration is performed by OVS
+    by default if it is supported by the DPDK driver.
+    DPDK IXGBE driver reports "Filter type (8) not supported" error,
+    because it does not support hash filter configuration.
+
 
 
 DPDK Rings :
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index f4ed210..b4771de 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -352,6 +352,150 @@ static int netdev_dpdk_construct(struct netdev *);
 
 struct virtio_net * netdev_dpdk_get_virtio(const struct netdev_dpdk *dev);
 
+/* Configure RSS Hash Filter input set for specified flow_type
+ * in order to include MAC addresses for RSS hash calculation.
+ * This configuration is completely optional. If any hardware
+ * does not support it, it can be skipped without any impact
+ * on further processing.
+ *
+ * XXX This configuration is not hardware agnostic. DPDK drivers,
+ *   which do not support this configuration report EINVAL error.
+ */
+static int
+dpdk_set_hash_input_set_flow(struct netdev_dpdk *dev, uint16_t flow_type)
+{
+    struct rte_eth_hash_filter_info info;
+    int err;
+
+    memset(&info, 0, sizeof (info));
+    info.info_type = RTE_ETH_HASH_FILTER_INPUT_SET_SELECT;
+    info.info.input_set_conf.flow_type = flow_type;
+    info.info.input_set_conf.field[0] = RTE_ETH_INPUT_SET_L2_SRC_MAC;
+    info.info.input_set_conf.field[1] = RTE_ETH_INPUT_SET_L2_DST_MAC;
+    info.info.input_set_conf.inset_size = 2;
+    info.info.input_set_conf.op = RTE_ETH_INPUT_SET_ADD;
+
+    /* Add source and destination MAC addresses to the Hash Filter input set */
+    err = rte_eth_dev_filter_ctrl(dev->port_id, RTE_ETH_FILTER_HASH,
+                                  RTE_ETH_FILTER_SET, &info);
+    if (err) {
+        /* XXX In case of not supported operation DPDK returns EINVAL error,
+         * so we cannot distinguish "not supported" from "invalid argument".
+         * Since it's optional feature let's report error as info */
+        VLOG_INFO("Interface %s: Cannot set hash filter on port %u: %s",
+                  dev->up.name, dev->port_id, rte_strerror(-err));
+        return err;
+    }
+
+    return 0;
+}
+
+/* Configure RSS Hash Filter input set for following flow types:
+ * RTE_ETH_FLOW_FRAG_IPV4
+ * RTE_ETH_FLOW_NONFRAG_IPV4_TCP
+ * RTE_ETH_FLOW_NONFRAG_IPV4_UDP
+ * RTE_ETH_FLOW_NONFRAG_IPV4_SCTP
+ * RTE_ETH_FLOW_NONFRAG_IPV4_OTHER
+ * RTE_ETH_FLOW_FRAG_IPV6
+ * RTE_ETH_FLOW_NONFRAG_IPV6_TCP
+ * RTE_ETH_FLOW_NONFRAG_IPV6_UDP
+ * RTE_ETH_FLOW_NONFRAG_IPV6_SCTP
+ * RTE_ETH_FLOW_NONFRAG_IPV6_OTHER
+ * RTE_ETH_FLOW_L2_PAYLOAD
+ *
+ * XXX These flow types are not supported by any DPDK driver:
+ * RTE_ETH_FLOW_RAW
+ * RTE_ETH_FLOW_IPV4
+ * RTE_ETH_FLOW_IPV6
+ * RTE_ETH_FLOW_IPV6_EX
+ * RTE_ETH_FLOW_IPV6_TCP_EX
+ * RTE_ETH_FLOW_IPV6_UDP_EX
+ */
+static int
+dpdk_set_hash_input_set(struct netdev_dpdk *dev)
+{
+    int err;
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_FRAG_IPV4);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_FRAG_IPV4");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_NONFRAG_IPV4_TCP);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_NONFRAG_IPV4_TCP");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_NONFRAG_IPV4_UDP);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_NONFRAG_IPV4_UDP");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_NONFRAG_IPV4_SCTP);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_NONFRAG_IPV4_SCTP");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_NONFRAG_IPV4_OTHER");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_FRAG_IPV6);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_FRAG_IPV6");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_NONFRAG_IPV6_TCP);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_NONFRAG_IPV6_TCP");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_NONFRAG_IPV6_UDP);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_NONFRAG_IPV6_UDP");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_NONFRAG_IPV6_SCTP);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_NONFRAG_IPV6_SCTP");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_NONFRAG_IPV6_OTHER");
+        return err;
+    }
+
+    err = dpdk_set_hash_input_set_flow(dev, RTE_ETH_FLOW_L2_PAYLOAD);
+    if (err) {
+        VLOG_INFO("Cannot set hash filter for flow type"
+                  " RTE_ETH_FLOW_L2_PAYLOAD");
+        return err;
+    }
+
+    return 0;
+}
+
 static bool
 is_dpdk_class(const struct netdev_class *class)
 {
@@ -544,6 +688,13 @@ dpdk_eth_dev_queue_setup(struct netdev_dpdk *dev, int 
n_rxq, int n_txq)
             break;
         }
 
+        diag = dpdk_set_hash_input_set(dev);
+        if (diag) {
+            /* This configuration is not supported by all DPDK drivers.
+             * Without this feature enabled we can just continue as usually. */
+            VLOG_INFO("Hash filter configuration skipped.");
+        }
+
         for (i = 0; i < n_txq; i++) {
             diag = rte_eth_tx_queue_setup(dev->port_id, i, NIC_PORT_TX_Q_SIZE,
                                           dev->socket_id, NULL);
-- 
1.8.3.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to