From 2296b3ba76327d81da29abf6b33b554215a5b801 Mon Sep 17 00:00:00 2001 From: Adam Kiripolsky Date: Tue, 10 Dec 2024 16:26:49 +0100 Subject: [PATCH] dpdk/rss: add rte_flow rss support for ixgbe 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 == 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 key_len 40 func default / end" Ticket: 7337 --- src/source-dpdk.c | 11 +++++++---- src/util-dpdk-ixgbe.c | 37 ++++++++++++++++++++++++++++++++++++- src/util-dpdk-ixgbe.h | 3 ++- src/util-dpdk-rss.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/util-dpdk-rss.h | 2 +- 5 files changed, 87 insertions(+), 7 deletions(-) diff --git a/src/source-dpdk.c b/src/source-dpdk.c index 4cb74b6df5..eeeb2fe011 100644 --- a/src/source-dpdk.c +++ b/src/source-dpdk.c @@ -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) */ } } diff --git a/src/util-dpdk-ixgbe.c b/src/util-dpdk-ixgbe.c index 5627c45270..7fb43ec2bf 100644 --- a/src/util-dpdk-ixgbe.c +++ b/src/util-dpdk-ixgbe.c @@ -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 @@ -32,14 +32,49 @@ #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 */ /** * @} diff --git a/src/util-dpdk-ixgbe.h b/src/util-dpdk-ixgbe.h index 3cb18fa55d..79d3881397 100644 --- a/src/util-dpdk-ixgbe.h +++ b/src/util-dpdk-ixgbe.h @@ -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 */ diff --git a/src/util-dpdk-rss.c b/src/util-dpdk-rss.c index ee4f0b43b4..f84840c396 100644 --- a/src/util-dpdk-rss.c +++ b/src/util-dpdk-rss.c @@ -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 diff --git a/src/util-dpdk-rss.h b/src/util-dpdk-rss.h index 61d7c97f7f..1c3233a292 100644 --- a/src/util-dpdk-rss.h +++ b/src/util-dpdk-rss.h @@ -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, -- 2.47.2