Acked-by: Nithin Dabilpuram <ndabilpu...@marvell.com>
On Thu, Jul 27, 2023 at 8:07 PM <pbhagavat...@marvell.com> wrote: > > From: Pavan Nikhilesh <pbhagavat...@marvell.com> > > Add IPv4 reassembly node. > > Signed-off-by: Pavan Nikhilesh <pbhagavat...@marvell.com> > --- > v4 Changes: > - Add packet drop node as the 0th edge. > - Free deathrow packets to packet drop node. > v3 Changes: > - Actually include the changes that fix compilation. > v2 Changes: > - Fix compilation. > > doc/guides/prog_guide/graph_lib.rst | 8 ++ > lib/node/ethdev_rx.c | 1 + > lib/node/ethdev_rx_priv.h | 1 + > lib/node/ip4_reassembly.c | 186 ++++++++++++++++++++++++++++ > lib/node/ip4_reassembly_priv.h | 28 +++++ > lib/node/meson.build | 3 +- > lib/node/rte_node_ip4_api.h | 37 ++++++ > lib/node/version.map | 1 + > 8 files changed, 264 insertions(+), 1 deletion(-) > create mode 100644 lib/node/ip4_reassembly.c > create mode 100644 lib/node/ip4_reassembly_priv.h > > diff --git a/doc/guides/prog_guide/graph_lib.rst > b/doc/guides/prog_guide/graph_lib.rst > index e7b6e12004..10d146e2f6 100644 > --- a/doc/guides/prog_guide/graph_lib.rst > +++ b/doc/guides/prog_guide/graph_lib.rst > @@ -453,6 +453,14 @@ to determine the L2 header to be written to the packet > before sending > the packet out to a particular ethdev_tx node. > ``rte_node_ip4_rewrite_add()`` is control path API to add next-hop info. > > +ip4_reassembly > +~~~~~~~~~~~~~~ > +This node is an intermediate node that reassembles ipv4 fragmented packets, > +non-fragmented packets pass through the node un-effected. The node rewrites > +it's stream and moves it to the next node. > +The fragment table and death row table should be setup via the > +``rte_node_ip4_reassembly_configure`` API. > + > ip6_lookup > ~~~~~~~~~~ > This node is an intermediate node that does LPM lookup for the received > diff --git a/lib/node/ethdev_rx.c b/lib/node/ethdev_rx.c > index d131034991..3e8fac1df4 100644 > --- a/lib/node/ethdev_rx.c > +++ b/lib/node/ethdev_rx.c > @@ -215,6 +215,7 @@ static struct rte_node_register ethdev_rx_node_base = { > .next_nodes = { > [ETHDEV_RX_NEXT_PKT_CLS] = "pkt_cls", > [ETHDEV_RX_NEXT_IP4_LOOKUP] = "ip4_lookup", > + [ETHDEV_RX_NEXT_IP4_REASSEMBLY] = "ip4_reassembly", > }, > }; > > diff --git a/lib/node/ethdev_rx_priv.h b/lib/node/ethdev_rx_priv.h > index 7f24cf962e..574a76c2a6 100644 > --- a/lib/node/ethdev_rx_priv.h > +++ b/lib/node/ethdev_rx_priv.h > @@ -39,6 +39,7 @@ struct ethdev_rx_node_elem { > enum ethdev_rx_next_nodes { > ETHDEV_RX_NEXT_IP4_LOOKUP, > ETHDEV_RX_NEXT_PKT_CLS, > + ETHDEV_RX_NEXT_IP4_REASSEMBLY, > ETHDEV_RX_NEXT_MAX, > }; > > diff --git a/lib/node/ip4_reassembly.c b/lib/node/ip4_reassembly.c > new file mode 100644 > index 0000000000..04823cc596 > --- /dev/null > +++ b/lib/node/ip4_reassembly.c > @@ -0,0 +1,186 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2023 Marvell. > + */ > + > +#include <arpa/inet.h> > +#include <stdlib.h> > +#include <sys/socket.h> > + > +#include <rte_cycles.h> > +#include <rte_debug.h> > +#include <rte_ethdev.h> > +#include <rte_ether.h> > +#include <rte_graph.h> > +#include <rte_graph_worker.h> > +#include <rte_ip.h> > +#include <rte_ip_frag.h> > +#include <rte_mbuf.h> > +#include <rte_tcp.h> > +#include <rte_udp.h> > + > +#include "rte_node_ip4_api.h" > + > +#include "ip4_reassembly_priv.h" > +#include "node_private.h" > + > +struct ip4_reassembly_elem { > + struct ip4_reassembly_elem *next; > + struct ip4_reassembly_ctx ctx; > + rte_node_t node_id; > +}; > + > +/* IP4 reassembly global data struct */ > +struct ip4_reassembly_node_main { > + struct ip4_reassembly_elem *head; > +}; > + > +typedef struct ip4_reassembly_ctx ip4_reassembly_ctx_t; > +typedef struct ip4_reassembly_elem ip4_reassembly_elem_t; > + > +static struct ip4_reassembly_node_main ip4_reassembly_main; > + > +static uint16_t > +ip4_reassembly_node_process(struct rte_graph *graph, struct rte_node *node, > void **objs, > + uint16_t nb_objs) > +{ > +#define PREFETCH_OFFSET 4 > + struct rte_mbuf *mbuf, *mbuf_out; > + struct rte_ip_frag_death_row *dr; > + struct ip4_reassembly_ctx *ctx; > + struct rte_ipv4_hdr *ipv4_hdr; > + struct rte_ip_frag_tbl *tbl; > + void **to_next, **to_free; > + uint16_t idx = 0; > + int i; > + > + ctx = (struct ip4_reassembly_ctx *)node->ctx; > + > + /* Get core specific reassembly tbl */ > + tbl = ctx->tbl; > + dr = ctx->dr; > + > + for (i = 0; i < PREFETCH_OFFSET && i < nb_objs; i++) { > + rte_prefetch0(rte_pktmbuf_mtod_offset((struct rte_mbuf > *)objs[i], void *, > + sizeof(struct > rte_ether_hdr))); > + } > + > + to_next = node->objs; > + for (i = 0; i < nb_objs - PREFETCH_OFFSET; i++) { > +#if RTE_GRAPH_BURST_SIZE > 64 > + /* Prefetch next-next mbufs */ > + if (likely(i + 8 < nb_objs)) > + rte_prefetch0(objs[i + 8]); > +#endif > + rte_prefetch0(rte_pktmbuf_mtod_offset((struct rte_mbuf > *)objs[i + PREFETCH_OFFSET], > + void *, sizeof(struct > rte_ether_hdr))); > + mbuf = (struct rte_mbuf *)objs[i]; > + > + ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr > *, > + sizeof(struct > rte_ether_hdr)); > + if (rte_ipv4_frag_pkt_is_fragmented(ipv4_hdr)) { > + /* prepare mbuf: setup l2_len/l3_len. */ > + mbuf->l2_len = sizeof(struct rte_ether_hdr); > + mbuf->l3_len = sizeof(struct rte_ipv4_hdr); > + > + mbuf_out = rte_ipv4_frag_reassemble_packet(tbl, dr, > mbuf, rte_rdtsc(), > + ipv4_hdr); > + } else { > + mbuf_out = mbuf; > + } > + > + if (mbuf_out) > + to_next[idx++] = (void *)mbuf_out; > + } > + > + for (; i < nb_objs; i++) { > + mbuf = (struct rte_mbuf *)objs[i]; > + > + ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr > *, > + sizeof(struct > rte_ether_hdr)); > + if (rte_ipv4_frag_pkt_is_fragmented(ipv4_hdr)) { > + /* prepare mbuf: setup l2_len/l3_len. */ > + mbuf->l2_len = sizeof(struct rte_ether_hdr); > + mbuf->l3_len = sizeof(struct rte_ipv4_hdr); > + > + mbuf_out = rte_ipv4_frag_reassemble_packet(tbl, dr, > mbuf, rte_rdtsc(), > + ipv4_hdr); > + } else { > + mbuf_out = mbuf; > + } > + > + if (mbuf_out) > + to_next[idx++] = (void *)mbuf_out; > + } > + node->idx = idx; > + rte_node_next_stream_move(graph, node, 1); > + if (dr->cnt) { > + to_free = rte_node_next_stream_get(graph, node, > + > RTE_NODE_IP4_REASSEMBLY_NEXT_PKT_DROP, dr->cnt); > + rte_memcpy(to_free, dr->row, dr->cnt * sizeof(to_free[0])); > + rte_node_next_stream_put(graph, node, > RTE_NODE_IP4_REASSEMBLY_NEXT_PKT_DROP, > + dr->cnt); > + idx += dr->cnt; > + dr->cnt = 0; > + } > + > + return idx; > +} > + > +int > +rte_node_ip4_reassembly_configure(struct rte_node_ip4_reassembly_cfg *cfg, > uint16_t cnt) > +{ > + ip4_reassembly_elem_t *elem; > + int i; > + > + for (i = 0; i < cnt; i++) { > + elem = malloc(sizeof(ip4_reassembly_elem_t)); > + if (elem == NULL) > + return -ENOMEM; > + elem->ctx.dr = cfg[i].dr; > + elem->ctx.tbl = cfg[i].tbl; > + elem->node_id = cfg[i].node_id; > + elem->next = ip4_reassembly_main.head; > + ip4_reassembly_main.head = elem; > + } > + > + return 0; > +} > + > +static int > +ip4_reassembly_node_init(const struct rte_graph *graph, struct rte_node > *node) > +{ > + ip4_reassembly_ctx_t *ctx = (ip4_reassembly_ctx_t *)node->ctx; > + ip4_reassembly_elem_t *elem = ip4_reassembly_main.head; > + > + RTE_SET_USED(graph); > + while (elem) { > + if (elem->node_id == node->id) { > + /* Update node specific context */ > + memcpy(ctx, &elem->ctx, sizeof(ip4_reassembly_ctx_t)); > + break; > + } > + elem = elem->next; > + } > + > + return 0; > +} > + > +static struct rte_node_register ip4_reassembly_node = { > + .process = ip4_reassembly_node_process, > + .name = "ip4_reassembly", > + > + .init = ip4_reassembly_node_init, > + > + .nb_edges = RTE_NODE_IP4_REASSEMBLY_NEXT_PKT_DROP + 1, > + .next_nodes = { > + [RTE_NODE_IP4_REASSEMBLY_NEXT_PKT_DROP] = "pkt_drop", > + }, > +}; > + > +struct rte_node_register * > +ip4_reassembly_node_get(void) > +{ > + return &ip4_reassembly_node; > +} > + > +RTE_NODE_REGISTER(ip4_reassembly_node); > diff --git a/lib/node/ip4_reassembly_priv.h b/lib/node/ip4_reassembly_priv.h > new file mode 100644 > index 0000000000..1fa70274ba > --- /dev/null > +++ b/lib/node/ip4_reassembly_priv.h > @@ -0,0 +1,28 @@ > +/* SPDX-License-Identifier: BSD-3-Clause > + * Copyright(C) 2023 Marvell International Ltd. > + */ > + > +#ifndef __INCLUDE_IP4_REASSEMBLY_PRIV_H__ > +#define __INCLUDE_IP4_REASSEMBLY_PRIV_H__ > + > +/** > + * @internal > + * > + * Ip4_reassembly context structure. > + */ > +struct ip4_reassembly_ctx { > + struct rte_ip_frag_tbl *tbl; > + struct rte_ip_frag_death_row *dr; > +}; > + > +/** > + * @internal > + * > + * Get the IP4 reassembly node > + * > + * @return > + * Pointer to the IP4 reassembly node. > + */ > +struct rte_node_register *ip4_reassembly_node_get(void); > + > +#endif /* __INCLUDE_IP4_REASSEMBLY_PRIV_H__ */ > diff --git a/lib/node/meson.build b/lib/node/meson.build > index 2fa7c1c8f3..72474c0856 100644 > --- a/lib/node/meson.build > +++ b/lib/node/meson.build > @@ -13,6 +13,7 @@ sources = files( > 'ethdev_tx.c', > 'ip4_lookup.c', > 'ip4_rewrite.c', > + 'ip4_reassembly.c', > 'ip6_lookup.c', > 'ip6_rewrite.c', > 'kernel_rx.c', > @@ -30,4 +31,4 @@ headers = files( > > # Strict-aliasing rules are violated by uint8_t[] to context size casts. > cflags += '-fno-strict-aliasing' > -deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev'] > +deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev', 'ip_frag'] > diff --git a/lib/node/rte_node_ip4_api.h b/lib/node/rte_node_ip4_api.h > index 3397da0ae8..8d8e4c41b2 100644 > --- a/lib/node/rte_node_ip4_api.h > +++ b/lib/node/rte_node_ip4_api.h > @@ -22,6 +22,8 @@ extern "C" { > #include <rte_common.h> > #include <rte_compat.h> > > +#include <rte_graph.h> > + > /** > * IP4 lookup next nodes. > */ > @@ -34,6 +36,27 @@ enum rte_node_ip4_lookup_next { > /**< Number of next nodes of lookup node. */ > }; > > +/** > + * IP4 reassembly next nodes. > + */ > +enum rte_node_ip4_reassembly_next { > + RTE_NODE_IP4_REASSEMBLY_NEXT_PKT_DROP, > + /**< Packet drop node. */ > +}; > + > +/** > + * Reassembly configure structure. > + * @see rte_node_ip4_reassembly_configure > + */ > +struct rte_node_ip4_reassembly_cfg { > + struct rte_ip_frag_tbl *tbl; > + /**< Reassembly fragmentation table. */ > + struct rte_ip_frag_death_row *dr; > + /**< Reassembly deathrow table. */ > + rte_node_t node_id; > + /**< Node identifier to configure. */ > +}; > + > /** > * Add ipv4 route to lookup table. > * > @@ -72,6 +95,20 @@ __rte_experimental > int rte_node_ip4_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data, > uint8_t rewrite_len, uint16_t dst_port); > > +/** > + * Add reassembly node configuration data. > + * > + * @param cfg > + * Pointer to the configuration structure. > + * @param cnt > + * Number of configuration structures passed. > + * > + * @return > + * 0 on success, negative otherwise. > + */ > +__rte_experimental > +int rte_node_ip4_reassembly_configure(struct rte_node_ip4_reassembly_cfg > *cfg, uint16_t cnt); > + > #ifdef __cplusplus > } > #endif > diff --git a/lib/node/version.map b/lib/node/version.map > index 40df308bfe..c10e2e78ea 100644 > --- a/lib/node/version.map > +++ b/lib/node/version.map > @@ -4,6 +4,7 @@ EXPERIMENTAL { > rte_node_eth_config; > rte_node_ip4_route_add; > rte_node_ip4_rewrite_add; > + rte_node_ip4_reassembly_configure; > rte_node_ip6_rewrite_add; > rte_node_ip6_route_add; > rte_node_logtype; > -- > 2.25.1 >