DPDK patches and discussions
 help / color / mirror / Atom feed
From: Serhii Iliushyk <sil-plv@napatech.com>
To: dev@dpdk.org
Cc: mko-plv@napatech.com, sil-plv@napatech.com, ckm@napatech.com,
	stephen@networkplumber.org,
	Danylo Vodopianov <dvo-plv@napatech.com>
Subject: [PATCH v1 25/31] net/ntnic: refactor RSS implementation
Date: Tue, 21 Jan 2025 18:08:03 +0100	[thread overview]
Message-ID: <20250121170814.3252171-26-sil-plv@napatech.com> (raw)
In-Reply-To: <20250121170814.3252171-1-sil-plv@napatech.com>

From: Danylo Vodopianov <dvo-plv@napatech.com>

Virtualization backward compatible RSS implementation is no longer
needed, thus RSS was refactored as follows:
* conversion of RTE_ETH_RSS fields into HSH registers was moved to
  separate files
* profile wrapper for RSS configuration was removed
* flow_nic_set_hasher(), to configure default 5-tuple hash, was
  replaced by call of hsh_set() with proper RTE_ETH_RSS*
  fields

Signed-off-by: Danylo Vodopianov <dvo-plv@napatech.com>
---
 drivers/net/ntnic/include/flow_api.h          |   9 -
 drivers/net/ntnic/include/hw_mod_backend.h    |   6 -
 drivers/net/ntnic/meson.build                 |   1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |  63 --
 .../net/ntnic/nthw/flow_api/flow_hsh_cfg.c    | 661 +++++++++++++++
 .../net/ntnic/nthw/flow_api/flow_hsh_cfg.h    |  17 +
 .../profile_inline/flow_api_hw_db_inline.c    |   5 +-
 .../profile_inline/flow_api_profile_inline.c  | 782 +-----------------
 .../profile_inline/flow_api_profile_inline.h  |   4 -
 drivers/net/ntnic/ntnic_ethdev.c              |   3 +-
 drivers/net/ntnic/ntnic_mod_reg.h             |   6 -
 11 files changed, 695 insertions(+), 862 deletions(-)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_hsh_cfg.c
 create mode 100644 drivers/net/ntnic/nthw/flow_api/flow_hsh_cfg.h

diff --git a/drivers/net/ntnic/include/flow_api.h b/drivers/net/ntnic/include/flow_api.h
index 0af766fe5b..9201b8a3ae 100644
--- a/drivers/net/ntnic/include/flow_api.h
+++ b/drivers/net/ntnic/include/flow_api.h
@@ -83,11 +83,6 @@ struct flow_eth_dev {
 	struct flow_eth_dev *next;
 };
 
