]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
dpdk/i40e: support RSS on Intel i40e PMD driver
authorLukas Sismis <lukas.sismis@gmail.com>
Sun, 21 Nov 2021 22:22:24 +0000 (23:22 +0100)
committerVictor Julien <vjulien@oisf.net>
Tue, 14 Dec 2021 11:41:16 +0000 (12:41 +0100)
Due to peculiar behavior of i40e PMD driver, the RSS is required to be set
via rte_flow rules or a hash filter as compared to other NICs where RSS is
configured through port configuration structure.
RTE_FLOW rules are created on 5-tuples (as opposed to 3-tuple configured
on the other NICs). Fragmented traffic have been tested with this setup
and it has been proven that fragmented packets of the same flow are
received on the same queue. At the same time, setting 3-tuple on rte_flow
rules have not yield in the expected results.

Notes from the experiments:

- Configuration of 5-tuple (as is in the commit):
    fragmented and nonfragmented packets are received by the same workers
    even when I applied seed to alter them via tcpreplay-edit (option --seed)

- Setting only ETH_RSS_FRAG_IPV4 and ETH_RSS_IPV4 (i.e. setting 3-tuple):
    when setting ETH_RSS_IPV4, the PMD driver says that pctype is not
    supported (generally this means that the "type" of traffic is not
    a valid configuration for the i40e)

