* [PATCH] lib/gro: use hash function for flow lookup
@ 2025-01-01 9:37 Kumara Parameshwaran
2025-01-01 17:21 ` Stephen Hemminger
0 siblings, 1 reply; 3+ messages in thread
From: Kumara Parameshwaran @ 2025-01-01 9:37 UTC (permalink / raw)
To: hujiayu.hu; +Cc: dev, Kumara Parameshwaran
optimize the GRO lookup using hash based
implementation
Signed-off-by: Kumara Parameshwaran <kumaraparamesh92@gmail.com>
---
The patch helps improving the CPU cycles during flow lookup in the GRO library.
The current approach iterates over all the flows in the GRO table to find a
matching flow for every incoming packet. The proposed patch uses Hash if the
incoming packet contains the RTE_MBUF_F_RX_RSS_HASH field in the rte_mbuf, if not
hash is computed based on the source and destination addresses and port. The
current implementation is simple XOR.
lib/gro/gro_tcp4.c | 131 ++++++++++++++++++++++++++-------------------
lib/gro/gro_tcp4.h | 4 ++
2 files changed, 79 insertions(+), 56 deletions(-)
diff --git a/lib/gro/gro_tcp4.c b/lib/gro/gro_tcp4.c
index 855cc7a71d..d2f0ecd931 100644
--- a/lib/gro/gro_tcp4.c
+++ b/lib/gro/gro_tcp4.c
@@ -57,6 +57,9 @@ gro_tcp4_tbl_create(uint16_t socket_id,
tbl->flows[i].start_index = INVALID_ARRAY_INDEX;
tbl->max_flow_num = entries_num;
+ for (i = 0; i < GRO_TCP4_HASH_BUCKET_SIZE; i++)
+ STAILQ_INIT(&tbl->collision_list[i]);
+
return tbl;
}
@@ -84,17 +87,18 @@ find_an_empty_flow(struct gro_tcp4_tbl *tbl)
return INVALID_ARRAY_INDEX;
}
-static inline uint32_t
+static inline int
insert_new_flow(struct gro_tcp4_tbl *tbl,
struct tcp4_flow_key *src,
- uint32_t item_idx)
+ uint32_t item_idx,
+ uint32_t flow_hash)
{
struct tcp4_flow_key *dst;
uint32_t flow_idx;
flow_idx = find_an_empty_flow(tbl);
if (unlikely(flow_idx == INVALID_ARRAY_INDEX))
- return INVALID_ARRAY_INDEX;
+ return -1;
dst = &(tbl->flows[flow_idx].key);
@@ -106,7 +110,28 @@ insert_new_flow(struct gro_tcp4_tbl *tbl,
tbl->flows[flow_idx].start_index = item_idx;
tbl->flow_num++;
- return flow_idx;
+ if (STAILQ_EMPTY(&tbl->collision_list[flow_hash]))
+ STAILQ_INSERT_HEAD(&tbl->collision_list[flow_hash],
+ &(tbl->flows[flow_idx]), next);
+ else
+ STAILQ_INSERT_TAIL(&tbl->collision_list[flow_hash],
+ &(tbl->flows[flow_idx]), next);
+ return 0;
+}
+
+static inline struct gro_tcp4_flow*
+gro_tcp4_flow_search(struct gro_tcp4_tbl *tbl,
+ struct tcp4_flow_key *key,
+ uint32_t flow_hash)
+{
+ struct gro_tcp4_flow *flow;
+
+ STAILQ_FOREACH(flow, &tbl->collision_list[flow_hash], next) {
+ if (memcmp(&(flow->key), key, sizeof(struct tcp4_flow_key)) == 0)
+ return flow;
+ }
+
+ return NULL;
}
int32_t
@@ -124,9 +149,8 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
struct tcp4_flow_key key;
uint32_t item_idx;
- uint32_t i, max_flow_num, remaining_flow_num;
- uint8_t find;
- uint32_t item_start_idx;
+ uint32_t flow_hash;
+ struct gro_tcp4_flow *flow;
/*
* Don't process the packet whose TCP header length is greater
@@ -173,22 +197,15 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
is_atomic = (frag_off & RTE_IPV4_HDR_DF_FLAG) == RTE_IPV4_HDR_DF_FLAG;
ip_id = is_atomic ? 0 : rte_be_to_cpu_16(ipv4_hdr->packet_id);
- /* Search for a matched flow. */
- max_flow_num = tbl->max_flow_num;
- remaining_flow_num = tbl->flow_num;
- find = 0;
- for (i = 0; i < max_flow_num && remaining_flow_num; i++) {
- if (tbl->flows[i].start_index != INVALID_ARRAY_INDEX) {
- if (is_same_tcp4_flow(tbl->flows[i].key, key)) {
- find = 1;
- item_start_idx = tbl->flows[i].start_index;
- break;
- }
- remaining_flow_num--;
- }
+ if (pkt->ol_flags & RTE_MBUF_F_RX_RSS_HASH) {
+ flow_hash = pkt->hash.rss % GRO_TCP4_HASH_BUCKET_SIZE;
+ } else {
+ flow_hash = ipv4_hdr->src_addr ^ ipv4_hdr->dst_addr ^
+ tcp_hdr->src_port ^ tcp_hdr->dst_port;
+ flow_hash = flow_hash % GRO_TCP4_HASH_BUCKET_SIZE;
}
-
- if (find == 1) {
+ flow = gro_tcp4_flow_search(tbl, &key, flow_hash);
+ if (flow != NULL) {
/*
* Any packet with additional flags like PSH,FIN should be processed
* and flushed immediately.
@@ -197,9 +214,9 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
*/
if (tcp_hdr->tcp_flags & (RTE_TCP_ACK_FLAG | RTE_TCP_PSH_FLAG | RTE_TCP_FIN_FLAG)) {
if (tcp_hdr->tcp_flags != RTE_TCP_ACK_FLAG)
- tbl->items[item_start_idx].start_time = 0;
+ tbl->items[flow->start_index].start_time = 0;
return process_tcp_item(pkt, tcp_hdr, tcp_dl, tbl->items,
- tbl->flows[i].start_index, &tbl->item_num,
+ flow->start_index, &tbl->item_num,
tbl->max_item_num, ip_id, is_atomic, start_time);
} else {
return -1;
@@ -217,8 +234,7 @@ gro_tcp4_reassemble(struct rte_mbuf *pkt,
is_atomic);
if (item_idx == INVALID_ARRAY_INDEX)
return -1;
- if (insert_new_flow(tbl, &key, item_idx) ==
- INVALID_ARRAY_INDEX) {
+ if (insert_new_flow(tbl, &key, item_idx, flow_hash) != 0) {
/*
* Fail to insert a new flow, so delete the
* stored packet.
@@ -255,36 +271,39 @@ gro_tcp4_tbl_timeout_flush(struct gro_tcp4_tbl *tbl,
{
uint16_t k = 0;
uint32_t i, j;
- uint32_t max_flow_num = tbl->max_flow_num;
-
- for (i = 0; i < max_flow_num; i++) {
- if (unlikely(tbl->flow_num == 0))
- return k;
-
- j = tbl->flows[i].start_index;
- while (j != INVALID_ARRAY_INDEX) {
- if (tbl->items[j].start_time <= flush_timestamp) {
- out[k++] = tbl->items[j].firstseg;
- if (tbl->items[j].nb_merged > 1)
- update_header(&(tbl->items[j]));
- /*
- * Delete the packet and get the next
- * packet in the flow.
- */
- j = delete_tcp_item(tbl->items, j,
- &tbl->item_num, INVALID_ARRAY_INDEX);
- tbl->flows[i].start_index = j;
- if (j == INVALID_ARRAY_INDEX)
- tbl->flow_num--;
-
- if (unlikely(k == nb_out))
- return k;
- } else
- /*
- * The left packets in this flow won't be
- * timeout. Go to check other flows.
- */
- break;
+ struct gro_tcp4_flow *flow;
+
+ for (i = 0; i < GRO_TCP4_HASH_BUCKET_SIZE; i++) {
+ STAILQ_FOREACH(flow, &tbl->collision_list[i], next) {
+ j = flow->start_index;
+ while (j != INVALID_ARRAY_INDEX) {
+ if (tbl->items[j].start_time <= flush_timestamp) {
+ out[k++] = tbl->items[j].firstseg;
+ if (tbl->items[j].nb_merged > 1)
+ update_header(&(tbl->items[j]));
+ /*
+ * Delete the packet and get the next
+ * packet in the flow.
+ */
+ j = delete_tcp_item(tbl->items, j,
+ &tbl->item_num,
+ INVALID_ARRAY_INDEX);
+ flow->start_index = j;
+ if (j == INVALID_ARRAY_INDEX) {
+ tbl->flow_num--;
+ STAILQ_REMOVE(&tbl->collision_list[i],
+ flow, gro_tcp4_flow, next);
+ }
+
+ if (unlikely(k == nb_out))
+ return k;
+ } else
+ /*
+ * The left packets in this flow won't be
+ * timeout. Go to check other flows.
+ */
+ break;
+ }
}
}
return k;
diff --git a/lib/gro/gro_tcp4.h b/lib/gro/gro_tcp4.h
index 245e5da486..077fe08e41 100644
--- a/lib/gro/gro_tcp4.h
+++ b/lib/gro/gro_tcp4.h
@@ -8,6 +8,7 @@
#include "gro_tcp.h"
#define GRO_TCP4_TBL_MAX_ITEM_NUM (1024UL * 1024UL)
+#define GRO_TCP4_HASH_BUCKET_SIZE 32
/* Header fields representing common fields in TCP flow */
struct tcp4_flow_key {
@@ -23,6 +24,7 @@ struct gro_tcp4_flow {
* INVALID_ARRAY_INDEX indicates an empty flow.
*/
uint32_t start_index;
+ STAILQ_ENTRY(gro_tcp4_flow) next;
};
/*
@@ -33,6 +35,8 @@ struct gro_tcp4_tbl {
struct gro_tcp_item *items;
/* flow array */
struct gro_tcp4_flow *flows;
+ /* Collision list for the flows following the same hash */
+ STAILQ_HEAD(, gro_tcp4_flow) collision_list[GRO_TCP4_HASH_BUCKET_SIZE];
/* current item number */
uint32_t item_num;
/* current flow num */
--
2.45.1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] lib/gro: use hash function for flow lookup
2025-01-01 9:37 [PATCH] lib/gro: use hash function for flow lookup Kumara Parameshwaran
@ 2025-01-01 17:21 ` Stephen Hemminger
2025-01-02 3:53 ` kumaraparameshwaran rathinavel
0 siblings, 1 reply; 3+ messages in thread
From: Stephen Hemminger @ 2025-01-01 17:21 UTC (permalink / raw)
To: Kumara Parameshwaran; +Cc: hujiayu.hu, dev
On Wed, 1 Jan 2025 15:07:35 +0530
Kumara Parameshwaran <kumaraparamesh92@gmail.com> wrote:
> From: Kumara Parameshwaran <kumaraparamesh92@gmail.com>
> To: hujiayu.hu@foxmail.com
> Cc: dev@dpdk.org, Kumara Parameshwaran <kumaraparamesh92@gmail.com>
> Subject: [PATCH] lib/gro: use hash function for flow lookup
> Date: Wed, 1 Jan 2025 15:07:35 +0530
> X-Mailer: git-send-email 2.47.1
>
> optimize the GRO lookup using hash based
> implementation
>
> Signed-off-by: Kumara Parameshwaran <kumaraparamesh92@gmail.com>
Rather than open coding a hash table with collision chains, please use the
existing DPDK cuckoo hash which is faster and you can also prevent hash
DoS chain attacks.
Alternatively, use a better hash function such as siphash which is resistent
to DoS attacks.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] lib/gro: use hash function for flow lookup
2025-01-01 17:21 ` Stephen Hemminger
@ 2025-01-02 3:53 ` kumaraparameshwaran rathinavel
0 siblings, 0 replies; 3+ messages in thread
From: kumaraparameshwaran rathinavel @ 2025-01-02 3:53 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: hujiayu.hu, dev
[-- Attachment #1: Type: text/plain, Size: 1171 bytes --]
On Wed, Jan 1, 2025 at 10:51 PM Stephen Hemminger <
stephen@networkplumber.org> wrote:
> On Wed, 1 Jan 2025 15:07:35 +0530
> Kumara Parameshwaran <kumaraparamesh92@gmail.com> wrote:
>
> > From: Kumara Parameshwaran <kumaraparamesh92@gmail.com>
> > To: hujiayu.hu@foxmail.com
> > Cc: dev@dpdk.org, Kumara Parameshwaran <kumaraparamesh92@gmail.com>
> > Subject: [PATCH] lib/gro: use hash function for flow lookup
> > Date: Wed, 1 Jan 2025 15:07:35 +0530
> > X-Mailer: git-send-email 2.47.1
> >
> > optimize the GRO lookup using hash based
> > implementation
> >
> > Signed-off-by: Kumara Parameshwaran <kumaraparamesh92@gmail.com>
>
> Rather than open coding a hash table with collision chains, please use the
> existing DPDK cuckoo hash which is faster and you can also prevent hash
> DoS chain attacks.
> >>Sure, I was thinking to use cuckoo hash, but then thought if this could
> be an overkill to for this implementation.
> Alternatively, use a better hash function such as siphash which is
> resistent
> to DoS attacks.
>> Yes, sure. Will change it. Had used that to get an idea for the
overall implementation itself.
>
[-- Attachment #2: Type: text/html, Size: 2338 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-01-02 3:53 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-01-01 9:37 [PATCH] lib/gro: use hash function for flow lookup Kumara Parameshwaran
2025-01-01 17:21 ` Stephen Hemminger
2025-01-02 3:53 ` kumaraparameshwaran rathinavel
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).