-enum flow_nic_hash_e {
-	HASH_ALGO_ROUND_ROBIN = 0,
-	HASH_ALGO_5TUPLE,
-};
-
 /* registered NIC backends */
 struct flow_nic_dev {
 	uint8_t adapter_no;     /* physical adapter no in the host system */
@@ -234,10 +229,6 @@ void flow_nic_free_resource(struct flow_nic_dev *ndev, enum res_type_e res_type,
 int flow_nic_ref_resource(struct flow_nic_dev *ndev, enum res_type_e res_type, int index);
 int flow_nic_deref_resource(struct flow_nic_dev *ndev, enum res_type_e res_type, int index);
 
-int flow_nic_set_hasher(struct flow_nic_dev *ndev, int hsh_idx, enum flow_nic_hash_e algorithm);
-int flow_nic_set_hasher_fields(struct flow_nic_dev *ndev, int hsh_idx,
-	struct nt_eth_rss_conf rss_conf);
-
 int flow_get_flm_stats(struct flow_nic_dev *ndev, uint64_t *data, uint64_t size);
 
 #endif
diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index 7bb39e37eb..28980b727b 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -239,12 +239,6 @@ enum {
 	PROT_TUN_L4_ICMP = 4
 };
 
-
-enum {
-	HASH_HASH_NONE = 0,
-	HASH_5TUPLE = 8,
-};
-
 enum {
 	CPY_SELECT_DSCP_IPV4 = 0,
 	CPY_SELECT_DSCP_IPV6 = 1,
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 3c05ad1d87..bfc5ae5aa8 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -70,6 +70,7 @@ sources = files(
         'nthw/flow_api/flow_backend/flow_backend.c',
         'nthw/flow_api/flow_filter.c',
         'nthw/flow_api/flow_hasher.c',
+        'nthw/flow_api/flow_hsh_cfg.c',
         'nthw/flow_api/flow_kcc.c',
         'nthw/flow_api/flow_km.c',
         'nthw/flow_api/hw_mod/hw_mod_backend.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index d25d1a3dd1..857051fe14 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -1009,55 +1009,6 @@ int sprint_nt_rss_mask(char *str, uint16_t str_len, const char *prefix, uint64_t
 	return 0;
 }
 
-/*
- * Hash
- */
-
-int flow_nic_set_hasher(struct flow_nic_dev *ndev, int hsh_idx, enum flow_nic_hash_e algorithm)
-{
-	hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_PRESET_ALL, hsh_idx, 0, 0);
-
-	switch (algorithm) {
-	case HASH_ALGO_5TUPLE:
-		/* need to create an IPv6 hashing and enable the adaptive ip mask bit */
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_LOAD_DIST_TYPE, hsh_idx, 0, 2);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_QW0_PE, hsh_idx, 0, DYN_FINAL_IP_DST);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_QW0_OFS, hsh_idx, 0, -16);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_QW4_PE, hsh_idx, 0, DYN_FINAL_IP_DST);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_QW4_OFS, hsh_idx, 0, 0);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_W8_PE, hsh_idx, 0, DYN_L4);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_W8_OFS, hsh_idx, 0, 0);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_W9_PE, hsh_idx, 0, 0);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_W9_OFS, hsh_idx, 0, 0);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_W9_P, hsh_idx, 0, 0);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_P_MASK, hsh_idx, 0, 1);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 0, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 1, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 2, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 3, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 4, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 5, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 6, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 7, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 8, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx, 9, 0);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_SEED, hsh_idx, 0, 0xffffffff);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_HSH_VALID, hsh_idx, 0, 1);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_HSH_TYPE, hsh_idx, 0, HASH_5TUPLE);
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_AUTO_IPV4_MASK, hsh_idx, 0, 1);
-
-		NT_LOG(DBG, FILTER, "Set IPv6 5-tuple hasher with adaptive IPv4 hashing");
-		break;
-
-	default:
-	case HASH_ALGO_ROUND_ROBIN:
-		/* zero is round-robin */
-		break;
-	}
-
-	return 0;
-}
-
 static int flow_dev_dump(struct flow_eth_dev *dev,
 	struct flow_handle *flow,
 	uint16_t caller_id,
@@ -1074,19 +1025,6 @@ static int flow_dev_dump(struct flow_eth_dev *dev,
 	return profile_inline_ops->flow_dev_dump_profile_inline(dev, flow, caller_id, file, error);
 }
 
-int flow_nic_set_hasher_fields(struct flow_nic_dev *ndev, int hsh_idx,
-	struct nt_eth_rss_conf rss_conf)
-{
-	const struct profile_inline_ops *profile_inline_ops = get_profile_inline_ops();
-
-	if (profile_inline_ops == NULL) {
-		NT_LOG(ERR, FILTER, "%s: profile_inline module uninitialized", __func__);
-		return -1;
-	}
-
-	return profile_inline_ops->flow_nic_set_hasher_fields_inline(ndev, hsh_idx, rss_conf);
-}
-
 static int flow_get_aged_flows(struct flow_eth_dev *dev,
 	uint16_t caller_id,
 	void **context,
@@ -1324,7 +1262,6 @@ static const struct flow_filter_ops ops = {
 	 * Other
 	 */
 	 .hw_mod_hsh_rcp_flush = hw_mod_hsh_rcp_flush,
-	 .flow_nic_set_hasher_fields = flow_nic_set_hasher_fields,
 };
 
 void init_flow_filter(void)
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_hsh_cfg.c b/drivers/net/ntnic/nthw/flow_api/flow_hsh_cfg.c
new file mode 100644
index 0000000000..624d1a26d1
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/flow_hsh_cfg.c
@@ -0,0 +1,661 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+#include "flow_hsh_cfg.h"
+
+#define RTE_ETH_RSS_UDP_COMBINED (RTE_ETH_RSS_NONFRAG_IPV4_UDP | \
+								  RTE_ETH_RSS_NONFRAG_IPV6_UDP | \
+								  RTE_ETH_RSS_IPV6_UDP_EX)
+
+#define RTE_ETH_RSS_TCP_COMBINED (RTE_ETH_RSS_NONFRAG_IPV4_TCP | \
+								  RTE_ETH_RSS_NONFRAG_IPV6_TCP | \
+								  RTE_ETH_RSS_IPV6_TCP_EX)
+
+#define TOEPLITS_HSH_SIZE 9
+/*
+ * FPGA uses up to 10 32-bit words (320 bits) for hash calculation + 8 bits for L4 protocol number.
+ * Hashed data are split between two 128-bit Quad Words (QW)
+ * and two 32-bit Words (W), which can refer to different header parts.
+ */
+enum hsh_words_id {
+	HSH_WORDS_QW0     = 0,
+	HSH_WORDS_QW4,
+	HSH_WORDS_W8,
+	HSH_WORDS_W9,
+	HSH_WORDS_SIZE,
+};
+
+/* struct with details about hash QWs & Ws */
+struct hsh_words {
+	/*
+	 * index of W (word) or index of 1st word of QW (quad word)
+	 * is used for hash mask calculation
+	 */
+	uint8_t index;
+	enum hw_hsh_e pe;           /* offset to header part, e.g. beginning of L4 */
+	enum hw_hsh_e ofs;          /* relative offset in BYTES to 'pe' header offset above */
+	uint16_t bit_len;           /* max length of header part in bits to fit into QW/W */
+	bool free;                  /* only free words can be used for hsh calculation */
+};
+
+static enum hsh_words_id get_free_word(struct hsh_words *words, uint16_t bit_len)
+{
+	enum hsh_words_id ret = HSH_WORDS_SIZE;
+	uint16_t ret_bit_len = UINT16_MAX;
+	for (enum hsh_words_id i = HSH_WORDS_QW0; i < HSH_WORDS_SIZE; i++) {
+		if (words[i].free && bit_len <=
+			words[i].bit_len && words[i].bit_len <
+			ret_bit_len) {
+			ret = i;
+			ret_bit_len = words[i].bit_len;
+		}
+	}
+	return ret;
+}
+
+static int hsh_set_part(struct flow_nic_dev *ndev, int hsh_idx, struct hsh_words *words,
+	uint32_t pe, uint32_t ofs, int bit_len, bool toeplitz)
+{
+	int res = 0;
+
+	/* check if there is any free word, which can accommodate header part of given 'bit_len' */
+	enum hsh_words_id word = get_free_word(words, bit_len);
+
+	if (word == HSH_WORDS_SIZE) {
+		NT_LOG(ERR, FILTER, "Cannot add additional %d bits into hash", bit_len);
+		return -1;
+	}
+
+	words[word].free = false;
+
+	res |= hw_mod_hsh_rcp_set(&ndev->be, words[word].pe, hsh_idx, 0, pe);
+	NT_LOG(DBG, FILTER, "hw_mod_hsh_rcp_set(&ndev->be, %d, %d, 0, %d)", words[word].pe,
+		hsh_idx, pe);
+	res |= hw_mod_hsh_rcp_set(&ndev->be, words[word].ofs, hsh_idx, 0, ofs);
+	NT_LOG(DBG, FILTER, "hw_mod_hsh_rcp_set(&ndev->be, %d, %d, 0, %d)", words[word].ofs,
+		hsh_idx, ofs);
+
+
+	/* set HW_HSH_RCP_WORD_MASK based on used QW/W and given 'bit_len' */
+	int mask_bit_len = bit_len;
+	uint32_t mask = 0x0;
+	uint32_t toeplitz_mask[TOEPLITS_HSH_SIZE] = {0x0};
+	/* iterate through all words of QW */
+	uint16_t words_count = words[word].bit_len / 32;
+	for (uint16_t mask_off = 1; mask_off <= words_count; mask_off++) {
+		if (mask_bit_len >= 32) {
+			mask_bit_len -= 32;
+			mask = 0xffffffff;
+		} else if (mask_bit_len > 0) {
+			mask = 0xffffffff >> (32 - mask_bit_len) << (32 - mask_bit_len);
+			mask_bit_len = 0;
+		} else {
+			mask = 0x0;
+		}
+		/* reorder QW words mask from little to big endian */
+		res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx,
+			words[word].index + words_count - mask_off, mask);
+		NT_LOG(DBG, FILTER,
+			"hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, %d, %d, 0x%08" PRIX32 ")",
+				hsh_idx, words[word].index + words_count - mask_off, mask);
+		toeplitz_mask[words[word].index + mask_off - 1] = mask;
+	}
+	if (toeplitz) {
+		NT_LOG(DBG, FILTER,
+			"Partial Toeplitz RSS key mask: %08" PRIX32 " %08" PRIX32 " %08" PRIX32
+			" %08" PRIX32 " %08" PRIX32 " %08" PRIX32 " %08" PRIX32 " %08" PRIX32
+			" %08" PRIX32 "",
+			toeplitz_mask[0], toeplitz_mask[1], toeplitz_mask[2], toeplitz_mask[3],
+			toeplitz_mask[4], toeplitz_mask[5], toeplitz_mask[6], toeplitz_mask[7],
+			toeplitz_mask[8]);
+		NT_LOG(DBG, FILTER, "                               MSB                                                                          LSB");
+	}
+	return res;
+}
+
+static __rte_always_inline bool all_bits_enabled(uint64_t hash_mask, uint64_t hash_bits)
+{
+	return (hash_mask & hash_bits) == hash_bits;
+}
+
+static __rte_always_inline void unset_bits(uint64_t *hash_mask, uint64_t hash_bits)
+{
+	*hash_mask &= ~hash_bits;
+}
+
+static __rte_always_inline void unset_bits_and_log(uint64_t *hash_mask, uint64_t hash_bits)
+{
+	char rss_buffer[4096];
+	uint16_t rss_buffer_len = sizeof(rss_buffer);
+
+	if (sprint_nt_rss_mask(rss_buffer, rss_buffer_len, " ", *hash_mask & hash_bits) == 0)
+		NT_LOG(DBG, FILTER, "Configured RSS types:%s", rss_buffer);
+	unset_bits(hash_mask, hash_bits);
+}
+
+static __rte_always_inline void unset_bits_if_all_enabled(uint64_t *hash_mask, uint64_t hash_bits)
+{
+	if (all_bits_enabled(*hash_mask, hash_bits))
+		unset_bits(hash_mask, hash_bits);
+}
+
+int hsh_set(struct flow_nic_dev *ndev, int hsh_idx, struct nt_eth_rss_conf rss_conf)
+{
+	uint64_t fields = rss_conf.rss_hf;
+
+	char rss_buffer[4096];
+	uint16_t rss_buffer_len = sizeof(rss_buffer);
+
+	if (sprint_nt_rss_mask(rss_buffer, rss_buffer_len, " ", fields) == 0)
+		NT_LOG(DBG, FILTER, "Requested RSS types:%s", rss_buffer);
+
+	/*
+	 * configure all (Q)Words usable for hash calculation
+	 * Hash can be calculated from 4 independent header parts:
+	 *      | QW0           | Qw4           | W8| W9|
+	 * word | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+	 */
+	struct hsh_words words[HSH_WORDS_SIZE] = {
+		{ 0, HW_HSH_RCP_QW0_PE, HW_HSH_RCP_QW0_OFS, 128, true },
+		{ 4, HW_HSH_RCP_QW4_PE, HW_HSH_RCP_QW4_OFS, 128, true },
+		{ 8, HW_HSH_RCP_W8_PE,  HW_HSH_RCP_W8_OFS,   32, true },
+		 /* not supported for Toeplitz */
+		{ 9, HW_HSH_RCP_W9_PE,  HW_HSH_RCP_W9_OFS,   32, true },
+	};
+
+	int res = 0;
+	res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_PRESET_ALL, hsh_idx, 0, 0);
+	/* enable hashing */
+	res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_LOAD_DIST_TYPE, hsh_idx, 0, 2);
+
+	/* configure selected hash function and its key */
+	bool toeplitz = false;
+	switch (rss_conf.algorithm) {
+	case RTE_ETH_HASH_FUNCTION_DEFAULT:
+		/* Use default NTH10 hashing algorithm */
+		res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_TOEPLITZ, hsh_idx, 0, 0);
+		/* Use 1st 32-bits from rss_key to configure NTH10 SEED */
+		res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_SEED, hsh_idx, 0,
+			rss_conf.rss_key[0] << 24 | rss_conf.rss_key[1] << 16 |
+				rss_conf.rss_key[2] << 8 | rss_conf.rss_key[3]);
+		break;
+	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+		toeplitz = true;
+		res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_TOEPLITZ, hsh_idx, 0, 1);
+		uint8_t empty_key = 0;
+
+		/* Toeplitz key (always 40B) words have to be programmed in reverse order */
+		for (uint8_t i = 0; i <= (MAX_RSS_KEY_LEN - 4); i += 4) {
+			res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_K, hsh_idx, 9 - i / 4,
+				rss_conf.rss_key[i] << 24 | rss_conf.rss_key[i + 1] << 16 |
+				rss_conf.rss_key[i + 2] << 8 | rss_conf.rss_key[i + 3]);
+			NT_LOG(DBG, FILTER,
+				"hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_K, %d, %d, 0x%" PRIX32 ")",
+				hsh_idx, 9 - i / 4, rss_conf.rss_key[i] << 24 |
+				rss_conf.rss_key[i + 1] << 16 | rss_conf.rss_key[i + 2] << 8 |
+				rss_conf.rss_key[i + 3]);
+			empty_key |= rss_conf.rss_key[i] | rss_conf.rss_key[i + 1] |
+				rss_conf.rss_key[i + 2] | rss_conf.rss_key[i + 3];
+		}
+
+		if (empty_key == 0) {
+			NT_LOG(ERR, FILTER, "Toeplitz key must be configured. Key with all bytes set to zero is not allowed.");
+			return -1;
+		}
+		words[HSH_WORDS_W9].free = false;
+		NT_LOG(DBG, FILTER, "Toeplitz hashing is enabled thus W9 and P_MASK cannot be used.");
+		break;
+	default:
+		NT_LOG(ERR, FILTER, "Unknown hashing function %d requested", rss_conf.algorithm);
+		return -1;
+	}
+
+	/* indication that some IPv6 flag is present */
+	bool ipv6 = fields & (NT_ETH_RSS_IPV6_MASK);
+	/* store proto mask for later use at IP and L4 checksum handling */
+	uint64_t l4_proto_mask = fields &
+				(RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV4_UDP |
+				RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV4_OTHER |
+				RTE_ETH_RSS_NONFRAG_IPV6_TCP | RTE_ETH_RSS_NONFRAG_IPV6_UDP |
+				RTE_ETH_RSS_NONFRAG_IPV6_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_OTHER |
+				RTE_ETH_RSS_IPV6_TCP_EX | RTE_ETH_RSS_IPV6_UDP_EX);
+
+	/* outermost headers are used by default, so innermost bit takes precedence if detected */
+	bool outer = (fields & RTE_ETH_RSS_LEVEL_INNERMOST) ? false : true;
+	unset_bits(&fields, RTE_ETH_RSS_LEVEL_MASK);
+
+	if (fields == 0) {
+		NT_LOG(ERR, FILTER, "RSS hash configuration 0x%" PRIX64 " is not valid.",
+			rss_conf.rss_hf);
+		return -1;
+	}
+
+	/* indication that IPv4 `protocol` or IPv6 `next header` fields shall be part of the hash */
+	bool l4_proto_hash = false;
+
+	/*
+	 * check if SRC_ONLY & DST_ONLY are used simultaneously;
+	 * According to DPDK, we shall behave like none of these bits is set
+	 */
+	unset_bits_if_all_enabled(&fields, RTE_ETH_RSS_L2_SRC_ONLY | RTE_ETH_RSS_L2_DST_ONLY);
+	unset_bits_if_all_enabled(&fields, RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY);
+	unset_bits_if_all_enabled(&fields, RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY);
+
+	/* L2 */
+	if (fields & (RTE_ETH_RSS_ETH | RTE_ETH_RSS_L2_SRC_ONLY | RTE_ETH_RSS_L2_DST_ONLY)) {
+		if (outer) {
+			if (fields & RTE_ETH_RSS_L2_SRC_ONLY) {
+				NT_LOG(DBG, FILTER, "Set outer src MAC hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_L2,
+					6, 48, toeplitz);
+			} else if (fields & RTE_ETH_RSS_L2_DST_ONLY) {
+				NT_LOG(DBG, FILTER, "Set outer dst MAC hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_L2,
+					0, 48, toeplitz);
+			} else {
+				NT_LOG(DBG, FILTER, "Set outer src & dst MAC hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_L2,
+					0, 96, toeplitz);
+			}
+		} else {
+			if (fields & RTE_ETH_RSS_L2_SRC_ONLY) {
+				NT_LOG(DBG, FILTER, "Set inner src MAC hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L2,
+					6, 48, toeplitz);
+			} else if (fields & RTE_ETH_RSS_L2_DST_ONLY) {
+				NT_LOG(DBG, FILTER, "Set inner dst MAC hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L2,
+					0, 48, toeplitz);
+			} else {
+				NT_LOG(DBG, FILTER, "Set inner src & dst MAC hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L2,
+					0, 96, toeplitz);
+			}
+		}
+		unset_bits_and_log(&fields, RTE_ETH_RSS_ETH | RTE_ETH_RSS_L2_SRC_ONLY |
+			RTE_ETH_RSS_L2_DST_ONLY);
+	}
+
+	/*
+	 * VLAN support of multiple VLAN headers,
+	 * where S-VLAN is the first and C-VLAN the last VLAN header
+	 */
+	if (fields & RTE_ETH_RSS_C_VLAN) {
+		/*
+		 * use MPLS protocol offset, which points
+		 * just after ethertype with relative
+		 * offset -6 (i.e. 2 bytes
+		 * of ethertype & size + 4 bytes of VLAN header field)
+		 * to access last vlan header
+		 */
+		if (outer) {
+			NT_LOG(DBG, FILTER, "Set outer C-VLAN hasher.");
+			/*
+			 * use whole 32-bit 802.1a tag - backward compatible
+			 * with VSWITCH implementation
+			 */
+			res |= hsh_set_part(ndev, hsh_idx, words, DYN_MPLS,
+				-6, 32, toeplitz);
+		} else {
+			NT_LOG(DBG, FILTER, "Set inner C-VLAN hasher.");
+			/*
+			 * use whole 32-bit 802.1a tag - backward compatible
+			 * with VSWITCH implementation
+			 */
+			res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_MPLS,
+				-6, 32, toeplitz);
+		}
+		unset_bits_and_log(&fields, RTE_ETH_RSS_C_VLAN);
+	}
+
+	if (fields & RTE_ETH_RSS_S_VLAN) {
+		if (outer) {
+			NT_LOG(DBG, FILTER, "Set outer S-VLAN hasher.");
+			/*
+			 * use whole 32-bit 802.1a tag - backward compatible
+			 * with VSWITCH implementation
+			 */
+			res |= hsh_set_part(ndev, hsh_idx, words, DYN_FIRST_VLAN,
+				0, 32, toeplitz);
+		} else {
+			NT_LOG(DBG, FILTER, "Set inner S-VLAN hasher.");
+			/*
+			 * use whole 32-bit 802.1a tag - backward compatible
+			 * with VSWITCH implementation
+			 */
+			res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_VLAN,
+				0, 32, toeplitz);
+		}
+		unset_bits_and_log(&fields, RTE_ETH_RSS_S_VLAN);
+	}
+
+	/* L2 payload */
+	/* calculate hash of 128-bits of l2 payload;
+	 * Use MPLS protocol offset to address the beginning
+	 * of L2 payload even if MPLS header is not present
+	 */
+	if (fields & RTE_ETH_RSS_L2_PAYLOAD) {
+		uint64_t outer_fields_enabled = 0;
+		if (outer) {
+			NT_LOG(DBG, FILTER, "Set outer L2 payload hasher.");
+			res |= hsh_set_part(ndev, hsh_idx, words, DYN_MPLS,
+				0, 128, toeplitz);
+		} else {
+			NT_LOG(DBG, FILTER, "Set inner L2 payload hasher.");
+			res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_MPLS,
+				0, 128, toeplitz);
+			outer_fields_enabled = fields & RTE_ETH_RSS_GTPU;
+		}
+		/*
+		 * L2 PAYLOAD hashing overrides all L3 & L4 RSS flags.
+		 * Thus we can clear all remaining (supported)
+		 * RSS flags...
+		 */
+		unset_bits_and_log(&fields, NT_ETH_RSS_OFFLOAD_MASK);
+		/*
+		 * ...but in case of INNER L2 PAYLOAD we must process
+		 * "always outer" GTPU field if enabled
+		 */
+		fields |= outer_fields_enabled;
+	}
+
+	/* L3 + L4 protocol number */
+	if (fields & RTE_ETH_RSS_IPV4_CHKSUM) {
+		/* only IPv4 checksum is supported by DPDK RTE_ETH_RSS_* types */
+		if (ipv6) {
+			NT_LOG(ERR, FILTER, "RSS: IPv4 checksum requested with IPv6 header hashing!");
+			res = 1;
+		} else {
+			if (outer) {
+				NT_LOG(DBG, FILTER, "Set outer IPv4 checksum hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_L3,
+					10, 16, toeplitz);
+			} else {
+				NT_LOG(DBG, FILTER, "Set inner IPv4 checksum hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L3,
+					10, 16, toeplitz);
+			}
+		}
+		/*
+		 * L3 checksum is made from whole L3 header, i.e. no need to process other
+		 * L3 hashing flags
+		 */
+		unset_bits_and_log(&fields, RTE_ETH_RSS_IPV4_CHKSUM | NT_ETH_RSS_IP_MASK);
+	}
+
+	if (fields & NT_ETH_RSS_IP_MASK) {
+		if (ipv6) {
+			if (outer) {
+				if (fields & RTE_ETH_RSS_L3_SRC_ONLY) {
+					NT_LOG(DBG, FILTER, "Set outer IPv6/IPv4 src hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_FINAL_IP_DST,
+						-16, 128, toeplitz);
+				} else if (fields & RTE_ETH_RSS_L3_DST_ONLY) {
+					NT_LOG(DBG, FILTER, "Set outer IPv6/IPv4 dst hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_FINAL_IP_DST,
+						0, 128, toeplitz);
+				} else {
+					NT_LOG(DBG, FILTER, "Set outer IPv6/IPv4 src & dst hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_FINAL_IP_DST,
+						-16, 128, toeplitz);
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_FINAL_IP_DST,
+						0, 128, toeplitz);
+				}
+			} else {
+				if (fields & RTE_ETH_RSS_L3_SRC_ONLY) {
+					NT_LOG(DBG, FILTER, "Set inner IPv6/IPv4 src hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words,
+						DYN_TUN_FINAL_IP_DST, -16, 128, toeplitz);
+				} else if (fields & RTE_ETH_RSS_L3_DST_ONLY) {
+					NT_LOG(DBG, FILTER, "Set inner IPv6/IPv4 dst hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words,
+						DYN_TUN_FINAL_IP_DST, 0, 128, toeplitz);
+				} else {
+					NT_LOG(DBG, FILTER, "Set inner IPv6/IPv4 src & dst hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words,
+						DYN_TUN_FINAL_IP_DST, -16, 128, toeplitz);
+					res |= hsh_set_part(ndev, hsh_idx, words,
+						DYN_TUN_FINAL_IP_DST, 0, 128, toeplitz);
+				}
+			}
+			/* check if fragment ID shall be part of hash */
+			if (fields & (RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_FRAG_IPV6)) {
+				if (outer) {
+					NT_LOG(DBG, FILTER, "Set outer IPv6/IPv4 fragment ID hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_ID_IPV4_6,
+						0, 32, toeplitz);
+				} else {
+					NT_LOG(DBG, FILTER, "Set inner IPv6/IPv4 fragment ID hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_ID_IPV4_6,
+						0, 32, toeplitz);
+				}
+			}
+			res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_AUTO_IPV4_MASK,
+				hsh_idx, 0, 1);
+		} else {
+			/* IPv4 */
+			if (outer) {
+				if (fields & RTE_ETH_RSS_L3_SRC_ONLY) {
+					NT_LOG(DBG, FILTER, "Set outer IPv4 src only hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_L3,
+						12, 32, toeplitz);
+				} else if (fields & RTE_ETH_RSS_L3_DST_ONLY) {
+					NT_LOG(DBG, FILTER, "Set outer IPv4 dst only hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_L3,
+						16, 32, toeplitz);
+				} else {
+					NT_LOG(DBG, FILTER, "Set outer IPv4 src & dst hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_L3,
+						12, 64, toeplitz);
+				}
+			} else {
+				if (fields & RTE_ETH_RSS_L3_SRC_ONLY) {
+					NT_LOG(DBG, FILTER, "Set inner IPv4 src only hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L3,
+						12, 32, toeplitz);
+				} else if (fields & RTE_ETH_RSS_L3_DST_ONLY) {
+					NT_LOG(DBG, FILTER, "Set inner IPv4 dst only hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L3,
+						16, 32, toeplitz);
+				} else {
+					NT_LOG(DBG, FILTER, "Set inner IPv4 src & dst hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L3,
+						12, 64, toeplitz);
+				}
+			}
+			/* check if fragment ID shall be part of hash */
+			if (fields & RTE_ETH_RSS_FRAG_IPV4) {
+				if (outer) {
+					NT_LOG(DBG, FILTER, "Set outer IPv4 fragment ID hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_ID_IPV4_6,
+						0, 16, toeplitz);
+				} else {
+					NT_LOG(DBG, FILTER, "Set inner IPv4 fragment ID hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_ID_IPV4_6,
+						0, 16, toeplitz);
+				}
+			}
+		}
+
+		/* check if L4 protocol type shall be part of hash */
+		if (l4_proto_mask)
+			l4_proto_hash = true;
+		unset_bits_and_log(&fields, NT_ETH_RSS_IP_MASK);
+	}
+
+	/* L4 */
+	if (fields & (RTE_ETH_RSS_PORT | RTE_ETH_RSS_L4_SRC_ONLY |
+		RTE_ETH_RSS_L4_DST_ONLY)) {
+		if (outer) {
+			if (fields & RTE_ETH_RSS_L4_SRC_ONLY) {
+				NT_LOG(DBG, FILTER, "Set outer L4 src hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_L4,
+					0, 16, toeplitz);
+			} else if (fields & RTE_ETH_RSS_L4_DST_ONLY) {
+				NT_LOG(DBG, FILTER, "Set outer L4 dst hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_L4,
+					2, 16, toeplitz);
+			} else {
+				NT_LOG(DBG, FILTER, "Set outer L4 src & dst hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_L4,
+					0, 32, toeplitz);
+			}
+		} else {
+			if (fields & RTE_ETH_RSS_L4_SRC_ONLY) {
+				NT_LOG(DBG, FILTER, "Set inner L4 src hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L4,
+					0, 16, toeplitz);
+			} else if (fields & RTE_ETH_RSS_L4_DST_ONLY) {
+				NT_LOG(DBG, FILTER, "Set inner L4 dst hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L4,
+					2, 16, toeplitz);
+			} else {
+				NT_LOG(DBG, FILTER, "Set inner L4 src & dst hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L4,
+					0, 32, toeplitz);
+			}
+		}
+		l4_proto_hash = true;
+		unset_bits_and_log(&fields, RTE_ETH_RSS_PORT | RTE_ETH_RSS_L4_SRC_ONLY |
+			RTE_ETH_RSS_L4_DST_ONLY);
+	}
+
+	/* IPv4 protocol / IPv6 next header fields */
+	if (l4_proto_hash) {
+		/* NOTE: HW_HSH_RCP_P_MASK is not supported for
+		 *Toeplitz and thus one of SW0, SW4 or W8
+		 * must be used to hash on `protocol` field of IPv4 or
+		 * `next header` field of IPv6 header.
+		 */
+		if (outer) {
+			NT_LOG(DBG, FILTER, "Set outer L4 protocol type / next header hasher.");
+			if (toeplitz) {
+				if (ipv6)
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_L3, 6, 8,
+						toeplitz);
+				else
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_L3, 9, 8,
+						toeplitz);
+			} else {
+				res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_P_MASK,
+					hsh_idx, 0, 1);
+				res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_TNL_P,
+					hsh_idx, 0, 0);
+			}
+		} else {
+			NT_LOG(DBG, FILTER, "Set inner L4 protocol type / next header hasher.");
+			if (toeplitz) {
+				if (ipv6) {
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L3, 6, 8,
+						toeplitz);
+				} else {
+					res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L3, 9, 8,
+						toeplitz);
+				}
+			} else {
+				res |= hw_mod_hsh_rcp_set(&ndev->be,
+					HW_HSH_RCP_P_MASK, hsh_idx, 0, 1);
+				res |= hw_mod_hsh_rcp_set(&ndev->be,
+					HW_HSH_RCP_TNL_P, hsh_idx, 0, 1);
+			}
+		}
+		l4_proto_hash = false;
+	}
+
+	/*
+	 * GTPU - for UPF use cases we always use TEID from outermost GTPU header
+	 * even if other headers are innermost
+	 */
+	if (fields & RTE_ETH_RSS_GTPU) {
+		NT_LOG(DBG, FILTER, "Set outer GTPU TEID hasher.");
+		res |= hsh_set_part(ndev, hsh_idx, words, DYN_L4_PAYLOAD, 4, 32, toeplitz);
+		unset_bits_and_log(&fields, RTE_ETH_RSS_GTPU);
+	}
+
+	/* Checksums */
+	/* only UDP, TCP and SCTP checksums are supported */
+	if (fields & RTE_ETH_RSS_L4_CHKSUM) {
+		switch (l4_proto_mask) {
+		case RTE_ETH_RSS_NONFRAG_IPV4_UDP:
+		case RTE_ETH_RSS_NONFRAG_IPV6_UDP:
+		case RTE_ETH_RSS_IPV6_UDP_EX:
+		case RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV6_UDP:
+		case RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_IPV6_UDP_EX:
+		case RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_IPV6_UDP_EX:
+		case RTE_ETH_RSS_UDP_COMBINED:
+			if (outer) {
+				NT_LOG(DBG, FILTER, "Set outer UDP checksum hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_L4, 6, 16,
+					toeplitz);
+			} else {
+				NT_LOG(DBG, FILTER, "Set inner UDP checksum hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L4, 6, 16,
+					toeplitz);
+			}
+			unset_bits_and_log(&fields, RTE_ETH_RSS_L4_CHKSUM | l4_proto_mask);
+			break;
+		case RTE_ETH_RSS_NONFRAG_IPV4_TCP:
+		case RTE_ETH_RSS_NONFRAG_IPV6_TCP:
+		case RTE_ETH_RSS_IPV6_TCP_EX:
+		case RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV6_TCP:
+		case RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_IPV6_TCP_EX:
+		case RTE_ETH_RSS_NONFRAG_IPV6_TCP | RTE_ETH_RSS_IPV6_TCP_EX:
+		case RTE_ETH_RSS_TCP_COMBINED:
+				if (outer) {
+					NT_LOG(DBG, FILTER, "Set outer TCP checksum hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words,
+						DYN_L4, 16, 16, toeplitz);
+				} else {
+					NT_LOG(DBG, FILTER, "Set inner TCP checksum hasher.");
+					res |= hsh_set_part(ndev, hsh_idx, words,
+						DYN_TUN_L4, 16, 16, toeplitz);
+				}
+				unset_bits_and_log(&fields, RTE_ETH_RSS_L4_CHKSUM | l4_proto_mask);
+				break;
+		case RTE_ETH_RSS_NONFRAG_IPV4_SCTP:
+		case RTE_ETH_RSS_NONFRAG_IPV6_SCTP:
+		case RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_SCTP:
+			if (outer) {
+				NT_LOG(DBG, FILTER, "Set outer SCTP checksum hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_L4, 8, 32,
+					toeplitz);
+			} else {
+				NT_LOG(DBG, FILTER, "Set inner SCTP checksum hasher.");
+				res |= hsh_set_part(ndev, hsh_idx, words, DYN_TUN_L4, 8, 32,
+					toeplitz);
+			}
+			unset_bits_and_log(&fields, RTE_ETH_RSS_L4_CHKSUM | l4_proto_mask);
+			break;
+		case RTE_ETH_RSS_NONFRAG_IPV4_OTHER:
+		case RTE_ETH_RSS_NONFRAG_IPV6_OTHER:
+		/* none or unsupported protocol was chosen */
+		case 0:
+			NT_LOG(ERR, FILTER, "L4 checksum hashing is supported only for UDP, TCP and SCTP protocols");
+			res = -1;
+			break;
+		/* multiple L4 protocols were selected */
+		default:
+			NT_LOG(ERR, FILTER, "L4 checksum hashing can be enabled just for one of UDP, TCP or SCTP protocols");
+			res = -1;
+			break;
+		}
+	}
+
+	if (fields || res != 0) {
+		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_PRESET_ALL, hsh_idx, 0, 0);
+		if (sprint_nt_rss_mask(rss_buffer, rss_buffer_len, " ", rss_conf.rss_hf) == 0) {
+			NT_LOG(ERR, FILTER, "RSS configuration%s is not supported for hash func %s.",
+				rss_buffer, (enum rte_eth_hash_function)toeplitz ?
+					"Toeplitz" : "NTH10");
+		} else {
+			NT_LOG(ERR, FILTER, "RSS configuration 0x%" PRIX64 " is not supported for hash func %s.",
+				rss_conf.rss_hf, (enum rte_eth_hash_function)toeplitz ?
+					"Toeplitz" : "NTH10");
+		}
+		return -1;
+	}
+
+	return res;
+}
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_hsh_cfg.h b/drivers/net/ntnic/nthw/flow_api/flow_hsh_cfg.h
new file mode 100644
index 0000000000..38901b3e8a
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/flow_hsh_cfg.h
@@ -0,0 +1,17 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2024 Napatech A/S
+ */
+
+#ifndef _FLOW_HSH_CFG_H_
+#define _FLOW_HSH_CFG_H_
+
+#include <rte_ethdev.h>
+
+#include "hw_mod_backend.h"
+#include "flow_api.h"
+
+int hsh_set(struct flow_nic_dev *ndev, int hsh_idx,
+	struct nt_eth_rss_conf rss_conf);
+
+#endif /* _FLOW_HSH_CFG_H_ */
diff --git a/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_hw_db_inline.c b/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_hw_db_inline.c
index ffab643f56..22cbf61b60 100644
--- a/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_hw_db_inline.c
+++ b/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_hw_db_inline.c
@@ -2,13 +2,14 @@
  * Copyright(c) 2023 Napatech A/S
  */
 