- Setting only ETH_RSS_FRAG_IPV4 and ETH_RSS_NONFRAG_IPV4_OTHER:
    this doesn't work well, packets of the same flow are received on
    the different workers (my explanation is that the fragmented packets are
    matched with ETH_RSS_FRAG_IPV4 but the other UDP packets are not matched
    with ETH_RSS_NONFRAG_IPV4_OTHER rte_flow rule (they would be matched with
    ETH_RSS_NONFRAG_IPV4_UDP).

src/Makefile.am
src/runmode-dpdk.c
src/source-dpdk.c
src/util-dpdk-i40e.c [new file with mode: 0644]
src/util-dpdk-i40e.h [new file with mode: 0644]
src/util-dpdk.h

index bfdead9fb8ae13b82b4dd5b0c599450e12d0b329..b206382846600913ae09262e151765083e2b919a 100755 (executable)
@@ -508,6 +508,7 @@ noinst_HEADERS = \
        util-detect.h \
        util-device.h \
        util-dpdk.h \
+       util-dpdk-i40e.h \
        util-ebpf.h \
        util-enum.h \
        util-error.h \
@@ -1073,6 +1074,7 @@ libsuricata_c_a_SOURCES = \
        util-detect.c \
        util-device.c \
        util-dpdk.c \
+       util-dpdk-i40e.c \
        util-ebpf.c \
        util-enum.c \
        util-error.c \
index 9c7c9cb71d555b929d21dc86796d503720896c2d..def0a3320701a510e0eb036a15b46fe855de785a 100644 (file)
@@ -38,6 +38,7 @@
 #include "util-byte.h"
 #include "util-cpu.h"
 #include "util-dpdk.h"
+#include "util-dpdk-i40e.h"
 
 #ifdef HAVE_DPDK
 
@@ -742,6 +743,9 @@ static DPDKIfaceConfig *ConfigParse(const char *iface)
 
 static void DeviceSetPMDSpecificRSS(struct rte_eth_rss_conf *rss_conf, const char *driver_name)
 {
+    // RSS is configured in a specific way for a driver i40e and DPDK version <= 19.xx
+    if (strcmp(driver_name, "net_i40e") == 0)
+        i40eDeviceSetRSSHashFunction(&rss_conf->rss_hf);
 }
 
 static void DumpRSSFlags(const uint64_t requested, const uint64_t actual)
index 202e335e5b4259ff6edb0698945006c73d9fdcd3..fc50de0ef0b93414742b687e7e8c491e4948cc0c 100644 (file)
@@ -84,6 +84,7 @@ TmEcode NoDPDKSupportExit(ThreadVars *tv, const void *initdata, void **data)
 #else /* We have DPDK support */
 
 #include "util-dpdk.h"
+#include "util-dpdk-i40e.h"
 #include <numa.h>
 
 #define BURST_SIZE 32
@@ -188,10 +189,25 @@ static uint64_t DPDKGetSeconds()
 
 static void DevicePostStartPMDSpecificActions(DPDKThreadVars *ptv, const char *driver_name)
 {
+    // The PMD Driver i40e has a special way to set the RSS, it can be set via rte_flow rules
+    // and only after the start of the port
+    if (strcmp(driver_name, "net_i40e") == 0)
+        i40eDeviceSetRSS(ptv->port_id, ptv->threads);
 }
 
 static void DevicePreStopPMDSpecificActions(DPDKThreadVars *ptv, const char *driver_name)
 {
+    int retval;
+
+    if (strcmp(driver_name, "net_i40e") == 0) {
+        // Flush the RSS rules that have been inserted in the post start section
+        struct rte_flow_error flush_error = { 0 };
+        retval = rte_flow_flush(ptv->port_id, &flush_error);
+        if (retval != 0) {
+            SCLogError(SC_ERR_DPDK_CONF, "Unable to flush rte_flow rules: %s Flush error msg: %s",
+                    rte_strerror(-retval), flush_error.message);
+        }
+    }
 }
 
 /**
diff --git a/src/util-dpdk-i40e.c b/src/util-dpdk-i40e.c
new file mode 100644 (file)
index 0000000..70e18f4
--- /dev/null
@@ -0,0 +1,382 @@
+/* Copyright (C) 2021 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
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ *  \defgroup dpdk DPDK Intel I40E driver helpers functions
+ *
+ *  @{
+ */
+
+/**
+ * \file
+ *
+ * \author Lukas Sismis <lukas.sismis@gmail.com>
+ *
+ * DPDK driver's helper functions
+ *
+ */
+
+#include "util-dpdk-i40e.h"
+
+#ifdef HAVE_DPDK
+
+#define I40E_RSS_HKEY_LEN 52
+
+#if RTE_VER_YEAR <= 19
+static int i40eDeviceEnableSymHash(
+        int port_id, const char *port_name, uint32_t ftype, enum rte_eth_hash_function function)
+{
+    struct rte_eth_hash_filter_info info;
+    int retval;
+    uint32_t idx, offset;
+
+    memset(&info, 0, sizeof(info));
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+    retval = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_HASH);
+#pragma GCC diagnostic pop
+    if (retval < 0) {
+        SCLogError(SC_ERR_DPDK_CONF, "RTE_ETH_FILTER_HASH not supported on port: %s", port_name);
+        return retval;
+    }
+
+    info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+    info.info.global_conf.hash_func = function;
+
+    idx = ftype / UINT64_BIT;
+    offset = ftype % UINT64_BIT;
+    info.info.global_conf.valid_bit_mask[idx] |= (1ULL << offset);
+    info.info.global_conf.sym_hash_enable_mask[idx] |= (1ULL << offset);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+    retval = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH, RTE_ETH_FILTER_SET, &info);
+#pragma GCC diagnostic pop
+
+    if (retval < 0) {
+        SCLogError(SC_ERR_DPDK_CONF, "Cannot set global hash configurations on port %s", port_name);
+        return retval;
+    }
+
+    return 0;
+}
+
+static int i40eDeviceSetSymHash(int port_id, const char *port_name, int enable)
+{
+    int ret;
+    struct rte_eth_hash_filter_info info;
+
+    memset(&info, 0, sizeof(info));
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+    ret = rte_eth_dev_filter_supported(port_id, RTE_ETH_FILTER_HASH);
+#pragma GCC diagnostic pop
+
+    if (ret < 0) {
+        SCLogError(SC_ERR_DPDK_CONF, "RTE_ETH_FILTER_HASH not supported on port: %s", port_name);
+        return ret;
+    }
+
+    info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+    info.info.enable = enable;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+    ret = rte_eth_dev_filter_ctrl(port_id, RTE_ETH_FILTER_HASH, RTE_ETH_FILTER_SET, &info);
+#pragma GCC diagnostic pop
+
+    if (ret < 0) {
+        SCLogError(SC_ERR_DPDK_CONF, "Cannot set symmetric hash enable per port on port %s",
+                port_name);
+        return ret;
+    }
+
+    return 0;
+}
+
+static int i40eDeviceSetRSSWithFilter(int port_id, const char *port_name)
+{
+    int retval = 0;
+
+    // Behavior of RTE_FLOW in DPDK version 19.xx and less is different than on versions
+    // above. For that reason RSS on i40e driver is set differently.
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_FRAG_IPV4, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_TCP, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_UDP, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_SCTP, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV4_OTHER, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_FRAG_IPV6, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_TCP, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_UDP, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_SCTP, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+    retval |= i40eDeviceEnableSymHash(
+            port_id, port_name, RTE_ETH_FLOW_NONFRAG_IPV6_OTHER, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+
+    retval |= i40eDeviceSetSymHash(port_id, port_name, 1);
+    return retval;
+}
+
+#else
+
+static int i40eDeviceSetRSSFlowQueues(
+        int port_id, const char *port_name, struct rte_eth_rss_conf rss_conf, int nb_rx_queues)
+{
+    struct rte_flow_action_rss rss_action_conf = { 0 };
+    struct rte_flow_attr attr = { 0 };
+    struct rte_flow_item pattern[] = { { 0 }, { 0 }, { 0 }, { 0 } };
+    struct rte_flow_action action[] = { { 0 }, { 0 } };
+    struct rte_flow *flow;
+    struct rte_flow_error flow_error = { 0 };
+    uint16_t queues[RTE_MAX_QUEUES_PER_PORT];
+
+    for (int i = 0; i < nb_rx_queues; ++i)
+        queues[i] = i;
+
+    rss_action_conf.func = RTE_ETH_HASH_FUNCTION_DEFAULT;
+    rss_action_conf.level = 0;
+    rss_action_conf.types = 0; // queues region can not be configured with types
+    rss_action_conf.key = rss_conf.rss_key;
+    rss_action_conf.key_len = rss_conf.rss_key_len;
+    rss_action_conf.queue_num = nb_rx_queues;
+    rss_action_conf.queue = queues;
+
+    attr.ingress = 1;
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_END;
+    action[0].type = RTE_FLOW_ACTION_TYPE_RSS;
+    action[0].conf = &rss_action_conf;
+    action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+    flow = rte_flow_create(port_id, &attr, pattern, action, &flow_error);
+    if (flow == NULL) {
+        SCLogError(SC_ERR_DPDK_CONF, "Error when creating rte_flow rule on %s: %s", port_name,
+                flow_error.message);
+        int ret = rte_flow_validate(port_id, &attr, pattern, action, &flow_error);
+        SCLogError(SC_ERR_DPDK_CONF, "Error on rte_flow validation for port %s: %s errmsg: %s",
+                port_name, rte_strerror(-ret), flow_error.message);
+        return ret;
+    } else {
+        SCLogInfo("RTE_FLOW queue region created for port %s", port_name);
+    }
+    return 0;
+}
+
+static int i40eDeviceCreateRSSFlow(int port_id, const char *port_name,
+        struct rte_eth_rss_conf rss_conf, uint64_t rss_type, struct rte_flow_item *pattern)
+{
+    struct rte_flow_action_rss rss_action_conf = { 0 };
+    struct rte_flow_attr attr = { 0 };
+    struct rte_flow_action action[] = { { 0 }, { 0 } };
+    struct rte_flow *flow;
+    struct rte_flow_error flow_error = { 0 };
+
+    rss_action_conf.func = RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ;
+    rss_action_conf.level = 0;
+    rss_action_conf.types = rss_type;
+    rss_action_conf.key_len = rss_conf.rss_key_len;
+    rss_action_conf.key = rss_conf.rss_key;
+    rss_action_conf.queue_num = 0;
+    rss_action_conf.queue = NULL;
+
+    attr.ingress = 1;
+    action[0].type = RTE_FLOW_ACTION_TYPE_RSS;
+    action[0].conf = &rss_action_conf;
+    action[1].type = RTE_FLOW_ACTION_TYPE_END;
+
+    flow = rte_flow_create(port_id, &attr, pattern, action, &flow_error);
+    if (flow == NULL) {
+        SCLogError(SC_ERR_DPDK_CONF, "Error when creating rte_flow rule on %s: %s", port_name,
+                flow_error.message);
+        int ret = rte_flow_validate(port_id, &attr, pattern, action, &flow_error);
+        SCLogError(SC_ERR_DPDK_CONF, "Error on rte_flow validation for port %s: %s errmsg: %s",
+                port_name, rte_strerror(-ret), flow_error.message);
+        return ret;
+    } else {
+        SCLogInfo("RTE_FLOW flow rule created for port %s", port_name);
+    }
+
+    return 0;
+}
+
+static int i40eDeviceSetRSSFlowIPv4(
+        int port_id, const char *port_name, struct rte_eth_rss_conf rss_conf)
+{
+    int ret = 0;
+    struct rte_flow_item pattern[] = { { 0 }, { 0 }, { 0 }, { 0 } };
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(
+            port_id, port_name, rss_conf, ETH_RSS_NONFRAG_IPV4_OTHER, pattern);
+    memset(pattern, 0, sizeof(pattern));
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP;
+    pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, ETH_RSS_NONFRAG_IPV4_UDP, pattern);
+    memset(pattern, 0, sizeof(pattern));
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_TCP;
+    pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, ETH_RSS_NONFRAG_IPV4_TCP, pattern);
+    memset(pattern, 0, sizeof(pattern));
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_SCTP;
+    pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(
+            port_id, port_name, rss_conf, ETH_RSS_NONFRAG_IPV4_SCTP, pattern);
+    memset(pattern, 0, sizeof(pattern));
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV4;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, ETH_RSS_FRAG_IPV4, pattern);
+
+    return ret;
+}
+
+static int i40eDeviceSetRSSFlowIPv6(
+        int port_id, const char *port_name, struct rte_eth_rss_conf rss_conf)
+{
+    int ret = 0;
+    struct rte_flow_item pattern[] = { { 0 }, { 0 }, { 0 }, { 0 } };
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(
+            port_id, port_name, rss_conf, ETH_RSS_NONFRAG_IPV6_OTHER, pattern);
+    memset(pattern, 0, sizeof(pattern));
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_UDP;
+    pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, ETH_RSS_NONFRAG_IPV6_UDP, pattern);
+    memset(pattern, 0, sizeof(pattern));
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_TCP;
+    pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, ETH_RSS_NONFRAG_IPV6_TCP, pattern);
+    memset(pattern, 0, sizeof(pattern));
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_SCTP;
+    pattern[3].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(
+            port_id, port_name, rss_conf, ETH_RSS_NONFRAG_IPV6_SCTP, pattern);
+    memset(pattern, 0, sizeof(pattern));
+
+    pattern[0].type = RTE_FLOW_ITEM_TYPE_ETH;
+    pattern[1].type = RTE_FLOW_ITEM_TYPE_IPV6;
+    pattern[2].type = RTE_FLOW_ITEM_TYPE_END;
+    ret |= i40eDeviceCreateRSSFlow(port_id, port_name, rss_conf, ETH_RSS_FRAG_IPV6, pattern);
+
+    return ret;
+}
+
+static int i40eDeviceSetRSSWithFlows(int port_id, const char *port_name, int nb_rx_queues)
+{
+    int retval;
+    uint8_t rss_key[I40E_RSS_HKEY_LEN];
+    struct rte_flow_error flush_error = { 0 };
+    struct rte_eth_rss_conf rss_conf = {
+        .rss_key = rss_key,
+        .rss_key_len = I40E_RSS_HKEY_LEN,
+    };
+
+    retval = rte_eth_dev_rss_hash_conf_get(port_id, &rss_conf);
+    if (retval != 0) {
+        SCLogError(SC_ERR_DPDK_CONF, "Unable to get RSS hash configuration of port %s", port_name);
+        return retval;
+    }
+
+    retval = 0;
+    retval |= i40eDeviceSetRSSFlowQueues(port_id, port_name, rss_conf, nb_rx_queues);
+    retval |= i40eDeviceSetRSSFlowIPv4(port_id, port_name, rss_conf);
+    retval |= i40eDeviceSetRSSFlowIPv6(port_id, port_name, rss_conf);
+    if (retval != 0) {
+        retval = rte_flow_flush(port_id, &flush_error);
+        if (retval != 0) {
+            SCLogError(SC_ERR_DPDK_CONF,
+                    "Unable to flush rte_flow rules of %s: %s Flush error msg: %s", port_name,
+                    rte_strerror(-retval), flush_error.message);
+        }
+        return retval;
+    }
+
+    return 0;
+}
+
+#endif /* RTE_VER_YEAR < 19 */
+
+int i40eDeviceSetRSS(int port_id, int nb_rx_queues)
+{
+    int retval;
+    (void)nb_rx_queues; // avoid unused variable warnings
+    char port_name[RTE_ETH_NAME_MAX_LEN];
+
+    retval = rte_eth_dev_get_name_by_port(port_id, port_name);
+    if (unlikely(retval != 0)) {
+        SCLogError(SC_ERR_STAT, "Failed to convert port id %d to the interface name: %s", port_id,
+                strerror(-retval));
+        return retval;
+    }
+
+#if RTE_VER_YEAR <= 19
+    i40eDeviceSetRSSWithFilter(port_id, port_name);
+#else
+    i40eDeviceSetRSSWithFlows(port_id, port_name, nb_rx_queues);
+#endif
+    return 0;
+}
+
+void i40eDeviceSetRSSHashFunction(uint64_t *rss_hf)
+{
+    if (RTE_VER_YEAR <= 19)
+        *rss_hf = ETH_RSS_FRAG_IPV4 | ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_NONFRAG_IPV4_UDP |
+                  ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_FRAG_IPV6 |
+                  ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_NONFRAG_IPV6_SCTP |
+                  ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_SCTP;
+    else
+        *rss_hf = ETH_RSS_FRAG_IPV4 | ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_FRAG_IPV6 |
+                  ETH_RSS_NONFRAG_IPV6_OTHER;
+}
+
+#endif /* HAVE_DPDK */
+/**
+ * @}
+ */
diff --git a/src/util-dpdk-i40e.h b/src/util-dpdk-i40e.h
new file mode 100644 (file)
index 0000000..3d77b11
--- /dev/null
@@ -0,0 +1,37 @@
+/* Copyright (C) 2021 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
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Lukas Sismis <lukas.sismis@gmail.com>
+ */
+
+#ifndef UTIL_DPDK_I40E_H
+#define UTIL_DPDK_I40E_H
+
+#include "suricata-common.h"
+#include "util-dpdk.h"
+
+#ifdef HAVE_DPDK
+
+int i40eDeviceSetRSS(int port_id, int nb_rx_queues);
+void i40eDeviceSetRSSHashFunction(uint64_t *rss_conf);
+
+#endif /* HAVE_DPDK */
+
+#endif /* UTIL_DPDK_I40E_H */
index 34820db79f333ccb8c2e8bb4a1ba29ee719775a4..3c2e6da6bd8656fd224bf7a3471973b946e5d2a7 100644 (file)
@@ -33,6 +33,7 @@
 #include <rte_log.h>
 #include <rte_mempool.h>
 #include <rte_mbuf.h>
+#include <rte_flow.h>
 
 #endif /* HAVE_DPDK */