]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
dpdk/rss: add rte_flow rss support for ixgbe
authorAdam Kiripolsky <Adam.Kiripolsky@cesnet.cz>
Tue, 10 Dec 2024 15:26:49 +0000 (16:26 +0100)
committerVictor Julien <victor@inliniac.net>
Mon, 10 Feb 2025 19:01:35 +0000 (20:01 +0100)
ixgbe driver requires different configuration of RSS rte_flow
rule than i40e, with just one generic rule matching all traffic.

The generic rule configured by DeviceCreateRSSFlowGeneric() has pattern
equivalent to "pattern eth / end" in dpdk-testpmd syntax. The rule must
have rx queues configured. The rule hashes traffic to different queues
based on ipv4 and ipv6 hash types (ipv4 src dst / ipv6 src dst).
The hash key is 40 bytes long  symmetric hash key. ixgbe does not
support any other hash function than RTE_ETH_HASH_FUNCTION_DEFAULT.

The syntax in dpdk-testpmd for this rule with attributes:
port index == 0
used rx queue indices == 0 1 2 3
<hash_key> == 6d5a symmetric hash key
is as follows:
"flow create 0 ingress pattern eth / end actions rss types ipv4 ipv6
end queues 0 1 2 3 end key <hash_key> key_len 40 func default / end"

Ticket: 7337

src/source-dpdk.c
src/util-dpdk-ixgbe.c
src/util-dpdk-ixgbe.h
src/util-dpdk-rss.c
src/util-dpdk-rss.h

index 4cb74b6df50cd36308420bd07b56210f17d1791e..eeeb2fe011c38b9cd23655cf323b333e48ea4c21 100644 (file)
@@ -196,7 +196,8 @@ static void DevicePostStartPMDSpecificActions(DPDKThreadVars *ptv, const char *d
         driver_name = BondingDeviceDriverGet(ptv->port_id);
     if (strcmp(driver_name, "net_i40e") == 0)
         i40eDeviceSetRSS(ptv->port_id, ptv->threads, ptv->livedev->dev);
-
+    else if (strcmp(driver_name, "net_ixgbe") == 0)
+        ixgbeDeviceSetRSS(ptv->port_id, ptv->threads, ptv->livedev->dev);
 }
 
 static void DevicePreClosePMDSpecificActions(DPDKThreadVars *ptv, const char *driver_name)
@@ -205,8 +206,11 @@ static void DevicePreClosePMDSpecificActions(DPDKThreadVars *ptv, const char *dr
         driver_name = BondingDeviceDriverGet(ptv->port_id);
     }
 
-    if (strcmp(driver_name, "net_i40e") == 0) {
-#if RTE_VERSION >= RTE_VERSION_NUM(20, 0, 0, 0)
+    if (
+#if RTE_VERSION > RTE_VERSION_NUM(20, 0, 0, 0)
+            strcmp(driver_name, "net_i40e") == 0 ||
+#endif /* RTE_VERSION > RTE_VERSION_NUM(20, 0, 0, 0) */
+            strcmp(driver_name, "net_ixgbe") == 0) {
         // Flush the RSS rules that have been inserted in the post start section
         struct rte_flow_error flush_error = { 0 };
         int32_t retval = rte_flow_flush(ptv->port_id, &flush_error);
@@ -214,7 +218,6 @@ static void DevicePreClosePMDSpecificActions(DPDKThreadVars *ptv, const char *dr
             SCLogError("%s: unable to flush rte_flow rules: %s Flush error msg: %s",
                     ptv->livedev->dev, rte_strerror(-retval), flush_error.message);
         }
-#endif /* RTE_VERSION >= RTE_VERSION_NUM(20, 0, 0, 0) */
     }
 }
 