+#include "rte_common.h"
 
 #include "hw_mod_backend.h"
 #include "flow_api_engine.h"
 
 #include "flow_api_hw_db_inline.h"
 #include "flow_api_profile_inline_config.h"
-#include "rte_common.h"
+#include "flow_hsh_cfg.h"
 
 #define HW_DB_INLINE_ACTION_SET_NB 512
 #define HW_DB_INLINE_MATCH_SET_NB 512
@@ -2844,7 +2845,7 @@ struct hw_db_hsh_idx hw_db_inline_hsh_add(struct flow_nic_dev *ndev, void *db_ha
 	tmp_rss_conf.rss_hf = data->hash_mask;
 	memcpy(tmp_rss_conf.rss_key, data->key, MAX_RSS_KEY_LEN);
 	tmp_rss_conf.algorithm = data->func;
-	int res = flow_nic_set_hasher_fields(ndev, idx.ids, tmp_rss_conf);
+	int res = hsh_set(ndev, idx.ids, tmp_rss_conf);
 
 	if (res != 0) {
 		idx.error = 1;
diff --git a/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_profile_inline.c b/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_profile_inline.c
index 574e51c2fa..e5abd372bc 100644
--- a/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_profile_inline.c
+++ b/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_profile_inline.c
@@ -20,6 +20,7 @@
 
 #include "flow_api_profile_inline.h"
 #include "ntnic_mod_reg.h"
+#include "flow_hsh_cfg.h"
 #include <rte_spinlock.h>
 #include <rte_common.h>
 
@@ -44,12 +45,6 @@
 #define NT_VIOLATING_MBR_CFN 0
 #define NT_VIOLATING_MBR_QSL 1
 
-#define RTE_ETH_RSS_UDP_COMBINED                                                                  \
-	(RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_IPV6_UDP_EX)
-
-#define RTE_ETH_RSS_TCP_COMBINED                                                                  \
-	(RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV6_TCP | RTE_ETH_RSS_IPV6_TCP_EX)
-
 #define NT_FLM_OP_UNLEARN 0
 #define NT_FLM_OP_LEARN 1
 
@@ -3809,116 +3804,6 @@ static struct flow_handle *create_flow_filter(struct flow_eth_dev *dev, struct n
 	return NULL;
 }
 
-/*
- * FPGA uses up to 10 32-bit words (320 bits) for hash calculation + 8 bits for L4 protocol number.
- * Hashed data are split between two 128-bit Quad Words (QW)
- * and two 32-bit Words (W), which can refer to different header parts.
- */
-enum hsh_words_id {
-	HSH_WORDS_QW0 = 0,
-	HSH_WORDS_QW4,
-	HSH_WORDS_W8,
-	HSH_WORDS_W9,
-	HSH_WORDS_SIZE,
-};
-
-/* struct with details about hash QWs & Ws */
-struct hsh_words {
-	/*
-	 * index of W (word) or index of 1st word of QW (quad word)
-	 * is used for hash mask calculation
-	 */
-	uint8_t index;
-	enum hw_hsh_e pe;	/* offset to header part, e.g. beginning of L4 */
-	enum hw_hsh_e ofs;	/* relative offset in BYTES to 'pe' header offset above */
-	uint16_t bit_len;	/* max length of header part in bits to fit into QW/W */
-	bool free;	/* only free words can be used for hsh calculation */
-};
-
-static enum hsh_words_id get_free_word(struct hsh_words *words, uint16_t bit_len)
-{
-	enum hsh_words_id ret = HSH_WORDS_SIZE;
-	uint16_t ret_bit_len = UINT16_MAX;
-
-	for (enum hsh_words_id i = HSH_WORDS_QW0; i < HSH_WORDS_SIZE; i++) {
-		if (words[i].free && bit_len <= words[i].bit_len &&
-			words[i].bit_len < ret_bit_len) {
-			ret = i;
-			ret_bit_len = words[i].bit_len;
-		}
-	}
-
-	return ret;
-}
-
-static int flow_nic_set_hasher_part_inline(struct flow_nic_dev *ndev, int hsh_idx,
-	struct hsh_words *words, uint32_t pe, uint32_t ofs,
-	int bit_len, bool toeplitz)
-{
-	int res = 0;
-
-	/* check if there is any free word, which can accommodate header part of given 'bit_len' */
-	enum hsh_words_id word = get_free_word(words, bit_len);
-
-	if (word == HSH_WORDS_SIZE) {
-		NT_LOG(ERR, FILTER, "Cannot add additional %d bits into hash", bit_len);
-		return -1;
-	}
-
-	words[word].free = false;
-
-	res |= hw_mod_hsh_rcp_set(&ndev->be, words[word].pe, hsh_idx, 0, pe);
-	NT_LOG(DBG, FILTER, "hw_mod_hsh_rcp_set(&ndev->be, %d, %d, 0, %d)", words[word].pe,
-		hsh_idx, pe);
-	res |= hw_mod_hsh_rcp_set(&ndev->be, words[word].ofs, hsh_idx, 0, ofs);
-	NT_LOG(DBG, FILTER, "hw_mod_hsh_rcp_set(&ndev->be, %d, %d, 0, %d)", words[word].ofs,
-		hsh_idx, ofs);
-
-	/* set HW_HSH_RCP_WORD_MASK based on used QW/W and given 'bit_len' */
-	int mask_bit_len = bit_len;
-	uint32_t mask = 0x0;
-	uint32_t toeplitz_mask[9] = { 0x0 };
-	/* iterate through all words of QW */
-	uint16_t words_count = words[word].bit_len / 32;
-
-	for (uint16_t mask_off = 1; mask_off <= words_count; mask_off++) {
-		if (mask_bit_len >= 32) {
-			mask_bit_len -= 32;
-			mask = 0xffffffff;
-
-		} else if (mask_bit_len > 0) {
-			mask = 0xffffffff >> (32 - mask_bit_len) << (32 - mask_bit_len);
-			mask_bit_len = 0;
-
-		} else {
-			mask = 0x0;
-		}
-
-		/* reorder QW words mask from little to big endian */
-		res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, hsh_idx,
-			words[word].index + words_count - mask_off, mask);
-		NT_LOG_DBGX(DBG, FILTER,
-			"hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_WORD_MASK, %d, %d, 0x%08" PRIX32
-			")",
-			hsh_idx, words[word].index + words_count - mask_off, mask);
-		toeplitz_mask[words[word].index + mask_off - 1] = mask;
-	}
-
-	if (toeplitz) {
-		NT_LOG(DBG, FILTER,
-			"Partial Toeplitz RSS key mask: %08" PRIX32 " %08" PRIX32 " %08" PRIX32
-			" %08" PRIX32 " %08" PRIX32 " %08" PRIX32 " %08" PRIX32 " %08" PRIX32
-			" %08" PRIX32 "",
-			toeplitz_mask[0], toeplitz_mask[1], toeplitz_mask[2], toeplitz_mask[3],
-			toeplitz_mask[4], toeplitz_mask[5], toeplitz_mask[6], toeplitz_mask[7],
-			toeplitz_mask[8]);
-		NT_LOG(DBG, FILTER,
-			"                               MSB                                                                          LSB");
-	}
-
-	return res;
-}
-
 /*
  * Public functions
  */
@@ -3982,8 +3867,16 @@ int initialize_flow_management_of_ndev_profile_inline(struct flow_nic_dev *ndev)
 
 		flow_nic_mark_resource_used(ndev, RES_PDB_RCP, 0);
 
-		/* Set default hasher recipe to 5-tuple */
-		flow_nic_set_hasher(ndev, 0, HASH_ALGO_5TUPLE);
+		/* Set default hasher recipe to 5-tuple:
+		 * RTE_ETH_RSS_IPV6 - enables hashing on both IPv4/IPv6 SA and DA
+		 * RTE_ETH_RSS_PORT - enables hashing on both L4 SP and DP and L4 protocol type
+		 */
+		struct nt_eth_rss_conf hsh_5_tuple = {
+			.rss_key = {},
+			.rss_hf = RTE_ETH_RSS_IPV6 | RTE_ETH_RSS_PORT,
+			.algorithm = 0,
+		};
+		hsh_set(ndev, 0, hsh_5_tuple);
 		hw_mod_hsh_rcp_flush(&ndev->be, 0, 1);
 
 		flow_nic_mark_resource_used(ndev, RES_HSH_RCP, 0);
@@ -4580,658 +4473,6 @@ int flow_actions_update_profile_inline(struct flow_eth_dev *dev,
 	return -1;
 }
 
-static __rte_always_inline bool all_bits_enabled(uint64_t hash_mask, uint64_t hash_bits)
-{
-	return (hash_mask & hash_bits) == hash_bits;
-}
-
-static __rte_always_inline void unset_bits(uint64_t *hash_mask, uint64_t hash_bits)
-{
-	*hash_mask &= ~hash_bits;
-}
-
-static __rte_always_inline void unset_bits_and_log(uint64_t *hash_mask, uint64_t hash_bits)
-{
-	char rss_buffer[4096];
-	uint16_t rss_buffer_len = sizeof(rss_buffer);
-
-	if (sprint_nt_rss_mask(rss_buffer, rss_buffer_len, " ", *hash_mask & hash_bits) == 0)
-		NT_LOG(DBG, FILTER, "Configured RSS types:%s", rss_buffer);
-
-	unset_bits(hash_mask, hash_bits);
-}
-
-static __rte_always_inline void unset_bits_if_all_enabled(uint64_t *hash_mask, uint64_t hash_bits)
-{
-	if (all_bits_enabled(*hash_mask, hash_bits))
-		unset_bits(hash_mask, hash_bits);
-}
-
-int flow_nic_set_hasher_fields_inline(struct flow_nic_dev *ndev, int hsh_idx,
-	struct nt_eth_rss_conf rss_conf)
-{
-	uint64_t fields = rss_conf.rss_hf;
-
-	char rss_buffer[4096];
-	uint16_t rss_buffer_len = sizeof(rss_buffer);
-
-	if (sprint_nt_rss_mask(rss_buffer, rss_buffer_len, " ", fields) == 0)
-		NT_LOG(DBG, FILTER, "Requested RSS types:%s", rss_buffer);
-
-	/*
-	 * configure all (Q)Words usable for hash calculation
-	 * Hash can be calculated from 4 independent header parts:
-	 *      | QW0           | Qw4           | W8| W9|
-	 * word | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
-	 */
-	struct hsh_words words[HSH_WORDS_SIZE] = {
-		{ 0, HW_HSH_RCP_QW0_PE, HW_HSH_RCP_QW0_OFS, 128, true },
-		{ 4, HW_HSH_RCP_QW4_PE, HW_HSH_RCP_QW4_OFS, 128, true },
-		{ 8, HW_HSH_RCP_W8_PE, HW_HSH_RCP_W8_OFS, 32, true },
-		{
-			9, HW_HSH_RCP_W9_PE, HW_HSH_RCP_W9_OFS, 32,
-			true
-		},	/* not supported for Toeplitz */
-	};
-
-	int res = 0;
-	res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_PRESET_ALL, hsh_idx, 0, 0);
-	/* enable hashing */
-	res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_LOAD_DIST_TYPE, hsh_idx, 0, 2);
-
-	/* configure selected hash function and its key */
-	bool toeplitz = false;
-
-	switch (rss_conf.algorithm) {
-	case RTE_ETH_HASH_FUNCTION_DEFAULT:
-		/* Use default NTH10 hashing algorithm */
-		res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_TOEPLITZ, hsh_idx, 0, 0);
-		/* Use 1st 32-bits from rss_key to configure NTH10 SEED */
-		res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_SEED, hsh_idx, 0,
-			rss_conf.rss_key[0] << 24 | rss_conf.rss_key[1] << 16 |
-			rss_conf.rss_key[2] << 8 | rss_conf.rss_key[3]);
-		break;
-
-	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
-		toeplitz = true;
-		res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_TOEPLITZ, hsh_idx, 0, 1);
-		uint8_t empty_key = 0;
-
-		/* Toeplitz key (always 40B) words have to be programmed in reverse order */
-		for (uint8_t i = 0; i <= (MAX_RSS_KEY_LEN - 4); i += 4) {
-			res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_K, hsh_idx, 9 - i / 4,
-					rss_conf.rss_key[i] << 24 |
-					rss_conf.rss_key[i + 1] << 16 |
-					rss_conf.rss_key[i + 2] << 8 |
-					rss_conf.rss_key[i + 3]);
-			NT_LOG_DBG(DBG, FILTER,
-				"hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_K, %d, %d, 0x%" PRIX32
-				")",
-				hsh_idx, 9 - i / 4,
-				rss_conf.rss_key[i] << 24 | rss_conf.rss_key[i + 1] << 16 |
-				rss_conf.rss_key[i + 2] << 8 | rss_conf.rss_key[i + 3]);
-			empty_key |= rss_conf.rss_key[i] | rss_conf.rss_key[i + 1] |
-				rss_conf.rss_key[i + 2] | rss_conf.rss_key[i + 3];
-		}
-
-		if (empty_key == 0) {
-			NT_LOG(ERR, FILTER,
-				"Toeplitz key must be configured. Key with all bytes set to zero is not allowed.");
-			return -1;
-		}
-
-		words[HSH_WORDS_W9].free = false;
-		NT_LOG(DBG, FILTER,
-			"Toeplitz hashing is enabled thus W9 and P_MASK cannot be used.");
-		break;
-
-	default:
-		NT_LOG(ERR, FILTER, "Unknown hashing function %d requested", rss_conf.algorithm);
-		return -1;
-	}
-
-	/* indication that some IPv6 flag is present */
-	bool ipv6 = fields & (NT_ETH_RSS_IPV6_MASK);
-	/* store proto mask for later use at IP and L4 checksum handling */
-	uint64_t l4_proto_mask = fields &
-		(RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV4_UDP |
-		RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV4_OTHER |
-		RTE_ETH_RSS_NONFRAG_IPV6_TCP | RTE_ETH_RSS_NONFRAG_IPV6_UDP |
-		RTE_ETH_RSS_NONFRAG_IPV6_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_OTHER |
-		RTE_ETH_RSS_IPV6_TCP_EX | RTE_ETH_RSS_IPV6_UDP_EX);
-
-	/* outermost headers are used by default, so innermost bit takes precedence if detected */
-	bool outer = (fields & RTE_ETH_RSS_LEVEL_INNERMOST) ? false : true;
-	unset_bits(&fields, RTE_ETH_RSS_LEVEL_MASK);
-
-	if (fields == 0) {
-		NT_LOG(ERR, FILTER, "RSS hash configuration 0x%" PRIX64 " is not valid.",
-			rss_conf.rss_hf);
-		return -1;
-	}
-
-	/* indication that IPv4 `protocol` or IPv6 `next header` fields shall be part of the hash
-	 */
-	bool l4_proto_hash = false;
-
-	/*
-	 * check if SRC_ONLY & DST_ONLY are used simultaneously;
-	 * According to DPDK, we shall behave like none of these bits is set
-	 */
-	unset_bits_if_all_enabled(&fields, RTE_ETH_RSS_L2_SRC_ONLY | RTE_ETH_RSS_L2_DST_ONLY);
-	unset_bits_if_all_enabled(&fields, RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY);
-	unset_bits_if_all_enabled(&fields, RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY);
-
-	/* L2 */
-	if (fields & (RTE_ETH_RSS_ETH | RTE_ETH_RSS_L2_SRC_ONLY | RTE_ETH_RSS_L2_DST_ONLY)) {
-		if (outer) {
-			if (fields & RTE_ETH_RSS_L2_SRC_ONLY) {
-				NT_LOG(DBG, FILTER, "Set outer src MAC hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_L2, 6, 48, toeplitz);
-
-			} else if (fields & RTE_ETH_RSS_L2_DST_ONLY) {
-				NT_LOG(DBG, FILTER, "Set outer dst MAC hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_L2, 0, 48, toeplitz);
-
-			} else {
-				NT_LOG(DBG, FILTER, "Set outer src & dst MAC hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_L2, 0, 96, toeplitz);
-			}
-
-		} else if (fields & RTE_ETH_RSS_L2_SRC_ONLY) {
-			NT_LOG(DBG, FILTER, "Set inner src MAC hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_L2, 6,
-				48, toeplitz);
-
-		} else if (fields & RTE_ETH_RSS_L2_DST_ONLY) {
-			NT_LOG(DBG, FILTER, "Set inner dst MAC hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_L2, 0,
-				48, toeplitz);
-
-		} else {
-			NT_LOG(DBG, FILTER, "Set inner src & dst MAC hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_L2, 0,
-				96, toeplitz);
-		}
-
-		unset_bits_and_log(&fields,
-			RTE_ETH_RSS_ETH | RTE_ETH_RSS_L2_SRC_ONLY |
-			RTE_ETH_RSS_L2_DST_ONLY);
-	}
-
-	/*
-	 * VLAN support of multiple VLAN headers,
-	 * where S-VLAN is the first and C-VLAN the last VLAN header
-	 */
-	if (fields & RTE_ETH_RSS_C_VLAN) {
-		/*
-		 * use MPLS protocol offset, which points just after ethertype with relative
-		 * offset -6 (i.e. 2 bytes
-		 * of ethertype & size + 4 bytes of VLAN header field) to access last vlan header
-		 */
-		if (outer) {
-			NT_LOG(DBG, FILTER, "Set outer C-VLAN hasher.");
-			/*
-			 * use whole 32-bit 802.1a tag - backward compatible
-			 * with VSWITCH implementation
-			 */
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_MPLS, -6,
-				32, toeplitz);
-
-		} else {
-			NT_LOG(DBG, FILTER, "Set inner C-VLAN hasher.");
-			/*
-			 * use whole 32-bit 802.1a tag - backward compatible
-			 * with VSWITCH implementation
-			 */
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_MPLS,
-				-6, 32, toeplitz);
-		}
-
-		unset_bits_and_log(&fields, RTE_ETH_RSS_C_VLAN);
-	}
-
-	if (fields & RTE_ETH_RSS_S_VLAN) {
-		if (outer) {
-			NT_LOG(DBG, FILTER, "Set outer S-VLAN hasher.");
-			/*
-			 * use whole 32-bit 802.1a tag - backward compatible
-			 * with VSWITCH implementation
-			 */
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-				DYN_FIRST_VLAN, 0, 32, toeplitz);
-
-		} else {
-			NT_LOG(DBG, FILTER, "Set inner S-VLAN hasher.");
-			/*
-			 * use whole 32-bit 802.1a tag - backward compatible
-			 * with VSWITCH implementation
-			 */
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_VLAN,
-				0, 32, toeplitz);
-		}
-
-		unset_bits_and_log(&fields, RTE_ETH_RSS_S_VLAN);
-	}
-	/* L2 payload */
-	/* calculate hash of 128-bits of l2 payload; Use MPLS protocol offset to address the
-	 * beginning of L2 payload even if MPLS header is not present
-	 */
-	if (fields & RTE_ETH_RSS_L2_PAYLOAD) {
-		uint64_t outer_fields_enabled = 0;
-
-		if (outer) {
-			NT_LOG(DBG, FILTER, "Set outer L2 payload hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_MPLS, 0,
-				128, toeplitz);
-
-		} else {
-			NT_LOG(DBG, FILTER, "Set inner L2 payload hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_MPLS,
-				0, 128, toeplitz);
-			outer_fields_enabled = fields & RTE_ETH_RSS_GTPU;
-		}
-
-		/*
-		 * L2 PAYLOAD hashing overrides all L3 & L4 RSS flags.
-		 * Thus we can clear all remaining (supported)
-		 * RSS flags...
-		 */
-		unset_bits_and_log(&fields, NT_ETH_RSS_OFFLOAD_MASK);
-		/*
-		 * ...but in case of INNER L2 PAYLOAD we must process
-		 * "always outer" GTPU field if enabled
-		 */
-		fields |= outer_fields_enabled;
-	}
-
-	/* L3 + L4 protocol number */
-	if (fields & RTE_ETH_RSS_IPV4_CHKSUM) {
-		/* only IPv4 checksum is supported by DPDK RTE_ETH_RSS_* types */
-		if (ipv6) {
-			NT_LOG(ERR, FILTER,
-				"RSS: IPv4 checksum requested with IPv6 header hashing!");
-			res = 1;
-
-		} else if (outer) {
-			NT_LOG(DBG, FILTER, "Set outer IPv4 checksum hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_L3, 10,
-				16, toeplitz);
-
-		} else {
-			NT_LOG(DBG, FILTER, "Set inner IPv4 checksum hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_L3,
-				10, 16, toeplitz);
-		}
-
-		/*
-		 * L3 checksum is made from whole L3 header, i.e. no need to process other
-		 * L3 hashing flags
-		 */
-		unset_bits_and_log(&fields, RTE_ETH_RSS_IPV4_CHKSUM | NT_ETH_RSS_IP_MASK);
-	}
-
-	if (fields & NT_ETH_RSS_IP_MASK) {
-		if (ipv6) {
-			if (outer) {
-				if (fields & RTE_ETH_RSS_L3_SRC_ONLY) {
-					NT_LOG(DBG, FILTER, "Set outer IPv6/IPv4 src hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words,
-						DYN_FINAL_IP_DST,
-						-16, 128, toeplitz);
-
-				} else if (fields & RTE_ETH_RSS_L3_DST_ONLY) {
-					NT_LOG(DBG, FILTER, "Set outer IPv6/IPv4 dst hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words,
-						DYN_FINAL_IP_DST, 0,
-						128, toeplitz);
-
-				} else {
-					NT_LOG(DBG, FILTER,
-						"Set outer IPv6/IPv4 src & dst hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words,
-						DYN_FINAL_IP_DST,
-						-16, 128, toeplitz);
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words,
-						DYN_FINAL_IP_DST, 0,
-						128, toeplitz);
-				}
-
-			} else if (fields & RTE_ETH_RSS_L3_SRC_ONLY) {
-				NT_LOG(DBG, FILTER, "Set inner IPv6/IPv4 src hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_FINAL_IP_DST, -16,
-					128, toeplitz);
-
-			} else if (fields & RTE_ETH_RSS_L3_DST_ONLY) {
-				NT_LOG(DBG, FILTER, "Set inner IPv6/IPv4 dst hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_FINAL_IP_DST, 0,
-					128, toeplitz);
-
-			} else {
-				NT_LOG(DBG, FILTER, "Set inner IPv6/IPv4 src & dst hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_FINAL_IP_DST, -16,
-					128, toeplitz);
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_FINAL_IP_DST, 0,
-					128, toeplitz);
-			}
-
-			/* check if fragment ID shall be part of hash */
-			if (fields & (RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_FRAG_IPV6)) {
-				if (outer) {
-					NT_LOG(DBG, FILTER,
-						"Set outer IPv6/IPv4 fragment ID hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words,
-						DYN_ID_IPV4_6, 0,
-						32, toeplitz);
-
-				} else {
-					NT_LOG(DBG, FILTER,
-						"Set inner IPv6/IPv4 fragment ID hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words,
-						DYN_TUN_ID_IPV4_6,
-						0, 32, toeplitz);
-				}
-			}
-
-			res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_AUTO_IPV4_MASK, hsh_idx, 0,
-				1);
-
-		} else {
-			/* IPv4 */
-			if (outer) {
-				if (fields & RTE_ETH_RSS_L3_SRC_ONLY) {
-					NT_LOG(DBG, FILTER, "Set outer IPv4 src only hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words, DYN_L3, 12,
-						32, toeplitz);
-
-				} else if (fields & RTE_ETH_RSS_L3_DST_ONLY) {
-					NT_LOG(DBG, FILTER, "Set outer IPv4 dst only hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words, DYN_L3, 16,
-						32, toeplitz);
-
-				} else {
-					NT_LOG(DBG, FILTER, "Set outer IPv4 src & dst hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words, DYN_L3, 12,
-						64, toeplitz);
-				}
-
-			} else if (fields & RTE_ETH_RSS_L3_SRC_ONLY) {
-				NT_LOG(DBG, FILTER, "Set inner IPv4 src only hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_L3, 12, 32,
-					toeplitz);
-
-			} else if (fields & RTE_ETH_RSS_L3_DST_ONLY) {
-				NT_LOG(DBG, FILTER, "Set inner IPv4 dst only hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_L3, 16, 32,
-					toeplitz);
-
-			} else {
-				NT_LOG(DBG, FILTER, "Set inner IPv4 src & dst hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_L3, 12, 64,
-					toeplitz);
-			}
-
-			/* check if fragment ID shall be part of hash */
-			if (fields & RTE_ETH_RSS_FRAG_IPV4) {
-				if (outer) {
-					NT_LOG(DBG, FILTER,
-						"Set outer IPv4 fragment ID hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words,
-						DYN_ID_IPV4_6, 0,
-						16, toeplitz);
-
-				} else {
-					NT_LOG(DBG, FILTER,
-						"Set inner IPv4 fragment ID hasher.");
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words,
-						DYN_TUN_ID_IPV4_6,
-						0, 16, toeplitz);
-				}
-			}
-		}
-
-		/* check if L4 protocol type shall be part of hash */
-		if (l4_proto_mask)
-			l4_proto_hash = true;
-
-		unset_bits_and_log(&fields, NT_ETH_RSS_IP_MASK);
-	}
-
-	/* L4 */
-	if (fields & (RTE_ETH_RSS_PORT | RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY)) {
-		if (outer) {
-			if (fields & RTE_ETH_RSS_L4_SRC_ONLY) {
-				NT_LOG(DBG, FILTER, "Set outer L4 src hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_L4, 0, 16, toeplitz);
-
-			} else if (fields & RTE_ETH_RSS_L4_DST_ONLY) {
-				NT_LOG(DBG, FILTER, "Set outer L4 dst hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_L4, 2, 16, toeplitz);
-
-			} else {
-				NT_LOG(DBG, FILTER, "Set outer L4 src & dst hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_L4, 0, 32, toeplitz);
-			}
-
-		} else if (fields & RTE_ETH_RSS_L4_SRC_ONLY) {
-			NT_LOG(DBG, FILTER, "Set inner L4 src hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_L4, 0,
-				16, toeplitz);
-
-		} else if (fields & RTE_ETH_RSS_L4_DST_ONLY) {
-			NT_LOG(DBG, FILTER, "Set inner L4 dst hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_L4, 2,
-				16, toeplitz);
-
-		} else {
-			NT_LOG(DBG, FILTER, "Set inner L4 src & dst hasher.");
-			res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_TUN_L4, 0,
-				32, toeplitz);
-		}
-
-		l4_proto_hash = true;
-		unset_bits_and_log(&fields,
-			RTE_ETH_RSS_PORT | RTE_ETH_RSS_L4_SRC_ONLY |
-			RTE_ETH_RSS_L4_DST_ONLY);
-	}
-
-	/* IPv4 protocol / IPv6 next header fields */
-	if (l4_proto_hash) {
-		/* NOTE: HW_HSH_RCP_P_MASK is not supported for Toeplitz and thus one of SW0, SW4
-		 * or W8 must be used to hash on `protocol` field of IPv4 or `next header` field of
-		 * IPv6 header.
-		 */
-		if (outer) {
-			NT_LOG(DBG, FILTER, "Set outer L4 protocol type / next header hasher.");
-
-			if (toeplitz) {
-				if (ipv6) {
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words, DYN_L3, 6, 8,
-						toeplitz);
-
-				} else {
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words, DYN_L3, 9, 8,
-						toeplitz);
-				}
-
-			} else {
-				res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_P_MASK, hsh_idx, 0,
-					1);
-				res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_TNL_P, hsh_idx, 0,
-					0);
-			}
-
-		} else {
-			NT_LOG(DBG, FILTER, "Set inner L4 protocol type / next header hasher.");
-
-			if (toeplitz) {
-				if (ipv6) {
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words, DYN_TUN_L3,
-						6, 8, toeplitz);
-
-				} else {
-					res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx,
-						words, DYN_TUN_L3,
-						9, 8, toeplitz);
-				}
-
-			} else {
-				res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_P_MASK, hsh_idx, 0,
-					1);
-				res |= hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_TNL_P, hsh_idx, 0,
-					1);
-			}
-		}
-
-		l4_proto_hash = false;
-	}
-
-	/*
-	 * GTPU - for UPF use cases we always use TEID from outermost GTPU header
-	 * even if other headers are innermost
-	 */
-	if (fields & RTE_ETH_RSS_GTPU) {
-		NT_LOG(DBG, FILTER, "Set outer GTPU TEID hasher.");
-		res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words, DYN_L4_PAYLOAD, 4, 32,
-			toeplitz);
-		unset_bits_and_log(&fields, RTE_ETH_RSS_GTPU);
-	}
-
-	/* Checksums */
-	/* only UDP, TCP and SCTP checksums are supported */
-	if (fields & RTE_ETH_RSS_L4_CHKSUM) {
-		switch (l4_proto_mask) {
-		case RTE_ETH_RSS_NONFRAG_IPV4_UDP:
-		case RTE_ETH_RSS_NONFRAG_IPV6_UDP:
-		case RTE_ETH_RSS_IPV6_UDP_EX:
-		case RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_NONFRAG_IPV6_UDP:
-		case RTE_ETH_RSS_NONFRAG_IPV4_UDP | RTE_ETH_RSS_IPV6_UDP_EX:
-		case RTE_ETH_RSS_NONFRAG_IPV6_UDP | RTE_ETH_RSS_IPV6_UDP_EX:
-		case RTE_ETH_RSS_UDP_COMBINED:
-			if (outer) {
-				NT_LOG(DBG, FILTER, "Set outer UDP checksum hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_L4, 6, 16, toeplitz);
-
-			} else {
-				NT_LOG(DBG, FILTER, "Set inner UDP checksum hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_L4, 6, 16,
-					toeplitz);
-			}
-
-			unset_bits_and_log(&fields, RTE_ETH_RSS_L4_CHKSUM | l4_proto_mask);
-			break;
-
-		case RTE_ETH_RSS_NONFRAG_IPV4_TCP:
-		case RTE_ETH_RSS_NONFRAG_IPV6_TCP:
-		case RTE_ETH_RSS_IPV6_TCP_EX:
-		case RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV6_TCP:
-		case RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_IPV6_TCP_EX:
-		case RTE_ETH_RSS_NONFRAG_IPV6_TCP | RTE_ETH_RSS_IPV6_TCP_EX:
-		case RTE_ETH_RSS_TCP_COMBINED:
-			if (outer) {
-				NT_LOG(DBG, FILTER, "Set outer TCP checksum hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_L4, 16, 16, toeplitz);
-
-			} else {
-				NT_LOG(DBG, FILTER, "Set inner TCP checksum hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_L4, 16, 16,
-					toeplitz);
-			}
-
-			unset_bits_and_log(&fields, RTE_ETH_RSS_L4_CHKSUM | l4_proto_mask);
-			break;
-
-		case RTE_ETH_RSS_NONFRAG_IPV4_SCTP:
-		case RTE_ETH_RSS_NONFRAG_IPV6_SCTP:
-		case RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_SCTP:
-			if (outer) {
-				NT_LOG(DBG, FILTER, "Set outer SCTP checksum hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_L4, 8, 32, toeplitz);
-
-			} else {
-				NT_LOG(DBG, FILTER, "Set inner SCTP checksum hasher.");
-				res |= flow_nic_set_hasher_part_inline(ndev, hsh_idx, words,
-					DYN_TUN_L4, 8, 32,
-					toeplitz);
-			}
-
-			unset_bits_and_log(&fields, RTE_ETH_RSS_L4_CHKSUM | l4_proto_mask);
-			break;
-
-		case RTE_ETH_RSS_NONFRAG_IPV4_OTHER:
-		case RTE_ETH_RSS_NONFRAG_IPV6_OTHER:
-
-		/* none or unsupported protocol was chosen */
-		case 0:
-			NT_LOG(ERR, FILTER,
-				"L4 checksum hashing is supported only for UDP, TCP and SCTP protocols");
-			res = -1;
-			break;
-
-		/* multiple L4 protocols were selected */
-		default:
-			NT_LOG(ERR, FILTER,
-				"L4 checksum hashing can be enabled just for one of UDP, TCP or SCTP protocols");
-			res = -1;
-			break;
-		}
-	}
-
-	if (fields || res != 0) {
-		hw_mod_hsh_rcp_set(&ndev->be, HW_HSH_RCP_PRESET_ALL, hsh_idx, 0, 0);
-
-		if (sprint_nt_rss_mask(rss_buffer, rss_buffer_len, " ", rss_conf.rss_hf) == 0) {
-			NT_LOG(ERR, FILTER,
-				"RSS configuration%s is not supported for hash func %s.",
-				rss_buffer,
-				(enum rte_eth_hash_function)toeplitz ? "Toeplitz" : "NTH10");
-
-		} else {
-			NT_LOG(ERR, FILTER,
-				"RSS configuration 0x%" PRIX64
-				" is not supported for hash func %s.",
-				rss_conf.rss_hf,
-				(enum rte_eth_hash_function)toeplitz ? "Toeplitz" : "NTH10");
-		}
-
-		return -1;
-	}
-
-	return res;
-}
-
 static void dump_flm_data(const uint32_t *data, FILE *file)
 {
 	for (unsigned int i = 0; i < 10; ++i) {
@@ -6020,7 +5261,6 @@ static const struct profile_inline_ops ops = {
 	.flow_destroy_profile_inline = flow_destroy_profile_inline,
 	.flow_flush_profile_inline = flow_flush_profile_inline,
 	.flow_actions_update_profile_inline = flow_actions_update_profile_inline,
-	.flow_nic_set_hasher_fields_inline = flow_nic_set_hasher_fields_inline,
 	.flow_get_aged_flows_profile_inline = flow_get_aged_flows_profile_inline,
 	/*
 	 * Stats
diff --git a/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_profile_inline.h b/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_profile_inline.h
index 169f71ee68..be22c9bcd1 100644
--- a/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_profile_inline.h
+++ b/drivers/net/ntnic/nthw/flow_api/profile_inline/flow_api_profile_inline.h
@@ -66,10 +66,6 @@ int flow_get_aged_flows_profile_inline(struct flow_eth_dev *dev,
 	uint32_t nb_contexts,
 	struct rte_flow_error *error);
 
-int flow_nic_set_hasher_fields_inline(struct flow_nic_dev *ndev,
-	int hsh_idx,
-	struct nt_eth_rss_conf rss_conf);
-
 /*
  * Stats
  */
diff --git a/drivers/net/ntnic/ntnic_ethdev.c b/drivers/net/ntnic/ntnic_ethdev.c
index d1360cc925..9000264804 100644
--- a/drivers/net/ntnic/ntnic_ethdev.c
+++ b/drivers/net/ntnic/ntnic_ethdev.c
@@ -27,6 +27,7 @@
 #include "ntnic_vfio.h"
 #include "ntnic_mod_reg.h"
 #include "nt_util.h"
+#include "flow_hsh_cfg.h"
 #include "profile_inline/flm_age_queue.h"
 #include "profile_inline/flm_evt_queue.h"
 #include "rte_pmd_ntnic.h"
@@ -1672,7 +1673,7 @@ static int eth_dev_rss_hash_update(struct rte_eth_dev *eth_dev, struct rte_eth_r
 	tmp_rss_conf.algorithm = rss_conf->algorithm;
 
 	tmp_rss_conf.rss_hf = rss_conf->rss_hf;
-	int res = flow_filter_ops->flow_nic_set_hasher_fields(ndev, hsh_idx, tmp_rss_conf);
+	int res = hsh_set(ndev, hsh_idx, tmp_rss_conf);
 
 	if (res == 0) {
 		flow_filter_ops->hw_mod_hsh_rcp_flush(&ndev->be, hsh_idx, 1);
diff --git a/drivers/net/ntnic/ntnic_mod_reg.h b/drivers/net/ntnic/ntnic_mod_reg.h
index 71861c6dea..8db4911262 100644
--- a/drivers/net/ntnic/ntnic_mod_reg.h
+++ b/drivers/net/ntnic/ntnic_mod_reg.h
@@ -355,10 +355,6 @@ struct profile_inline_ops {
 		struct flow_handle *flow, void *user_data,
 		struct rte_flow_error *error);
 
-	int (*flow_nic_set_hasher_fields_inline)(struct flow_nic_dev *ndev,
-		int hsh_idx,
-		struct nt_eth_rss_conf rss_conf);
-
 	/*
 	 * Stats
 	 */
@@ -467,8 +463,6 @@ struct flow_filter_ops {
 	/*
 	 * Other
 	 */
-	int (*flow_nic_set_hasher_fields)(struct flow_nic_dev *ndev, int hsh_idx,
-		struct nt_eth_rss_conf rss_conf);
 	int (*hw_mod_hsh_rcp_flush)(struct flow_api_backend_s *be, int start_idx, int count);
 
 	int (*flow_get_aged_flows)(struct flow_eth_dev *dev,
-- 
2.45.0


  parent reply	other threads:[~2025-01-21 17:11 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-21 17:07 [PATCH v1 00/31] net/ntnic: bugfixes and refactoring Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 01/31] net/ntnic: fix index verification Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 02/31] net/ntnic: add thread check return code Serhii Iliushyk
2025-01-21 18:24   ` Stephen Hemminger
2025-01-21 17:07 ` [PATCH v1 03/31] net/ntnic: add return code handling Serhii Iliushyk
2025-01-21 18:30   ` Stephen Hemminger
2025-01-21 17:07 ` [PATCH v1 04/31] net/ntnic: add array index verification Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 05/31] net/ntnic: fix realloc memory leak Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 06/31] net/ntnic: fix array index verification Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 07/31] net/ntnic: add var definition transparently Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 08/31] net/ntnic: add proper var freed Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 09/31] net/ntnic: remove deadcode Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 10/31] net/ntnic: fix potentially overflow Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 11/31] net/ntnic: add null checking Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 12/31] net/ntnic: fix overflow issue Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 13/31] net/ntnic: fix untrusted loop bound Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 14/31] net/ntnic: add null checking Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 15/31] net/ntnic: move " Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 16/31] net/ntnic: fix var size Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 17/31] net/ntnic: fix var overflow Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 18/31] net/ntnic: remove dead code Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 19/31] net/ntnic: remove convert error func Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 20/31] net/ntnic: fix array verification Serhii Iliushyk
2025-01-21 17:07 ` [PATCH v1 21/31] net/ntnic: fix memory leak Serhii Iliushyk
2025-01-21 17:08 ` [PATCH v1 22/31] net/ntnic: remove extra address-of operator Serhii Iliushyk
2025-01-21 17:08 ` [PATCH v1 23/31] net/ntnic: remove extra check for null Serhii Iliushyk
2025-01-21 17:08 ` [PATCH v1 24/31] net/ntnic: remove unused code Serhii Iliushyk
2025-01-21 17:08 ` Serhii Iliushyk [this message]
2025-01-21 17:08 ` [PATCH v1 26/31] net/ntnic: fix age timeout recalculation into fpga unit Serhii Iliushyk
2025-01-21 17:08 ` [PATCH v1 27/31] net/ntnic: rework age event generation Serhii Iliushyk
2025-01-21 17:08 ` [PATCH v1 28/31] net/ntnic: fix group print Serhii Iliushyk
2025-01-21 17:08 ` [PATCH v1 29/31] net/ntnic: extend module mapping Serhii Iliushyk
2025-01-21 17:08 ` [PATCH v1 30/31] net/ntnic: refactoring of the FPGA initialization Serhii Iliushyk
2025-01-21 17:08 ` [PATCH v1 31/31] net/ntnic: remove tag EXPERIMENTAL Serhii Iliushyk

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250121170814.3252171-26-sil-plv@napatech.com \
    --to=sil-plv@napatech.com \
    --cc=ckm@napatech.com \
    --cc=dev@dpdk.org \
    --cc=dvo-plv@napatech.com \
    --cc=mko-plv@napatech.com \
    --cc=stephen@networkplumber.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).