index 5627c45270d1af4235f93996b47ce2918bd905cf..7fb43ec2bf27d2883091d962d38e107084b0f578 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021 Open Information Security Foundation
+/* Copyright (C) 2021-2025 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
 
 #include "util-dpdk-ixgbe.h"
 #include "util-dpdk.h"
+#include "util-debug.h"
+#include "util-dpdk-bonding.h"
+#include "util-dpdk-rss.h"
 
 #ifdef HAVE_DPDK
 
+#define IXGBE_RSS_HKEY_LEN 40
+
 void ixgbeDeviceSetRSSHashFunction(uint64_t *rss_hf)
 {
     *rss_hf = RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_IPV6_EX;
 }
 
+int ixgbeDeviceSetRSS(int port_id, int nb_rx_queues, char *port_name)
+{
+    uint16_t queues[RTE_MAX_QUEUES_PER_PORT];
+    struct rte_flow_error flush_error = { 0 };
+    struct rte_eth_rss_conf rss_conf = {
+        .rss_key = RSS_HKEY,
+        .rss_key_len = IXGBE_RSS_HKEY_LEN,
+    };
+
+    if (nb_rx_queues < 1) {
+        FatalError("The number of queues for RSS configuration must be "
+                   "configured with a positive number");
+    }
+
+    struct rte_flow_action_rss rss_action_conf =
+            DPDKInitRSSAction(rss_conf, nb_rx_queues, queues, RTE_ETH_HASH_FUNCTION_DEFAULT, true);
+
+    int retval = DPDKCreateRSSFlowGeneric(port_id, port_name, rss_action_conf);
+    if (retval != 0) {
+        retval = rte_flow_flush(port_id, &flush_error);
+        if (retval != 0) {
+            SCLogError("%s: unable to flush rte_flow rules: %s Flush error msg: %s", port_name,
+                    rte_strerror(-retval), flush_error.message);
+        }
+        return retval;
+    }
+
+    return 0;
+}
+
 #endif /* HAVE_DPDK */
 /**
  * @}
index 3cb18fa55d7509e07b05b505d967b953169b8fe8..79d3881397221dcd7b11b704559a84f8c9571868 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2021 Open Information Security Foundation
+/* Copyright (C) 2021-2025 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -28,6 +28,7 @@
 
 #ifdef HAVE_DPDK
 
+int ixgbeDeviceSetRSS(int port_id, int nb_rx_queues, char *port_name);
 void ixgbeDeviceSetRSSHashFunction(uint64_t *rss_conf);
 
 #endif /* HAVE_DPDK */
index ee4f0b43b4d2c197bb946b7788c8f737e66e8348..f84840c3960307c750f038c58ae735b510d7ca98 100644 (file)
@@ -83,6 +83,47 @@ struct rte_flow_action_rss DPDKInitRSSAction(struct rte_eth_rss_conf rss_conf, i
     return rss_action_conf;
 }
 
+/**
+ * \brief Creates RTE_FLOW RSS rule used by NIC drivers
+ *        to redistribute packets to different queues based
+ *        on IP adresses.
+ *
+ * \param port_id The port identifier of the Ethernet device
+ * \param port_name The port name of the Ethernet device
+ * \param rss_conf RSS configuration
+ * \return int 0 on success, a negative errno value otherwise
+ */
+int DPDKCreateRSSFlowGeneric(
+        int port_id, const char *port_name, struct rte_flow_action_rss rss_conf)
+{
+    struct rte_flow_attr attr = { 0 };
+    struct rte_flow_action action[] = { { 0 }, { 0 } };
+    struct rte_flow_error flow_error = { 0 };
+    struct rte_flow_item pattern[] = { { 0 }, { 0 } };
+
+    rss_conf.types = RTE_ETH_RSS_IPV4 | RTE_ETH_RSS_IPV6;
+
+    attr.ingress = 1;
+    action[0].type = RTE_FLOW_ACTION_TYPE_RSS;
+    action[0].conf = &rss_conf;
+    action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_END;
+
+    struct rte_flow *flow = rte_flow_create(port_id, &attr, pattern, action, &flow_error);
+    if (flow == NULL) {
+        SCLogError("%s: rte_flow rule creation error: %s", port_name, flow_error.message);
+        int ret = rte_flow_validate(port_id, &attr, pattern, action, &flow_error);
+        SCLogError("%s: rte_flow rule validation error: %s, errmsg: %s", port_name,
+                rte_strerror(-ret), flow_error.message);
+        return ret;
+    } else {
+        SCLogDebug("%s: rte_flow rule created", port_name);
+    }
+
+    return 0;
+}
+
 /**
  * \brief Create RTE_FLOW RSS rule configured with pattern and rss_type
  *        but with no rx_queues configured. This is specific way of setting RTE_FLOW RSS rule
index 61d7c97f7f56f5aad5eb9044d7cea73f5297b385..1c3233a292076b43c3d13ef3bf6a1af3151a87c5 100644 (file)
@@ -36,7 +36,7 @@ extern uint8_t RSS_HKEY[];
 
 struct rte_flow_action_rss DPDKInitRSSAction(struct rte_eth_rss_conf rss_conf, int nb_rx_queues,
         uint16_t *queues, enum rte_eth_hash_function func, bool set_key);
-int DeviceCreateRSSFlowGeneric(
+int DPDKCreateRSSFlowGeneric(
         int port_id, const char *port_name, struct rte_flow_action_rss rss_conf);
 int DPDKSetRSSFlowQueues(int port_id, const char *port_name, struct rte_flow_action_rss rss_conf);
 int DPDKCreateRSSFlow(int port_id, const char *port_name, struct rte_flow_action_rss rss_conf,