* [PATCH 1/3] lib: add IPv6 lookup node
@ 2023-05-16 9:11 Amit Prakash Shukla
2023-05-16 9:11 ` [PATCH 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
` (2 more replies)
0 siblings, 3 replies; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-05-16 9:11 UTC (permalink / raw)
To: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh; +Cc: dev, skori
From: Sunil Kumar Kori <skori@marvell.com>
Similar to IPv4 lookup node, patch adds IPv6 lookup
node.
Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
---
doc/guides/prog_guide/graph_lib.rst | 13 ++
lib/node/ip6_lookup.c | 225 ++++++++++++++++++++++++++++
lib/node/meson.build | 3 +-
lib/node/node_private.h | 3 +-
lib/node/pkt_cls.c | 14 ++
lib/node/pkt_cls_priv.h | 1 +
lib/node/rte_node_ip6_api.h | 80 ++++++++++
lib/node/version.map | 2 +
8 files changed, 339 insertions(+), 2 deletions(-)
create mode 100644 lib/node/ip6_lookup.c
create mode 100644 lib/node/rte_node_ip6_api.h
diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
index 1cfdc86433..1f70d63628 100644
--- a/doc/guides/prog_guide/graph_lib.rst
+++ b/doc/guides/prog_guide/graph_lib.rst
@@ -388,6 +388,19 @@ 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.
+ip6_lookup
+~~~~~~~~~~
+This node is an intermediate node that does LPM lookup for the received
+ipv6 packets and the result determines each packets next node.
+
+On successful LPM lookup, the result contains the ``next_node`` id and
+``next-hop`` id with which the packet needs to be further processed.
+
+On LPM lookup failure, objects are redirected to pkt_drop node.
+``rte_node_ip6_route_add()`` is control path API to add ipv6 routes.
+To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
+sections.
+
null
~~~~
This node ignores the set of objects passed to it and reports that all are
diff --git a/lib/node/ip6_lookup.c b/lib/node/ip6_lookup.c
new file mode 100644
index 0000000000..94a9c404b4
--- /dev/null
+++ b/lib/node/ip6_lookup.c
@@ -0,0 +1,225 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_ip.h>
+#include <rte_lpm6.h>
+
+#include "rte_node_ip6_api.h"
+
+#include "node_private.h"
+
+#define IPV6_L3FWD_LPM_MAX_RULES 1024
+#define IPV6_L3FWD_LPM_NUMBER_TBL8S (1 << 8)
+
+/* IP6 Lookup global data struct */
+struct ip6_lookup_node_main {
+ struct rte_lpm6 *lpm_tbl[RTE_MAX_NUMA_NODES];
+};
+
+struct ip6_lookup_node_ctx {
+ /* Socket's LPM table */
+ struct rte_lpm6 *lpm6;
+ /* Dynamic offset to mbuf priv1 */
+ int mbuf_priv1_off;
+};
+
+int ip6_node_mbuf_priv1_dynfield_offset = -1;
+
+static struct ip6_lookup_node_main ip6_lookup_nm;
+
+#define IP6_LOOKUP_NODE_LPM(ctx) \
+ (((struct ip6_lookup_node_ctx *)ctx)->lpm6)
+
+#define IP6_LOOKUP_NODE_PRIV1_OFF(ctx) \
+ (((struct ip6_lookup_node_ctx *)ctx)->mbuf_priv1_off)
+
+static uint16_t
+ip6_lookup_node_process_scalar(struct rte_graph *graph, struct rte_node *node,
+ void **objs, uint16_t nb_objs)
+{
+ struct rte_lpm6 *lpm6 = IP6_LOOKUP_NODE_LPM(node->ctx);
+ const int dyn = IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx);
+ struct rte_ipv6_hdr *ipv6_hdr;
+ void **to_next, **from;
+ uint16_t last_spec = 0;
+ struct rte_mbuf *mbuf;
+ rte_edge_t next_index;
+ uint16_t held = 0;
+ uint32_t drop_nh;
+ int i, rc;
+
+ /* Speculative next */
+ next_index = RTE_NODE_IP6_LOOKUP_NEXT_REWRITE;
+ /* Drop node */
+ drop_nh = ((uint32_t)RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP) << 16;
+ from = objs;
+
+ /* Get stream for the speculated next node */
+ to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
+ for (i = 0; i < nb_objs; i++) {
+ uint32_t next_hop;
+ uint16_t next;
+
+ mbuf = (struct rte_mbuf *)objs[i];
+
+ /* Extract DIP of mbuf0 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract hop_limits as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf, dyn)->ttl = ipv6_hdr->hop_limits;
+
+ rc = rte_lpm6_lookup(lpm6, ipv6_hdr->dst_addr, &next_hop);
+ next_hop = (rc == 0) ? next_hop : drop_nh;
+
+ node_mbuf_priv1(mbuf, dyn)->nh = (uint16_t)next_hop;
+ next_hop = next_hop >> 16;
+ next = (uint16_t)next_hop;
+
+ if (unlikely(next_index != next)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ rte_node_enqueue_x1(graph, node, next, from[0]);
+ from += 1;
+ } else {
+ last_spec += 1;
+ }
+ }
+
+ /* !!! Home run !!! */
+ if (likely(last_spec == nb_objs)) {
+ rte_node_next_stream_move(graph, node, next_index);
+ return nb_objs;
+ }
+ held += last_spec;
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ rte_node_next_stream_put(graph, node, next_index, held);
+
+ return nb_objs;
+}
+
+int
+rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
+ enum rte_node_ip6_lookup_next next_node)
+{
+ char abuf[INET6_ADDRSTRLEN];
+ struct in6_addr in6;
+ uint8_t socket;
+ uint32_t val;
+ int ret;
+
+ memcpy(in6.s6_addr, ip, RTE_LPM6_IPV6_ADDR_SIZE);
+ inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf));
+ /* Embedded next node id into 24 bit next hop */
+ val = ((next_node << 16) | next_hop) & ((1ull << 24) - 1);
+ node_dbg("ip6_lookup", "LPM: Adding route %s / %d nh (0x%x)", abuf,
+ depth, val);
+
+ for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
+ if (!ip6_lookup_nm.lpm_tbl[socket])
+ continue;
+
+ ret = rte_lpm6_add(ip6_lookup_nm.lpm_tbl[socket], ip, depth,
+ val);
+ if (ret < 0) {
+ node_err("ip6_lookup",
+ "Unable to add entry %s / %d nh (%x) to LPM "
+ "table on sock %d, rc=%d\n",
+ abuf, depth, val, socket, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+setup_lpm6(struct ip6_lookup_node_main *nm, int socket)
+{
+ struct rte_lpm6_config config_ipv6;
+ char s[RTE_LPM6_NAMESIZE];
+
+ /* One LPM table per socket */
+ if (nm->lpm_tbl[socket])
+ return 0;
+
+ /* create the LPM table */
+ config_ipv6.max_rules = IPV6_L3FWD_LPM_MAX_RULES;
+ config_ipv6.number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S;
+ config_ipv6.flags = 0;
+ snprintf(s, sizeof(s), "IPV6_L3FWD_LPM_%d", socket);
+ nm->lpm_tbl[socket] = rte_lpm6_create(s, socket, &config_ipv6);
+ if (nm->lpm_tbl[socket] == NULL)
+ return -rte_errno;
+
+ return 0;
+}
+
+static int
+ip6_lookup_node_init(const struct rte_graph *graph, struct rte_node *node)
+{
+ uint16_t socket, lcore_id;
+ static uint8_t init_once;
+ int rc;
+
+ RTE_SET_USED(graph);
+ RTE_BUILD_BUG_ON(sizeof(struct ip6_lookup_node_ctx) > RTE_NODE_CTX_SZ);
+
+ if (!init_once) {
+ ip6_node_mbuf_priv1_dynfield_offset =
+ rte_mbuf_dynfield_register(
+ &node_mbuf_priv1_dynfield_desc);
+ if (ip6_node_mbuf_priv1_dynfield_offset < 0)
+ return -rte_errno;
+
+ /* Setup LPM tables for all sockets */
+ RTE_LCORE_FOREACH(lcore_id)
+ {
+ socket = rte_lcore_to_socket_id(lcore_id);
+ rc = setup_lpm6(&ip6_lookup_nm, socket);
+ if (rc) {
+ node_err("ip6_lookup",
+ "Failed to setup lpm6 tbl for "
+ "sock %u, rc=%d", socket, rc);
+ return rc;
+ }
+ }
+ init_once = 1;
+ }
+
+ /* Update socket's LPM and mbuf dyn priv1 offset in node ctx */
+ IP6_LOOKUP_NODE_LPM(node->ctx) = ip6_lookup_nm.lpm_tbl[graph->socket];
+ IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx) =
+ ip6_node_mbuf_priv1_dynfield_offset;
+
+ node_dbg("ip6_lookup", "Initialized ip6_lookup node");
+
+ return 0;
+}
+
+static struct rte_node_register ip6_lookup_node = {
+ .process = ip6_lookup_node_process_scalar,
+ .name = "ip6_lookup",
+
+ .init = ip6_lookup_node_init,
+
+ .nb_edges = RTE_NODE_IP6_LOOKUP_NEXT_MAX,
+ .next_nodes = {
+ [RTE_NODE_IP6_LOOKUP_NEXT_REWRITE] = "ip6_rewrite",
+ [RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP] = "pkt_drop",
+ },
+};
+
+RTE_NODE_REGISTER(ip6_lookup_node);
diff --git a/lib/node/meson.build b/lib/node/meson.build
index dbdf673c86..cd30847a0b 100644
--- a/lib/node/meson.build
+++ b/lib/node/meson.build
@@ -12,13 +12,14 @@ sources = files(
'ethdev_rx.c',
'ethdev_tx.c',
'ip4_lookup.c',
+ 'ip6_lookup.c',
'ip4_rewrite.c',
'log.c',
'null.c',
'pkt_cls.c',
'pkt_drop.c',
)
-headers = files('rte_node_ip4_api.h', 'rte_node_eth_api.h')
+headers = files('rte_node_ip4_api.h', 'rte_node_ip6_api.h', 'rte_node_eth_api.h')
# Strict-aliasing rules are violated by uint8_t[] to context size casts.
cflags += '-fno-strict-aliasing'
deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev']
diff --git a/lib/node/node_private.h b/lib/node/node_private.h
index 8c73d5dc10..27555cbfd8 100644
--- a/lib/node/node_private.h
+++ b/lib/node/node_private.h
@@ -26,7 +26,7 @@ extern int rte_node_logtype;
*/
struct node_mbuf_priv1 {
union {
- /* IP4 rewrite */
+ /* IP4/IP6 rewrite */
struct {
uint16_t nh;
uint16_t ttl;
@@ -43,6 +43,7 @@ static const struct rte_mbuf_dynfield node_mbuf_priv1_dynfield_desc = {
.align = __alignof__(struct node_mbuf_priv1),
};
extern int node_mbuf_priv1_dynfield_offset;
+extern int ip6_node_mbuf_priv1_dynfield_offset;
/**
* Node mbuf private area 2.
diff --git a/lib/node/pkt_cls.c b/lib/node/pkt_cls.c
index 3e75f2cf78..a8302b8d28 100644
--- a/lib/node/pkt_cls.c
+++ b/lib/node/pkt_cls.c
@@ -24,6 +24,19 @@ static const uint8_t p_nxt[256] __rte_cache_aligned = {
[RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
PKT_CLS_NEXT_IP4_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
+ PKT_CLS_NEXT_IP6_LOOKUP,
};
static uint16_t
@@ -216,6 +229,7 @@ struct rte_node_register pkt_cls_node = {
/* Pkt drop node starts at '0' */
[PKT_CLS_NEXT_PKT_DROP] = "pkt_drop",
[PKT_CLS_NEXT_IP4_LOOKUP] = "ip4_lookup",
+ [PKT_CLS_NEXT_IP6_LOOKUP] = "ip6_lookup",
},
};
RTE_NODE_REGISTER(pkt_cls_node);
diff --git a/lib/node/pkt_cls_priv.h b/lib/node/pkt_cls_priv.h
index 6f5374f0be..16135807a1 100644
--- a/lib/node/pkt_cls_priv.h
+++ b/lib/node/pkt_cls_priv.h
@@ -13,6 +13,7 @@ struct pkt_cls_node_ctx {
enum pkt_cls_next_nodes {
PKT_CLS_NEXT_PKT_DROP,
PKT_CLS_NEXT_IP4_LOOKUP,
+ PKT_CLS_NEXT_IP6_LOOKUP,
PKT_CLS_NEXT_MAX,
};
diff --git a/lib/node/rte_node_ip6_api.h b/lib/node/rte_node_ip6_api.h
new file mode 100644
index 0000000000..1696ed154d
--- /dev/null
+++ b/lib/node/rte_node_ip6_api.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef __INCLUDE_RTE_NODE_IP6_API_H__
+#define __INCLUDE_RTE_NODE_IP6_API_H__
+
+/**
+ * @file rte_node_ip6_api.h
+ *
+ * @warning
+ * @b EXPERIMENTAL:
+ * All functions in this file may be changed or removed without prior notice.
+ *
+ * This API allows to do control path functions of ip6_* nodes
+ * like ip6_lookup, ip6_rewrite.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+#include <rte_compat.h>
+
+/**
+ * IP6 lookup next nodes.
+ */
+enum rte_node_ip6_lookup_next {
+ RTE_NODE_IP6_LOOKUP_NEXT_REWRITE,
+ /**< Rewrite node. */
+ RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP,
+ /**< Packet drop node. */
+ RTE_NODE_IP6_LOOKUP_NEXT_MAX,
+ /**< Number of next nodes of lookup node. */
+};
+
+/**
+ * Add ipv6 route to lookup table.
+ *
+ * @param ip
+ * IPv6 address of route to be added.
+ * @param depth
+ * Depth of the rule to be added.
+ * @param next_hop
+ * Next hop id of the rule result to be added.
+ * @param next_node
+ * Next node to redirect traffic to.
+ *
+ * @return
+ * 0 on success, negative otherwise.
+ */
+__rte_experimental
+int rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
+ enum rte_node_ip6_lookup_next next_node);
+
+/**
+ * Add a next hop's rewrite data.
+ *
+ * @param next_hop
+ * Next hop id to add rewrite data to.
+ * @param rewrite_data
+ * Rewrite data.
+ * @param rewrite_len
+ * Length of rewrite data.
+ * @param dst_port
+ * Destination port to redirect traffic to.
+ *
+ * @return
+ * 0 on success, negative otherwise.
+ */
+__rte_experimental
+int rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
+ uint8_t rewrite_len, uint16_t dst_port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_NODE_IP6_API_H__ */
diff --git a/lib/node/version.map b/lib/node/version.map
index a799b0d389..40df308bfe 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -4,6 +4,8 @@ EXPERIMENTAL {
rte_node_eth_config;
rte_node_ip4_route_add;
rte_node_ip4_rewrite_add;
+ rte_node_ip6_rewrite_add;
+ rte_node_ip6_route_add;
rte_node_logtype;
local: *;
};
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 2/3] lib: add IPv6 rewrite node
2023-05-16 9:11 [PATCH 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
@ 2023-05-16 9:11 ` Amit Prakash Shukla
2023-05-16 9:11 ` [PATCH 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
2 siblings, 0 replies; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-05-16 9:11 UTC (permalink / raw)
To: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh
Cc: dev, skori, Amit Prakash Shukla
Similar to IPv4 rewrite node, patch adds IPv6 rewrite node.
Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
doc/guides/prog_guide/graph_lib.rst | 8 +
lib/node/ethdev_ctrl.c | 13 ++
lib/node/ip6_rewrite.c | 331 ++++++++++++++++++++++++++++
lib/node/ip6_rewrite_priv.h | 69 ++++++
lib/node/meson.build | 1 +
5 files changed, 422 insertions(+)
create mode 100644 lib/node/ip6_rewrite.c
create mode 100644 lib/node/ip6_rewrite_priv.h
diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
index 1f70d63628..841cabe259 100644
--- a/doc/guides/prog_guide/graph_lib.rst
+++ b/doc/guides/prog_guide/graph_lib.rst
@@ -401,6 +401,14 @@ On LPM lookup failure, objects are redirected to pkt_drop node.
To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
sections.
+ip6_rewrite
+~~~~~~~~~~~
+This node gets packets from ``ip6_lookup`` node with next-hop id for each
+packet is embedded in ``node_mbuf_priv1(mbuf)->nh``. This id is used
+to determine the L2 header to be written to the packet before sending
+the packet out to a particular ethdev_tx node.
+``rte_node_ip6_rewrite_add()`` is control path API to add next-hop info.
+
null
~~~~
This node ignores the set of objects passed to it and reports that all are
diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index 37df0431b8..ea7dc8210b 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -12,6 +12,7 @@
#include "ethdev_rx_priv.h"
#include "ethdev_tx_priv.h"
#include "ip4_rewrite_priv.h"
+#include "ip6_rewrite_priv.h"
#include "node_private.h"
static struct ethdev_ctrl {
@@ -23,6 +24,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
uint16_t nb_graphs)
{
struct rte_node_register *ip4_rewrite_node;
+ struct rte_node_register *ip6_rewrite_node;
struct ethdev_tx_node_main *tx_node_data;
uint16_t tx_q_used, rx_q_used, port_id;
struct rte_node_register *tx_node;
@@ -33,6 +35,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
uint32_t id;
ip4_rewrite_node = ip4_rewrite_node_get();
+ ip6_rewrite_node = ip6_rewrite_node_get();
tx_node_data = ethdev_tx_node_data_get();
tx_node = ethdev_tx_node_get();
for (i = 0; i < nb_confs; i++) {
@@ -110,6 +113,16 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
port_id, rte_node_edge_count(ip4_rewrite_node->id) - 1);
if (rc < 0)
return rc;
+
+ /* Add this tx port node as next to ip6_rewrite_node */
+ rte_node_edge_update(ip6_rewrite_node->id, RTE_EDGE_ID_INVALID,
+ &next_nodes, 1);
+ /* Assuming edge id is the last one alloc'ed */
+ rc = ip6_rewrite_set_next(
+ port_id, rte_node_edge_count(ip6_rewrite_node->id) - 1);
+ if (rc < 0)
+ return rc;
+
}
ctrl.nb_graphs = nb_graphs;
diff --git a/lib/node/ip6_rewrite.c b/lib/node/ip6_rewrite.c
new file mode 100644
index 0000000000..0e9631c86f
--- /dev/null
+++ b/lib/node/ip6_rewrite.c
@@ -0,0 +1,331 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_ip.h>
+#include <rte_malloc.h>
+#include <rte_vect.h>
+
+#include "rte_node_ip6_api.h"
+
+#include "ip6_rewrite_priv.h"
+#include "node_private.h"
+
+struct ip6_rewrite_node_ctx {
+ /* Dynamic offset to mbuf priv1 */
+ int mbuf_priv1_off;
+ /* Cached next index */
+ uint16_t next_index;
+};
+
+static struct ip6_rewrite_node_main *ip6_rewrite_nm;
+
+#define IP6_REWRITE_NODE_LAST_NEXT(ctx) \
+ (((struct ip6_rewrite_node_ctx *)ctx)->next_index)
+
+#define IP6_REWRITE_NODE_PRIV1_OFF(ctx) \
+ (((struct ip6_rewrite_node_ctx *)ctx)->mbuf_priv1_off)
+
+static uint16_t
+ip6_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
+ void **objs, uint16_t nb_objs)
+{
+ struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
+ struct ip6_rewrite_nh_header *nh = ip6_rewrite_nm->nh;
+ const int dyn = IP6_REWRITE_NODE_PRIV1_OFF(node->ctx);
+ uint16_t next0, next1, next2, next3, next_index;
+ uint16_t n_left_from, held = 0, last_spec = 0;
+ struct rte_ipv6_hdr *ip0, *ip1, *ip2, *ip3;
+ void *d0, *d1, *d2, *d3;
+ void **to_next, **from;
+ rte_xmm_t priv01;
+ rte_xmm_t priv23;
+ int i;
+
+ /* Speculative next as last next */
+ next_index = IP6_REWRITE_NODE_LAST_NEXT(node->ctx);
+ rte_prefetch0(nh);
+
+ pkts = (struct rte_mbuf **)objs;
+ from = objs;
+ n_left_from = nb_objs;
+
+ for (i = 0; i < 4 && i < n_left_from; i++)
+ rte_prefetch0(pkts[i]);
+
+ /* Get stream for the speculated next node */
+ to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
+ /* Update Ethernet header of pkts */
+ while (n_left_from >= 4) {
+ if (likely(n_left_from > 7)) {
+ /* Prefetch only next-mbuf struct and priv area.
+ * Data need not be prefetched as we only write.
+ */
+ rte_prefetch0(pkts[4]);
+ rte_prefetch0(pkts[5]);
+ rte_prefetch0(pkts[6]);
+ rte_prefetch0(pkts[7]);
+ }
+
+ mbuf0 = pkts[0];
+ mbuf1 = pkts[1];
+ mbuf2 = pkts[2];
+ mbuf3 = pkts[3];
+
+ pkts += 4;
+ n_left_from -= 4;
+ priv01.u64[0] = node_mbuf_priv1(mbuf0, dyn)->u;
+ priv01.u64[1] = node_mbuf_priv1(mbuf1, dyn)->u;
+ priv23.u64[0] = node_mbuf_priv1(mbuf2, dyn)->u;
+ priv23.u64[1] = node_mbuf_priv1(mbuf3, dyn)->u;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf0 */
+ d0 = rte_pktmbuf_mtod(mbuf0, void *);
+ rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,
+ nh[priv01.u16[0]].rewrite_len);
+
+ next0 = nh[priv01.u16[0]].tx_node;
+ ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
+ sizeof(struct rte_ether_hdr));
+ ip0->hop_limits = priv01.u16[1] - 1;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf1 */
+ d1 = rte_pktmbuf_mtod(mbuf1, void *);
+ rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,
+ nh[priv01.u16[4]].rewrite_len);
+
+ next1 = nh[priv01.u16[4]].tx_node;
+ ip1 = (struct rte_ipv6_hdr *)((uint8_t *)d1 +
+ sizeof(struct rte_ether_hdr));
+ ip1->hop_limits = priv01.u16[5] - 1;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf2 */
+ d2 = rte_pktmbuf_mtod(mbuf2, void *);
+ rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,
+ nh[priv23.u16[0]].rewrite_len);
+ next2 = nh[priv23.u16[0]].tx_node;
+ ip2 = (struct rte_ipv6_hdr *)((uint8_t *)d2 +
+ sizeof(struct rte_ether_hdr));
+ ip2->hop_limits = priv23.u16[1] - 1;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf3 */
+ d3 = rte_pktmbuf_mtod(mbuf3, void *);
+ rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,
+ nh[priv23.u16[4]].rewrite_len);
+
+ next3 = nh[priv23.u16[4]].tx_node;
+ ip3 = (struct rte_ipv6_hdr *)((uint8_t *)d3 +
+ sizeof(struct rte_ether_hdr));
+ ip3->hop_limits = priv23.u16[5] - 1;
+
+ /* Enqueue four packets to next node */
+ rte_edge_t fix_spec =
+ ((next_index == next0) && (next0 == next1) &&
+ (next1 == next2) && (next2 == next3));
+
+ if (unlikely(fix_spec == 0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ /* next0 */
+ if (next_index == next0) {
+ to_next[0] = from[0];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next0,
+ from[0]);
+ }
+
+ /* next1 */
+ if (next_index == next1) {
+ to_next[0] = from[1];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next1,
+ from[1]);
+ }
+
+ /* next2 */
+ if (next_index == next2) {
+ to_next[0] = from[2];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next2,
+ from[2]);
+ }
+
+ /* next3 */
+ if (next_index == next3) {
+ to_next[0] = from[3];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next3,
+ from[3]);
+ }
+
+ from += 4;
+
+ /* Change speculation if last two are same */
+ if ((next_index != next3) && (next2 == next3)) {
+ /* Put the current speculated node */
+ rte_node_next_stream_put(graph, node,
+ next_index, held);
+ held = 0;
+
+ /* Get next speculated stream */
+ next_index = next3;
+ to_next = rte_node_next_stream_get(
+ graph, node, next_index, nb_objs);
+ }
+ } else {
+ last_spec += 4;
+ }
+ }
+
+ while (n_left_from > 0) {
+ mbuf0 = pkts[0];
+
+ pkts += 1;
+ n_left_from -= 1;
+
+ d0 = rte_pktmbuf_mtod(mbuf0, void *);
+ rte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,
+ nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);
+
+ next0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node;
+ ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
+ sizeof(struct rte_ether_hdr));
+ ip0->hop_limits = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;
+
+ if (unlikely(next_index ^ next0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ rte_node_enqueue_x1(graph, node, next0, from[0]);
+ from += 1;
+ } else {
+ last_spec += 1;
+ }
+ }
+
+ /* !!! Home run !!! */
+ if (likely(last_spec == nb_objs)) {
+ rte_node_next_stream_move(graph, node, next_index);
+ return nb_objs;
+ }
+
+ held += last_spec;
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ rte_node_next_stream_put(graph, node, next_index, held);
+ /* Save the last next used */
+ IP6_REWRITE_NODE_LAST_NEXT(node->ctx) = next_index;
+
+ return nb_objs;
+}
+
+static int
+ip6_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
+{
+ static bool init_once;
+
+ RTE_SET_USED(graph);
+ RTE_BUILD_BUG_ON(sizeof(struct ip6_rewrite_node_ctx) > RTE_NODE_CTX_SZ);
+
+ if (!init_once) {
+ ip6_node_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register(
+ &node_mbuf_priv1_dynfield_desc);
+ if (ip6_node_mbuf_priv1_dynfield_offset < 0)
+ return -rte_errno;
+ init_once = true;
+ }
+ IP6_REWRITE_NODE_PRIV1_OFF(node->ctx) = ip6_node_mbuf_priv1_dynfield_offset;
+
+ node_dbg("ip6_rewrite", "Initialized ip6_rewrite node");
+
+ return 0;
+}
+
+int
+ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index)
+{
+ if (ip6_rewrite_nm == NULL) {
+ ip6_rewrite_nm = rte_zmalloc(
+ "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
+ RTE_CACHE_LINE_SIZE);
+ if (ip6_rewrite_nm == NULL)
+ return -ENOMEM;
+ }
+ ip6_rewrite_nm->next_index[port_id] = next_index;
+
+ return 0;
+}
+
+int
+rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
+ uint8_t rewrite_len, uint16_t dst_port)
+{
+ struct ip6_rewrite_nh_header *nh;
+
+ if (next_hop >= RTE_GRAPH_IP6_REWRITE_MAX_NH)
+ return -EINVAL;
+
+ if (rewrite_len > RTE_GRAPH_IP6_REWRITE_MAX_LEN)
+ return -EINVAL;
+
+ if (ip6_rewrite_nm == NULL) {
+ ip6_rewrite_nm = rte_zmalloc(
+ "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
+ RTE_CACHE_LINE_SIZE);
+ if (ip6_rewrite_nm == NULL)
+ return -ENOMEM;
+ }
+
+ /* Check if dst port doesn't exist as edge */
+ if (!ip6_rewrite_nm->next_index[dst_port])
+ return -EINVAL;
+
+ /* Update next hop */
+ nh = &ip6_rewrite_nm->nh[next_hop];
+
+ memcpy(nh->rewrite_data, rewrite_data, rewrite_len);
+ nh->tx_node = ip6_rewrite_nm->next_index[dst_port];
+ nh->rewrite_len = rewrite_len;
+ nh->enabled = true;
+
+ return 0;
+}
+
+static struct rte_node_register ip6_rewrite_node = {
+ .process = ip6_rewrite_node_process,
+ .name = "ip6_rewrite",
+ /* Default edge i.e '0' is pkt drop */
+ .nb_edges = 1,
+ .next_nodes = {
+ [0] = "pkt_drop",
+ },
+ .init = ip6_rewrite_node_init,
+};
+
+struct rte_node_register *
+ip6_rewrite_node_get(void)
+{
+ return &ip6_rewrite_node;
+}
+
+RTE_NODE_REGISTER(ip6_rewrite_node);
diff --git a/lib/node/ip6_rewrite_priv.h b/lib/node/ip6_rewrite_priv.h
new file mode 100644
index 0000000000..93db28bec0
--- /dev/null
+++ b/lib/node/ip6_rewrite_priv.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+#ifndef __INCLUDE_IP6_REWRITE_PRIV_H__
+#define __INCLUDE_IP6_REWRITE_PRIV_H__
+
+#include <rte_common.h>
+
+#define RTE_GRAPH_IP6_REWRITE_MAX_NH 64
+#define RTE_GRAPH_IP6_REWRITE_MAX_LEN 56
+
+/**
+ * @internal
+ *
+ * Ipv6 rewrite next hop header data structure. Used to store port specific
+ * rewrite data.
+ */
+struct ip6_rewrite_nh_header {
+ uint16_t rewrite_len; /**< Header rewrite length. */
+ uint16_t tx_node; /**< Tx node next index identifier. */
+ uint16_t enabled; /**< NH enable flag */
+ uint16_t rsvd;
+ union {
+ struct {
+ struct rte_ether_addr dst;
+ /**< Destination mac address. */
+ struct rte_ether_addr src;
+ /**< Source mac address. */
+ };
+ uint8_t rewrite_data[RTE_GRAPH_IP6_REWRITE_MAX_LEN];
+ /**< Generic rewrite data */
+ };
+};
+
+/**
+ * @internal
+ *
+ * Ipv6 node main data structure.
+ */
+struct ip6_rewrite_node_main {
+ struct ip6_rewrite_nh_header nh[RTE_GRAPH_IP6_REWRITE_MAX_NH];
+ /**< Array of next hop header data */
+ uint16_t next_index[RTE_MAX_ETHPORTS];
+ /**< Next index of each configured port. */
+};
+
+/**
+ * @internal
+ *
+ * Get the ipv6 rewrite node.
+ *
+ * @return
+ * Pointer to the ipv6 rewrite node.
+ */
+struct rte_node_register *ip6_rewrite_node_get(void);
+
+/**
+ * @internal
+ *
+ * Set the Edge index of a given port_id.
+ *
+ * @param port_id
+ * Ethernet port identifier.
+ * @param next_index
+ * Edge index of the Given Tx node.
+ */
+int ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index);
+
+#endif /* __INCLUDE_IP6_REWRITE_PRIV_H__ */
diff --git a/lib/node/meson.build b/lib/node/meson.build
index cd30847a0b..b2f04269c5 100644
--- a/lib/node/meson.build
+++ b/lib/node/meson.build
@@ -14,6 +14,7 @@ sources = files(
'ip4_lookup.c',
'ip6_lookup.c',
'ip4_rewrite.c',
+ 'ip6_rewrite.c',
'log.c',
'null.c',
'pkt_cls.c',
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support
2023-05-16 9:11 [PATCH 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
2023-05-16 9:11 ` [PATCH 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
@ 2023-05-16 9:11 ` Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
2 siblings, 0 replies; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-05-16 9:11 UTC (permalink / raw)
To: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram
Cc: dev, skori, Amit Prakash Shukla
From: Sunil Kumar Kori <skori@marvell.com>
Similar to ipv4, to support IPv6 lookup and rewrite node
routes and rewrite data needs to be added.
Patch adds routes for ipv6 to validate ip6_lookup node
and rewrite data to validate ip6_rewrite node.
Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
doc/guides/sample_app_ug/l3_forward_graph.rst | 40 ++++++----
examples/l3fwd-graph/main.c | 77 ++++++++++++++++++-
2 files changed, 98 insertions(+), 19 deletions(-)
diff --git a/doc/guides/sample_app_ug/l3_forward_graph.rst b/doc/guides/sample_app_ug/l3_forward_graph.rst
index 585ac8c898..23f86e4785 100644
--- a/doc/guides/sample_app_ug/l3_forward_graph.rst
+++ b/doc/guides/sample_app_ug/l3_forward_graph.rst
@@ -12,7 +12,8 @@ Overview
--------
The application demonstrates the use of the graph framework and graph nodes
-``ethdev_rx``, ``ip4_lookup``, ``ip4_rewrite``, ``ethdev_tx`` and ``pkt_drop`` in DPDK to
+``ethdev_rx``, ``pkt_cls``, ``ip4_lookup``/``ip6_lookup``,
+``ip4_rewrite``/``ip6_rewrite``, ``ethdev_tx`` and ``pkt_drop`` in DPDK to
implement packet forwarding.
The initialization is very similar to those of the :doc:`l3_forward`.
@@ -24,13 +25,15 @@ TTL update and finally Tx is implemented inside graph nodes. These nodes are
interconnected in graph framework. Application main loop needs to walk over
graph using ``rte_graph_walk()`` with graph objects created one per worker lcore.
-The lookup method is as per implementation of ``ip4_lookup`` graph node.
+The lookup method is as per implementation of ``ip4_lookup``/``ip6_lookup`` graph node.
The ID of the output interface for the input packet is the next hop returned by
the LPM lookup. The set of LPM rules used by the application is statically
-configured and provided to ``ip4_lookup`` graph node and ``ip4_rewrite`` graph node
-using node control API ``rte_node_ip4_route_add()`` and ``rte_node_ip4_rewrite_add()``.
+configured and provided to ``ip4_lookup``/``ip6_lookup`` graph node and
+``ip4_rewrite``/``ip6_rewrite`` graph node using node control API
+``rte_node_ip4_route_add()``/``rte_node_ip6_route_add`` and
+``rte_node_ip4_rewrite_add()``/``rte_node_ip6_rewrite_add``.
-In the sample application, only IPv4 forwarding is supported as of now.
+In the sample application, IPv4 and IPv6 forwarding is supported.
Compiling the Application
-------------------------
@@ -149,8 +152,8 @@ lead to the clone of ``ethdev_rx`` and ``ethdev_tx`` nodes as ``ethdev_rx-X-Y``
In case of ``ethdev_tx-X`` nodes, tx queue id assigned per instance of the node
is same as graph id.
-These cloned nodes along with existing static nodes such as ``ip4_lookup`` and
-``ip4_rewrite`` will be used in graph creation to associate node's to lcore
+These cloned nodes along with existing static nodes such as ``ip4_lookup``/``ip6_lookup``
+and ``ip4_rewrite``/``ip6_rewrite`` will be used in graph creation to associate node's to lcore
specific graph object.
.. literalinclude:: ../../../examples/l3fwd-graph/main.c
@@ -186,20 +189,21 @@ Forwarding data(Route, Next-Hop) addition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once graph objects are created, node specific info like routes and rewrite
-headers will be provided run-time using ``rte_node_ip4_route_add()`` and
-``rte_node_ip4_rewrite_add()`` API.
+headers will be provided run-time using ``rte_node_ip4_route_add()``/
+``rte_node_ip6_route_add`` and ``rte_node_ip4_rewrite_add()``/``rte_node_ip6_rewrite_add``
+API.
.. note::
- Since currently ``ip4_lookup`` and ``ip4_rewrite`` nodes don't support
- lock-less mechanisms(RCU, etc) to add run-time forwarding data like route and
- rewrite data, forwarding data is added before packet processing loop is
- launched on worker lcore.
+ Since currently ``ip4_lookup``/``ip6_lookup`` and ``ip4_rewrite``/``ip6_rewrite``
+ nodes don't support lock-less mechanisms(RCU, etc) to add run-time forwarding
+ data like route and rewrite data, forwarding data is added before packet
+ processing loop is launched on worker lcore.
.. literalinclude:: ../../../examples/l3fwd-graph/main.c
:language: c
- :start-after: Add route to ip4 graph infra. 8<
- :end-before: >8 End of adding route to ip4 graph infa.
+ :start-after: Add routes and rewrite data to graph infra. 8<
+ :end-before: >8 End of adding routes and rewrite data to graph infa.
:dedent: 1
Packet Forwarding using Graph Walk
@@ -215,8 +219,10 @@ specific graph object that was already created.
rte_graph_walk() will walk over all the sources nodes i.e ``ethdev_rx-X-Y``
associated with a given graph and Rx the available packets and enqueue them
- to the following node ``ip4_lookup`` which then will enqueue them to ``ip4_rewrite``
- node if LPM lookup succeeds. ``ip4_rewrite`` node then will update Ethernet header
+ to the following node ``pkt_cls`` which based on the packet type will enqueue
+ them to ``ip4_lookup``/``ip6_lookup`` which then will enqueue them to
+ ``ip4_rewrite``/``ip6_rewrite`` node if LPM lookup succeeds.
+ ``ip4_rewrite``/``ip6_rewrite`` node then will update Ethernet header
as per next-hop data and transmit the packet via port 'Z' by enqueuing
to ``ethdev_tx-Z`` node instance in its graph object.
diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c
index 5feeab4f0f..0c82e24513 100644
--- a/examples/l3fwd-graph/main.c
+++ b/examples/l3fwd-graph/main.c
@@ -27,9 +27,11 @@
#include <rte_launch.h>
#include <rte_lcore.h>
#include <rte_log.h>
+#include <rte_lpm6.h>
#include <rte_mempool.h>
#include <rte_node_eth_api.h>
#include <rte_node_ip4_api.h>
+#include <rte_node_ip6_api.h>
#include <rte_per_lcore.h>
#include <rte_string_fns.h>
#include <rte_vect.h>
@@ -142,6 +144,12 @@ struct ipv4_l3fwd_lpm_route {
uint8_t if_out;
};
+struct ipv6_l3fwd_lpm_route {
+ uint8_t ip[RTE_LPM6_IPV6_ADDR_SIZE];
+ uint8_t depth;
+ uint8_t if_out;
+};
+
#define IPV4_L3FWD_LPM_NUM_ROUTES \
(sizeof(ipv4_l3fwd_lpm_route_array) / \
sizeof(ipv4_l3fwd_lpm_route_array[0]))
@@ -153,6 +161,28 @@ static struct ipv4_l3fwd_lpm_route ipv4_l3fwd_lpm_route_array[] = {
{RTE_IPV4(198, 18, 6, 0), 24, 6}, {RTE_IPV4(198, 18, 7, 0), 24, 7},
};
+#define IPV6_L3FWD_LPM_NUM_ROUTES \
+ (sizeof(ipv6_l3fwd_lpm_route_array) / \
+ sizeof(ipv6_l3fwd_lpm_route_array[0]))
+static struct ipv6_l3fwd_lpm_route ipv6_l3fwd_lpm_route_array[] = {
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00}, 48, 0},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01}, 48, 1},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02}, 48, 2},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03}, 48, 3},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04}, 48, 4},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05}, 48, 5},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06}, 48, 6},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02}, 48, 7},
+};
+
static int
check_lcore_params(void)
{
@@ -1128,7 +1158,7 @@ main(int argc, char **argv)
memset(&rewrite_data, 0, sizeof(rewrite_data));
rewrite_len = sizeof(rewrite_data);
- /* Add route to ip4 graph infra. 8< */
+ /* Add routes and rewrite data to graph infra. 8< */
for (i = 0; i < IPV4_L3FWD_LPM_NUM_ROUTES; i++) {
char route_str[INET6_ADDRSTRLEN * 4];
char abuf[INET6_ADDRSTRLEN];
@@ -1172,7 +1202,50 @@ main(int argc, char **argv)
RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n",
route_str, i);
}
- /* >8 End of adding route to ip4 graph infa. */
+
+ for (i = 0; i < IPV6_L3FWD_LPM_NUM_ROUTES; i++) {
+ char route_str[INET6_ADDRSTRLEN * 4];
+ char abuf[INET6_ADDRSTRLEN];
+ struct in6_addr in6;
+ uint32_t dst_port;
+
+ /* Skip unused ports */
+ if ((1 << ipv6_l3fwd_lpm_route_array[i].if_out &
+ enabled_port_mask) == 0)
+ continue;
+
+ dst_port = ipv6_l3fwd_lpm_route_array[i].if_out;
+
+ memcpy(in6.s6_addr, ipv6_l3fwd_lpm_route_array[i].ip, RTE_LPM6_IPV6_ADDR_SIZE);
+ snprintf(route_str, sizeof(route_str), "%s / %d (%d)",
+ inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf)),
+ ipv6_l3fwd_lpm_route_array[i].depth,
+ ipv6_l3fwd_lpm_route_array[i].if_out);
+
+ /* Use route index 'i' as next hop id */
+ ret = rte_node_ip6_route_add(ipv6_l3fwd_lpm_route_array[i].ip,
+ ipv6_l3fwd_lpm_route_array[i].depth, i,
+ RTE_NODE_IP6_LOOKUP_NEXT_REWRITE);
+
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "Unable to add ip6 route %s to graph\n",
+ route_str);
+
+ memcpy(rewrite_data, val_eth + dst_port, rewrite_len);
+
+ /* Add next hop rewrite data for id 'i' */
+ ret = rte_node_ip6_rewrite_add(i, rewrite_data,
+ rewrite_len, dst_port);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "Unable to add next hop %u for "
+ "route %s\n", i, route_str);
+
+ RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n",
+ route_str, i);
+ }
+ /* >8 End of adding routes and rewrite data to graph infa. */
/* Launch per-lcore init on every worker lcore */
rte_eal_mp_remote_launch(graph_main_loop, NULL, SKIP_MAIN);
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 1/3] lib: add IPv6 lookup node
2023-05-16 9:11 [PATCH 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
2023-05-16 9:11 ` [PATCH 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
2023-05-16 9:11 ` [PATCH 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
@ 2023-05-18 15:56 ` Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
` (3 more replies)
2 siblings, 4 replies; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-05-18 15:56 UTC (permalink / raw)
To: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh
Cc: dev, skori, Amit Prakash Shukla
From: Sunil Kumar Kori <skori@marvell.com>
Similar to IPv4 lookup node, patch adds IPv6 lookup
node.
Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Performance related changes
doc/guides/prog_guide/graph_lib.rst | 13 +
lib/node/ip6_lookup.c | 374 ++++++++++++++++++++++++++++
lib/node/meson.build | 3 +-
lib/node/node_private.h | 3 +-
lib/node/pkt_cls.c | 14 ++
lib/node/pkt_cls_priv.h | 1 +
lib/node/rte_node_ip6_api.h | 80 ++++++
lib/node/version.map | 2 +
8 files changed, 488 insertions(+), 2 deletions(-)
create mode 100644 lib/node/ip6_lookup.c
create mode 100644 lib/node/rte_node_ip6_api.h
diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
index 1cfdc86433..1f70d63628 100644
--- a/doc/guides/prog_guide/graph_lib.rst
+++ b/doc/guides/prog_guide/graph_lib.rst
@@ -388,6 +388,19 @@ 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.
+ip6_lookup
+~~~~~~~~~~
+This node is an intermediate node that does LPM lookup for the received
+ipv6 packets and the result determines each packets next node.
+
+On successful LPM lookup, the result contains the ``next_node`` id and
+``next-hop`` id with which the packet needs to be further processed.
+
+On LPM lookup failure, objects are redirected to pkt_drop node.
+``rte_node_ip6_route_add()`` is control path API to add ipv6 routes.
+To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
+sections.
+
null
~~~~
This node ignores the set of objects passed to it and reports that all are
diff --git a/lib/node/ip6_lookup.c b/lib/node/ip6_lookup.c
new file mode 100644
index 0000000000..a377c06072
--- /dev/null
+++ b/lib/node/ip6_lookup.c
@@ -0,0 +1,374 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_ip.h>
+#include <rte_lpm6.h>
+
+#include "rte_node_ip6_api.h"
+
+#include "node_private.h"
+
+#define IPV6_L3FWD_LPM_MAX_RULES 1024
+#define IPV6_L3FWD_LPM_NUMBER_TBL8S (1 << 8)
+
+/* IP6 Lookup global data struct */
+struct ip6_lookup_node_main {
+ struct rte_lpm6 *lpm_tbl[RTE_MAX_NUMA_NODES];
+};
+
+struct ip6_lookup_node_ctx {
+ /* Socket's LPM table */
+ struct rte_lpm6 *lpm6;
+ /* Dynamic offset to mbuf priv1 */
+ int mbuf_priv1_off;
+};
+
+int ip6_node_mbuf_priv1_dynfield_offset = -1;
+
+static struct ip6_lookup_node_main ip6_lookup_nm;
+
+#define IP6_LOOKUP_NODE_LPM(ctx) \
+ (((struct ip6_lookup_node_ctx *)ctx)->lpm6)
+
+#define IP6_LOOKUP_NODE_PRIV1_OFF(ctx) \
+ (((struct ip6_lookup_node_ctx *)ctx)->mbuf_priv1_off)
+
+static uint16_t
+ip6_lookup_node_process_scalar(struct rte_graph *graph, struct rte_node *node,
+ void **objs, uint16_t nb_objs)
+{
+ struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
+ struct rte_lpm6 *lpm6 = IP6_LOOKUP_NODE_LPM(node->ctx);
+ const int dyn = IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx);
+ struct rte_ipv6_hdr *ipv6_hdr;
+ void **to_next, **from;
+ uint16_t last_spec = 0;
+ rte_edge_t next_index;
+ uint16_t n_left_from;
+ uint16_t held = 0;
+ uint32_t drop_nh;
+ int i, rc;
+
+ /* Speculative next */
+ next_index = RTE_NODE_IP6_LOOKUP_NEXT_REWRITE;
+ /* Drop node */
+ drop_nh = ((uint32_t)RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP) << 16;
+
+ pkts = (struct rte_mbuf **)objs;
+ from = objs;
+ n_left_from = nb_objs;
+
+ for (i = OBJS_PER_CLINE; i < RTE_GRAPH_BURST_SIZE; i += OBJS_PER_CLINE)
+ rte_prefetch0(&objs[i]);
+
+ for (i = 0; i < 4 && i < n_left_from; i++)
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[i], void *,
+ sizeof(struct rte_ether_hdr)));
+
+ /* Get stream for the speculated next node */
+ to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
+ while (n_left_from >= 4) {
+#if RTE_GRAPH_BURST_SIZE > 64
+ /* Prefetch next-next mbufs */
+ if (likely(n_left_from > 11)) {
+ rte_prefetch0(pkts[8]);
+ rte_prefetch0(pkts[9]);
+ rte_prefetch0(pkts[10]);
+ rte_prefetch0(pkts[11]);
+ }
+#endif
+ /* Prefetch next mbuf data */
+ if (likely(n_left_from > 7)) {
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[4], void *,
+ sizeof(struct rte_ether_hdr)));
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[5], void *,
+ sizeof(struct rte_ether_hdr)));
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[6], void *,
+ sizeof(struct rte_ether_hdr)));
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[7], void *,
+ sizeof(struct rte_ether_hdr)));
+ }
+
+ mbuf0 = pkts[0];
+ mbuf1 = pkts[1];
+ mbuf2 = pkts[2];
+ mbuf3 = pkts[3];
+
+ pkts += 4;
+ n_left_from -= 4;
+
+ uint8_t ip_batch[4][16];
+ int32_t next_hop[4];
+ uint16_t next[4];
+
+ /* Extract DIP of mbuf0 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract hop_limits as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
+ rte_memcpy(ip_batch[0], ipv6_hdr->dst_addr, 16);
+
+ /* Extract DIP of mbuf1 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf1, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract hop_limits as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf1, dyn)->ttl = ipv6_hdr->hop_limits;
+ rte_memcpy(ip_batch[1], ipv6_hdr->dst_addr, 16);
+
+ /* Extract DIP of mbuf2 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf2, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract hop_limits as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf2, dyn)->ttl = ipv6_hdr->hop_limits;
+ rte_memcpy(ip_batch[2], ipv6_hdr->dst_addr, 16);
+
+ /* Extract DIP of mbuf3 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf3, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract hop_limits as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf3, dyn)->ttl = ipv6_hdr->hop_limits;
+ rte_memcpy(ip_batch[3], ipv6_hdr->dst_addr, 16);
+
+ rc = rte_lpm6_lookup_bulk_func(lpm6, ip_batch, next_hop, 4);
+
+ next_hop[0] = (next_hop[0] < 0) ? (int32_t)drop_nh : next_hop[0];
+ node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop[0];
+ next[0] = (uint16_t)(next_hop[0] >> 16);
+
+ next_hop[1] = (next_hop[1] < 0) ? (int32_t)drop_nh : next_hop[1];
+ node_mbuf_priv1(mbuf1, dyn)->nh = (uint16_t)next_hop[1];
+ next[1] = (uint16_t)(next_hop[1] >> 16);
+
+ next_hop[2] = (next_hop[2] < 0) ? (int32_t)drop_nh : next_hop[2];
+ node_mbuf_priv1(mbuf2, dyn)->nh = (uint16_t)next_hop[2];
+ next[2] = (uint16_t)(next_hop[2] >> 16);
+
+ next_hop[3] = (next_hop[3] < 0) ? (int32_t)drop_nh : next_hop[3];
+ node_mbuf_priv1(mbuf3, dyn)->nh = (uint16_t)next_hop[3];
+ next[3] = (uint16_t)(next_hop[3] >> 16);
+
+ rte_edge_t fix_spec = ((next_index == next[0]) &&
+ (next_index == next[1]) &&
+ (next_index == next[2]) &&
+ (next_index == next[3]));
+
+ if (unlikely(fix_spec == 0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ /* Next0 */
+ if (next_index == next[0]) {
+ to_next[0] = from[0];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next[0], from[0]);
+ }
+
+ /* Next1 */
+ if (next_index == next[1]) {
+ to_next[0] = from[1];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next[1], from[1]);
+ }
+
+ /* Next2 */
+ if (next_index == next[2]) {
+ to_next[0] = from[2];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next[2], from[2]);
+ }
+
+ /* Next3 */
+ if (next_index == next[3]) {
+ to_next[0] = from[3];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next[3], from[3]);
+ }
+
+ from += 4;
+ } else {
+ last_spec += 4;
+ }
+ }
+
+ while (n_left_from > 0) {
+ uint32_t next_hop;
+ uint16_t next0;
+
+ mbuf0 = pkts[0];
+
+ pkts += 1;
+ n_left_from -= 1;
+
+ /* Extract DIP of mbuf0 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract ttl as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
+
+ rc = rte_lpm6_lookup(lpm6, ipv6_hdr->dst_addr, &next_hop);
+ next_hop = (rc == 0) ? next_hop : drop_nh;
+
+ node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop;
+ next_hop = next_hop >> 16;
+ next0 = (uint16_t)next_hop;
+
+ if (unlikely(next_index ^ next0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ rte_node_enqueue_x1(graph, node, next0, from[0]);
+ from += 1;
+ } else {
+ last_spec += 1;
+ }
+ }
+
+ /* !!! Home run !!! */
+ if (likely(last_spec == nb_objs)) {
+ rte_node_next_stream_move(graph, node, next_index);
+ return nb_objs;
+ }
+ held += last_spec;
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ rte_node_next_stream_put(graph, node, next_index, held);
+
+ return nb_objs;
+}
+
+int
+rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
+ enum rte_node_ip6_lookup_next next_node)
+{
+ char abuf[INET6_ADDRSTRLEN];
+ struct in6_addr in6;
+ uint8_t socket;
+ uint32_t val;
+ int ret;
+
+ memcpy(in6.s6_addr, ip, RTE_LPM6_IPV6_ADDR_SIZE);
+ inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf));
+ /* Embedded next node id into 24 bit next hop */
+ val = ((next_node << 16) | next_hop) & ((1ull << 24) - 1);
+ node_dbg("ip6_lookup", "LPM: Adding route %s / %d nh (0x%x)", abuf,
+ depth, val);
+
+ for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
+ if (!ip6_lookup_nm.lpm_tbl[socket])
+ continue;
+
+ ret = rte_lpm6_add(ip6_lookup_nm.lpm_tbl[socket], ip, depth,
+ val);
+ if (ret < 0) {
+ node_err("ip6_lookup",
+ "Unable to add entry %s / %d nh (%x) to LPM "
+ "table on sock %d, rc=%d\n",
+ abuf, depth, val, socket, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+setup_lpm6(struct ip6_lookup_node_main *nm, int socket)
+{
+ struct rte_lpm6_config config_ipv6;
+ char s[RTE_LPM6_NAMESIZE];
+
+ /* One LPM table per socket */
+ if (nm->lpm_tbl[socket])
+ return 0;
+
+ /* create the LPM table */
+ config_ipv6.max_rules = IPV6_L3FWD_LPM_MAX_RULES;
+ config_ipv6.number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S;
+ config_ipv6.flags = 0;
+ snprintf(s, sizeof(s), "IPV6_L3FWD_LPM_%d", socket);
+ nm->lpm_tbl[socket] = rte_lpm6_create(s, socket, &config_ipv6);
+ if (nm->lpm_tbl[socket] == NULL)
+ return -rte_errno;
+
+ return 0;
+}
+
+static int
+ip6_lookup_node_init(const struct rte_graph *graph, struct rte_node *node)
+{
+ uint16_t socket, lcore_id;
+ static uint8_t init_once;
+ int rc;
+
+ RTE_SET_USED(graph);
+ RTE_BUILD_BUG_ON(sizeof(struct ip6_lookup_node_ctx) > RTE_NODE_CTX_SZ);
+
+ if (!init_once) {
+ ip6_node_mbuf_priv1_dynfield_offset =
+ rte_mbuf_dynfield_register(
+ &node_mbuf_priv1_dynfield_desc);
+ if (ip6_node_mbuf_priv1_dynfield_offset < 0)
+ return -rte_errno;
+
+ /* Setup LPM tables for all sockets */
+ RTE_LCORE_FOREACH(lcore_id)
+ {
+ socket = rte_lcore_to_socket_id(lcore_id);
+ rc = setup_lpm6(&ip6_lookup_nm, socket);
+ if (rc) {
+ node_err("ip6_lookup",
+ "Failed to setup lpm6 tbl for "
+ "sock %u, rc=%d", socket, rc);
+ return rc;
+ }
+ }
+ init_once = 1;
+ }
+
+ /* Update socket's LPM and mbuf dyn priv1 offset in node ctx */
+ IP6_LOOKUP_NODE_LPM(node->ctx) = ip6_lookup_nm.lpm_tbl[graph->socket];
+ IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx) =
+ ip6_node_mbuf_priv1_dynfield_offset;
+
+ node_dbg("ip6_lookup", "Initialized ip6_lookup node");
+
+ return 0;
+}
+
+static struct rte_node_register ip6_lookup_node = {
+ .process = ip6_lookup_node_process_scalar,
+ .name = "ip6_lookup",
+
+ .init = ip6_lookup_node_init,
+
+ .nb_edges = RTE_NODE_IP6_LOOKUP_NEXT_MAX,
+ .next_nodes = {
+ [RTE_NODE_IP6_LOOKUP_NEXT_REWRITE] = "ip6_rewrite",
+ [RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP] = "pkt_drop",
+ },
+};
+
+RTE_NODE_REGISTER(ip6_lookup_node);
diff --git a/lib/node/meson.build b/lib/node/meson.build
index dbdf673c86..cd30847a0b 100644
--- a/lib/node/meson.build
+++ b/lib/node/meson.build
@@ -12,13 +12,14 @@ sources = files(
'ethdev_rx.c',
'ethdev_tx.c',
'ip4_lookup.c',
+ 'ip6_lookup.c',
'ip4_rewrite.c',
'log.c',
'null.c',
'pkt_cls.c',
'pkt_drop.c',
)
-headers = files('rte_node_ip4_api.h', 'rte_node_eth_api.h')
+headers = files('rte_node_ip4_api.h', 'rte_node_ip6_api.h', 'rte_node_eth_api.h')
# Strict-aliasing rules are violated by uint8_t[] to context size casts.
cflags += '-fno-strict-aliasing'
deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev']
diff --git a/lib/node/node_private.h b/lib/node/node_private.h
index 8c73d5dc10..27555cbfd8 100644
--- a/lib/node/node_private.h
+++ b/lib/node/node_private.h
@@ -26,7 +26,7 @@ extern int rte_node_logtype;
*/
struct node_mbuf_priv1 {
union {
- /* IP4 rewrite */
+ /* IP4/IP6 rewrite */
struct {
uint16_t nh;
uint16_t ttl;
@@ -43,6 +43,7 @@ static const struct rte_mbuf_dynfield node_mbuf_priv1_dynfield_desc = {
.align = __alignof__(struct node_mbuf_priv1),
};
extern int node_mbuf_priv1_dynfield_offset;
+extern int ip6_node_mbuf_priv1_dynfield_offset;
/**
* Node mbuf private area 2.
diff --git a/lib/node/pkt_cls.c b/lib/node/pkt_cls.c
index 3e75f2cf78..a8302b8d28 100644
--- a/lib/node/pkt_cls.c
+++ b/lib/node/pkt_cls.c
@@ -24,6 +24,19 @@ static const uint8_t p_nxt[256] __rte_cache_aligned = {
[RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
PKT_CLS_NEXT_IP4_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
+ PKT_CLS_NEXT_IP6_LOOKUP,
};
static uint16_t
@@ -216,6 +229,7 @@ struct rte_node_register pkt_cls_node = {
/* Pkt drop node starts at '0' */
[PKT_CLS_NEXT_PKT_DROP] = "pkt_drop",
[PKT_CLS_NEXT_IP4_LOOKUP] = "ip4_lookup",
+ [PKT_CLS_NEXT_IP6_LOOKUP] = "ip6_lookup",
},
};
RTE_NODE_REGISTER(pkt_cls_node);
diff --git a/lib/node/pkt_cls_priv.h b/lib/node/pkt_cls_priv.h
index 6f5374f0be..16135807a1 100644
--- a/lib/node/pkt_cls_priv.h
+++ b/lib/node/pkt_cls_priv.h
@@ -13,6 +13,7 @@ struct pkt_cls_node_ctx {
enum pkt_cls_next_nodes {
PKT_CLS_NEXT_PKT_DROP,
PKT_CLS_NEXT_IP4_LOOKUP,
+ PKT_CLS_NEXT_IP6_LOOKUP,
PKT_CLS_NEXT_MAX,
};
diff --git a/lib/node/rte_node_ip6_api.h b/lib/node/rte_node_ip6_api.h
new file mode 100644
index 0000000000..1696ed154d
--- /dev/null
+++ b/lib/node/rte_node_ip6_api.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef __INCLUDE_RTE_NODE_IP6_API_H__
+#define __INCLUDE_RTE_NODE_IP6_API_H__
+
+/**
+ * @file rte_node_ip6_api.h
+ *
+ * @warning
+ * @b EXPERIMENTAL:
+ * All functions in this file may be changed or removed without prior notice.
+ *
+ * This API allows to do control path functions of ip6_* nodes
+ * like ip6_lookup, ip6_rewrite.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+#include <rte_compat.h>
+
+/**
+ * IP6 lookup next nodes.
+ */
+enum rte_node_ip6_lookup_next {
+ RTE_NODE_IP6_LOOKUP_NEXT_REWRITE,
+ /**< Rewrite node. */
+ RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP,
+ /**< Packet drop node. */
+ RTE_NODE_IP6_LOOKUP_NEXT_MAX,
+ /**< Number of next nodes of lookup node. */
+};
+
+/**
+ * Add ipv6 route to lookup table.
+ *
+ * @param ip
+ * IPv6 address of route to be added.
+ * @param depth
+ * Depth of the rule to be added.
+ * @param next_hop
+ * Next hop id of the rule result to be added.
+ * @param next_node
+ * Next node to redirect traffic to.
+ *
+ * @return
+ * 0 on success, negative otherwise.
+ */
+__rte_experimental
+int rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
+ enum rte_node_ip6_lookup_next next_node);
+
+/**
+ * Add a next hop's rewrite data.
+ *
+ * @param next_hop
+ * Next hop id to add rewrite data to.
+ * @param rewrite_data
+ * Rewrite data.
+ * @param rewrite_len
+ * Length of rewrite data.
+ * @param dst_port
+ * Destination port to redirect traffic to.
+ *
+ * @return
+ * 0 on success, negative otherwise.
+ */
+__rte_experimental
+int rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
+ uint8_t rewrite_len, uint16_t dst_port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_NODE_IP6_API_H__ */
diff --git a/lib/node/version.map b/lib/node/version.map
index a799b0d389..40df308bfe 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -4,6 +4,8 @@ EXPERIMENTAL {
rte_node_eth_config;
rte_node_ip4_route_add;
rte_node_ip4_rewrite_add;
+ rte_node_ip6_rewrite_add;
+ rte_node_ip6_route_add;
rte_node_logtype;
local: *;
};
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 2/3] lib: add IPv6 rewrite node
2023-05-18 15:56 ` [PATCH v2 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
@ 2023-05-18 15:56 ` Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
` (2 subsequent siblings)
3 siblings, 0 replies; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-05-18 15:56 UTC (permalink / raw)
To: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh
Cc: dev, skori, Amit Prakash Shukla
Similar to IPv4 rewrite node, patch adds IPv6 rewrite node.
Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Performance related changes
doc/guides/prog_guide/graph_lib.rst | 8 +
lib/node/ethdev_ctrl.c | 13 ++
lib/node/ip6_rewrite.c | 331 ++++++++++++++++++++++++++++
lib/node/ip6_rewrite_priv.h | 69 ++++++
lib/node/meson.build | 1 +
5 files changed, 422 insertions(+)
create mode 100644 lib/node/ip6_rewrite.c
create mode 100644 lib/node/ip6_rewrite_priv.h
diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
index 1f70d63628..841cabe259 100644
--- a/doc/guides/prog_guide/graph_lib.rst
+++ b/doc/guides/prog_guide/graph_lib.rst
@@ -401,6 +401,14 @@ On LPM lookup failure, objects are redirected to pkt_drop node.
To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
sections.
+ip6_rewrite
+~~~~~~~~~~~
+This node gets packets from ``ip6_lookup`` node with next-hop id for each
+packet is embedded in ``node_mbuf_priv1(mbuf)->nh``. This id is used
+to determine the L2 header to be written to the packet before sending
+the packet out to a particular ethdev_tx node.
+``rte_node_ip6_rewrite_add()`` is control path API to add next-hop info.
+
null
~~~~
This node ignores the set of objects passed to it and reports that all are
diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index 37df0431b8..ea7dc8210b 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -12,6 +12,7 @@
#include "ethdev_rx_priv.h"
#include "ethdev_tx_priv.h"
#include "ip4_rewrite_priv.h"
+#include "ip6_rewrite_priv.h"
#include "node_private.h"
static struct ethdev_ctrl {
@@ -23,6 +24,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
uint16_t nb_graphs)
{
struct rte_node_register *ip4_rewrite_node;
+ struct rte_node_register *ip6_rewrite_node;
struct ethdev_tx_node_main *tx_node_data;
uint16_t tx_q_used, rx_q_used, port_id;
struct rte_node_register *tx_node;
@@ -33,6 +35,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
uint32_t id;
ip4_rewrite_node = ip4_rewrite_node_get();
+ ip6_rewrite_node = ip6_rewrite_node_get();
tx_node_data = ethdev_tx_node_data_get();
tx_node = ethdev_tx_node_get();
for (i = 0; i < nb_confs; i++) {
@@ -110,6 +113,16 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
port_id, rte_node_edge_count(ip4_rewrite_node->id) - 1);
if (rc < 0)
return rc;
+
+ /* Add this tx port node as next to ip6_rewrite_node */
+ rte_node_edge_update(ip6_rewrite_node->id, RTE_EDGE_ID_INVALID,
+ &next_nodes, 1);
+ /* Assuming edge id is the last one alloc'ed */
+ rc = ip6_rewrite_set_next(
+ port_id, rte_node_edge_count(ip6_rewrite_node->id) - 1);
+ if (rc < 0)
+ return rc;
+
}
ctrl.nb_graphs = nb_graphs;
diff --git a/lib/node/ip6_rewrite.c b/lib/node/ip6_rewrite.c
new file mode 100644
index 0000000000..0e9631c86f
--- /dev/null
+++ b/lib/node/ip6_rewrite.c
@@ -0,0 +1,331 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_ip.h>
+#include <rte_malloc.h>
+#include <rte_vect.h>
+
+#include "rte_node_ip6_api.h"
+
+#include "ip6_rewrite_priv.h"
+#include "node_private.h"
+
+struct ip6_rewrite_node_ctx {
+ /* Dynamic offset to mbuf priv1 */
+ int mbuf_priv1_off;
+ /* Cached next index */
+ uint16_t next_index;
+};
+
+static struct ip6_rewrite_node_main *ip6_rewrite_nm;
+
+#define IP6_REWRITE_NODE_LAST_NEXT(ctx) \
+ (((struct ip6_rewrite_node_ctx *)ctx)->next_index)
+
+#define IP6_REWRITE_NODE_PRIV1_OFF(ctx) \
+ (((struct ip6_rewrite_node_ctx *)ctx)->mbuf_priv1_off)
+
+static uint16_t
+ip6_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
+ void **objs, uint16_t nb_objs)
+{
+ struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
+ struct ip6_rewrite_nh_header *nh = ip6_rewrite_nm->nh;
+ const int dyn = IP6_REWRITE_NODE_PRIV1_OFF(node->ctx);
+ uint16_t next0, next1, next2, next3, next_index;
+ uint16_t n_left_from, held = 0, last_spec = 0;
+ struct rte_ipv6_hdr *ip0, *ip1, *ip2, *ip3;
+ void *d0, *d1, *d2, *d3;
+ void **to_next, **from;
+ rte_xmm_t priv01;
+ rte_xmm_t priv23;
+ int i;
+
+ /* Speculative next as last next */
+ next_index = IP6_REWRITE_NODE_LAST_NEXT(node->ctx);
+ rte_prefetch0(nh);
+
+ pkts = (struct rte_mbuf **)objs;
+ from = objs;
+ n_left_from = nb_objs;
+
+ for (i = 0; i < 4 && i < n_left_from; i++)
+ rte_prefetch0(pkts[i]);
+
+ /* Get stream for the speculated next node */
+ to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
+ /* Update Ethernet header of pkts */
+ while (n_left_from >= 4) {
+ if (likely(n_left_from > 7)) {
+ /* Prefetch only next-mbuf struct and priv area.
+ * Data need not be prefetched as we only write.
+ */
+ rte_prefetch0(pkts[4]);
+ rte_prefetch0(pkts[5]);
+ rte_prefetch0(pkts[6]);
+ rte_prefetch0(pkts[7]);
+ }
+
+ mbuf0 = pkts[0];
+ mbuf1 = pkts[1];
+ mbuf2 = pkts[2];
+ mbuf3 = pkts[3];
+
+ pkts += 4;
+ n_left_from -= 4;
+ priv01.u64[0] = node_mbuf_priv1(mbuf0, dyn)->u;
+ priv01.u64[1] = node_mbuf_priv1(mbuf1, dyn)->u;
+ priv23.u64[0] = node_mbuf_priv1(mbuf2, dyn)->u;
+ priv23.u64[1] = node_mbuf_priv1(mbuf3, dyn)->u;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf0 */
+ d0 = rte_pktmbuf_mtod(mbuf0, void *);
+ rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,
+ nh[priv01.u16[0]].rewrite_len);
+
+ next0 = nh[priv01.u16[0]].tx_node;
+ ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
+ sizeof(struct rte_ether_hdr));
+ ip0->hop_limits = priv01.u16[1] - 1;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf1 */
+ d1 = rte_pktmbuf_mtod(mbuf1, void *);
+ rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,
+ nh[priv01.u16[4]].rewrite_len);
+
+ next1 = nh[priv01.u16[4]].tx_node;
+ ip1 = (struct rte_ipv6_hdr *)((uint8_t *)d1 +
+ sizeof(struct rte_ether_hdr));
+ ip1->hop_limits = priv01.u16[5] - 1;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf2 */
+ d2 = rte_pktmbuf_mtod(mbuf2, void *);
+ rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,
+ nh[priv23.u16[0]].rewrite_len);
+ next2 = nh[priv23.u16[0]].tx_node;
+ ip2 = (struct rte_ipv6_hdr *)((uint8_t *)d2 +
+ sizeof(struct rte_ether_hdr));
+ ip2->hop_limits = priv23.u16[1] - 1;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf3 */
+ d3 = rte_pktmbuf_mtod(mbuf3, void *);
+ rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,
+ nh[priv23.u16[4]].rewrite_len);
+
+ next3 = nh[priv23.u16[4]].tx_node;
+ ip3 = (struct rte_ipv6_hdr *)((uint8_t *)d3 +
+ sizeof(struct rte_ether_hdr));
+ ip3->hop_limits = priv23.u16[5] - 1;
+
+ /* Enqueue four packets to next node */
+ rte_edge_t fix_spec =
+ ((next_index == next0) && (next0 == next1) &&
+ (next1 == next2) && (next2 == next3));
+
+ if (unlikely(fix_spec == 0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ /* next0 */
+ if (next_index == next0) {
+ to_next[0] = from[0];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next0,
+ from[0]);
+ }
+
+ /* next1 */
+ if (next_index == next1) {
+ to_next[0] = from[1];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next1,
+ from[1]);
+ }
+
+ /* next2 */
+ if (next_index == next2) {
+ to_next[0] = from[2];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next2,
+ from[2]);
+ }
+
+ /* next3 */
+ if (next_index == next3) {
+ to_next[0] = from[3];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next3,
+ from[3]);
+ }
+
+ from += 4;
+
+ /* Change speculation if last two are same */
+ if ((next_index != next3) && (next2 == next3)) {
+ /* Put the current speculated node */
+ rte_node_next_stream_put(graph, node,
+ next_index, held);
+ held = 0;
+
+ /* Get next speculated stream */
+ next_index = next3;
+ to_next = rte_node_next_stream_get(
+ graph, node, next_index, nb_objs);
+ }
+ } else {
+ last_spec += 4;
+ }
+ }
+
+ while (n_left_from > 0) {
+ mbuf0 = pkts[0];
+
+ pkts += 1;
+ n_left_from -= 1;
+
+ d0 = rte_pktmbuf_mtod(mbuf0, void *);
+ rte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,
+ nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);
+
+ next0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node;
+ ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
+ sizeof(struct rte_ether_hdr));
+ ip0->hop_limits = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;
+
+ if (unlikely(next_index ^ next0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ rte_node_enqueue_x1(graph, node, next0, from[0]);
+ from += 1;
+ } else {
+ last_spec += 1;
+ }
+ }
+
+ /* !!! Home run !!! */
+ if (likely(last_spec == nb_objs)) {
+ rte_node_next_stream_move(graph, node, next_index);
+ return nb_objs;
+ }
+
+ held += last_spec;
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ rte_node_next_stream_put(graph, node, next_index, held);
+ /* Save the last next used */
+ IP6_REWRITE_NODE_LAST_NEXT(node->ctx) = next_index;
+
+ return nb_objs;
+}
+
+static int
+ip6_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
+{
+ static bool init_once;
+
+ RTE_SET_USED(graph);
+ RTE_BUILD_BUG_ON(sizeof(struct ip6_rewrite_node_ctx) > RTE_NODE_CTX_SZ);
+
+ if (!init_once) {
+ ip6_node_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register(
+ &node_mbuf_priv1_dynfield_desc);
+ if (ip6_node_mbuf_priv1_dynfield_offset < 0)
+ return -rte_errno;
+ init_once = true;
+ }
+ IP6_REWRITE_NODE_PRIV1_OFF(node->ctx) = ip6_node_mbuf_priv1_dynfield_offset;
+
+ node_dbg("ip6_rewrite", "Initialized ip6_rewrite node");
+
+ return 0;
+}
+
+int
+ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index)
+{
+ if (ip6_rewrite_nm == NULL) {
+ ip6_rewrite_nm = rte_zmalloc(
+ "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
+ RTE_CACHE_LINE_SIZE);
+ if (ip6_rewrite_nm == NULL)
+ return -ENOMEM;
+ }
+ ip6_rewrite_nm->next_index[port_id] = next_index;
+
+ return 0;
+}
+
+int
+rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
+ uint8_t rewrite_len, uint16_t dst_port)
+{
+ struct ip6_rewrite_nh_header *nh;
+
+ if (next_hop >= RTE_GRAPH_IP6_REWRITE_MAX_NH)
+ return -EINVAL;
+
+ if (rewrite_len > RTE_GRAPH_IP6_REWRITE_MAX_LEN)
+ return -EINVAL;
+
+ if (ip6_rewrite_nm == NULL) {
+ ip6_rewrite_nm = rte_zmalloc(
+ "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
+ RTE_CACHE_LINE_SIZE);
+ if (ip6_rewrite_nm == NULL)
+ return -ENOMEM;
+ }
+
+ /* Check if dst port doesn't exist as edge */
+ if (!ip6_rewrite_nm->next_index[dst_port])
+ return -EINVAL;
+
+ /* Update next hop */
+ nh = &ip6_rewrite_nm->nh[next_hop];
+
+ memcpy(nh->rewrite_data, rewrite_data, rewrite_len);
+ nh->tx_node = ip6_rewrite_nm->next_index[dst_port];
+ nh->rewrite_len = rewrite_len;
+ nh->enabled = true;
+
+ return 0;
+}
+
+static struct rte_node_register ip6_rewrite_node = {
+ .process = ip6_rewrite_node_process,
+ .name = "ip6_rewrite",
+ /* Default edge i.e '0' is pkt drop */
+ .nb_edges = 1,
+ .next_nodes = {
+ [0] = "pkt_drop",
+ },
+ .init = ip6_rewrite_node_init,
+};
+
+struct rte_node_register *
+ip6_rewrite_node_get(void)
+{
+ return &ip6_rewrite_node;
+}
+
+RTE_NODE_REGISTER(ip6_rewrite_node);
diff --git a/lib/node/ip6_rewrite_priv.h b/lib/node/ip6_rewrite_priv.h
new file mode 100644
index 0000000000..93db28bec0
--- /dev/null
+++ b/lib/node/ip6_rewrite_priv.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+#ifndef __INCLUDE_IP6_REWRITE_PRIV_H__
+#define __INCLUDE_IP6_REWRITE_PRIV_H__
+
+#include <rte_common.h>
+
+#define RTE_GRAPH_IP6_REWRITE_MAX_NH 64
+#define RTE_GRAPH_IP6_REWRITE_MAX_LEN 56
+
+/**
+ * @internal
+ *
+ * Ipv6 rewrite next hop header data structure. Used to store port specific
+ * rewrite data.
+ */
+struct ip6_rewrite_nh_header {
+ uint16_t rewrite_len; /**< Header rewrite length. */
+ uint16_t tx_node; /**< Tx node next index identifier. */
+ uint16_t enabled; /**< NH enable flag */
+ uint16_t rsvd;
+ union {
+ struct {
+ struct rte_ether_addr dst;
+ /**< Destination mac address. */
+ struct rte_ether_addr src;
+ /**< Source mac address. */
+ };
+ uint8_t rewrite_data[RTE_GRAPH_IP6_REWRITE_MAX_LEN];
+ /**< Generic rewrite data */
+ };
+};
+
+/**
+ * @internal
+ *
+ * Ipv6 node main data structure.
+ */
+struct ip6_rewrite_node_main {
+ struct ip6_rewrite_nh_header nh[RTE_GRAPH_IP6_REWRITE_MAX_NH];
+ /**< Array of next hop header data */
+ uint16_t next_index[RTE_MAX_ETHPORTS];
+ /**< Next index of each configured port. */
+};
+
+/**
+ * @internal
+ *
+ * Get the ipv6 rewrite node.
+ *
+ * @return
+ * Pointer to the ipv6 rewrite node.
+ */
+struct rte_node_register *ip6_rewrite_node_get(void);
+
+/**
+ * @internal
+ *
+ * Set the Edge index of a given port_id.
+ *
+ * @param port_id
+ * Ethernet port identifier.
+ * @param next_index
+ * Edge index of the Given Tx node.
+ */
+int ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index);
+
+#endif /* __INCLUDE_IP6_REWRITE_PRIV_H__ */
diff --git a/lib/node/meson.build b/lib/node/meson.build
index cd30847a0b..b2f04269c5 100644
--- a/lib/node/meson.build
+++ b/lib/node/meson.build
@@ -14,6 +14,7 @@ sources = files(
'ip4_lookup.c',
'ip6_lookup.c',
'ip4_rewrite.c',
+ 'ip6_rewrite.c',
'log.c',
'null.c',
'pkt_cls.c',
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support
2023-05-18 15:56 ` [PATCH v2 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
@ 2023-05-18 15:56 ` Amit Prakash Shukla
2023-05-22 5:49 ` Sunil Kumar Kori
2023-05-30 8:51 ` [PATCH v2 1/3] lib: add IPv6 lookup node Nithin Dabilpuram
2023-05-31 11:37 ` [PATCH v3 " Amit Prakash Shukla
3 siblings, 1 reply; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-05-18 15:56 UTC (permalink / raw)
To: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram
Cc: dev, skori, Amit Prakash Shukla
From: Sunil Kumar Kori <skori@marvell.com>
Similar to ipv4, to support IPv6 lookup and rewrite node
routes and rewrite data needs to be added.
Patch adds routes for ipv6 to validate ip6_lookup node
and rewrite data to validate ip6_rewrite node.
Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Performance related changes
doc/guides/sample_app_ug/l3_forward_graph.rst | 40 ++++++----
examples/l3fwd-graph/main.c | 77 ++++++++++++++++++-
2 files changed, 98 insertions(+), 19 deletions(-)
diff --git a/doc/guides/sample_app_ug/l3_forward_graph.rst b/doc/guides/sample_app_ug/l3_forward_graph.rst
index 585ac8c898..23f86e4785 100644
--- a/doc/guides/sample_app_ug/l3_forward_graph.rst
+++ b/doc/guides/sample_app_ug/l3_forward_graph.rst
@@ -12,7 +12,8 @@ Overview
--------
The application demonstrates the use of the graph framework and graph nodes
-``ethdev_rx``, ``ip4_lookup``, ``ip4_rewrite``, ``ethdev_tx`` and ``pkt_drop`` in DPDK to
+``ethdev_rx``, ``pkt_cls``, ``ip4_lookup``/``ip6_lookup``,
+``ip4_rewrite``/``ip6_rewrite``, ``ethdev_tx`` and ``pkt_drop`` in DPDK to
implement packet forwarding.
The initialization is very similar to those of the :doc:`l3_forward`.
@@ -24,13 +25,15 @@ TTL update and finally Tx is implemented inside graph nodes. These nodes are
interconnected in graph framework. Application main loop needs to walk over
graph using ``rte_graph_walk()`` with graph objects created one per worker lcore.
-The lookup method is as per implementation of ``ip4_lookup`` graph node.
+The lookup method is as per implementation of ``ip4_lookup``/``ip6_lookup`` graph node.
The ID of the output interface for the input packet is the next hop returned by
the LPM lookup. The set of LPM rules used by the application is statically
-configured and provided to ``ip4_lookup`` graph node and ``ip4_rewrite`` graph node
-using node control API ``rte_node_ip4_route_add()`` and ``rte_node_ip4_rewrite_add()``.
+configured and provided to ``ip4_lookup``/``ip6_lookup`` graph node and
+``ip4_rewrite``/``ip6_rewrite`` graph node using node control API
+``rte_node_ip4_route_add()``/``rte_node_ip6_route_add`` and
+``rte_node_ip4_rewrite_add()``/``rte_node_ip6_rewrite_add``.
-In the sample application, only IPv4 forwarding is supported as of now.
+In the sample application, IPv4 and IPv6 forwarding is supported.
Compiling the Application
-------------------------
@@ -149,8 +152,8 @@ lead to the clone of ``ethdev_rx`` and ``ethdev_tx`` nodes as ``ethdev_rx-X-Y``
In case of ``ethdev_tx-X`` nodes, tx queue id assigned per instance of the node
is same as graph id.
-These cloned nodes along with existing static nodes such as ``ip4_lookup`` and
-``ip4_rewrite`` will be used in graph creation to associate node's to lcore
+These cloned nodes along with existing static nodes such as ``ip4_lookup``/``ip6_lookup``
+and ``ip4_rewrite``/``ip6_rewrite`` will be used in graph creation to associate node's to lcore
specific graph object.
.. literalinclude:: ../../../examples/l3fwd-graph/main.c
@@ -186,20 +189,21 @@ Forwarding data(Route, Next-Hop) addition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once graph objects are created, node specific info like routes and rewrite
-headers will be provided run-time using ``rte_node_ip4_route_add()`` and
-``rte_node_ip4_rewrite_add()`` API.
+headers will be provided run-time using ``rte_node_ip4_route_add()``/
+``rte_node_ip6_route_add`` and ``rte_node_ip4_rewrite_add()``/``rte_node_ip6_rewrite_add``
+API.
.. note::
- Since currently ``ip4_lookup`` and ``ip4_rewrite`` nodes don't support
- lock-less mechanisms(RCU, etc) to add run-time forwarding data like route and
- rewrite data, forwarding data is added before packet processing loop is
- launched on worker lcore.
+ Since currently ``ip4_lookup``/``ip6_lookup`` and ``ip4_rewrite``/``ip6_rewrite``
+ nodes don't support lock-less mechanisms(RCU, etc) to add run-time forwarding
+ data like route and rewrite data, forwarding data is added before packet
+ processing loop is launched on worker lcore.
.. literalinclude:: ../../../examples/l3fwd-graph/main.c
:language: c
- :start-after: Add route to ip4 graph infra. 8<
- :end-before: >8 End of adding route to ip4 graph infa.
+ :start-after: Add routes and rewrite data to graph infra. 8<
+ :end-before: >8 End of adding routes and rewrite data to graph infa.
:dedent: 1
Packet Forwarding using Graph Walk
@@ -215,8 +219,10 @@ specific graph object that was already created.
rte_graph_walk() will walk over all the sources nodes i.e ``ethdev_rx-X-Y``
associated with a given graph and Rx the available packets and enqueue them
- to the following node ``ip4_lookup`` which then will enqueue them to ``ip4_rewrite``
- node if LPM lookup succeeds. ``ip4_rewrite`` node then will update Ethernet header
+ to the following node ``pkt_cls`` which based on the packet type will enqueue
+ them to ``ip4_lookup``/``ip6_lookup`` which then will enqueue them to
+ ``ip4_rewrite``/``ip6_rewrite`` node if LPM lookup succeeds.
+ ``ip4_rewrite``/``ip6_rewrite`` node then will update Ethernet header
as per next-hop data and transmit the packet via port 'Z' by enqueuing
to ``ethdev_tx-Z`` node instance in its graph object.
diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c
index 5feeab4f0f..0c82e24513 100644
--- a/examples/l3fwd-graph/main.c
+++ b/examples/l3fwd-graph/main.c
@@ -27,9 +27,11 @@
#include <rte_launch.h>
#include <rte_lcore.h>
#include <rte_log.h>
+#include <rte_lpm6.h>
#include <rte_mempool.h>
#include <rte_node_eth_api.h>
#include <rte_node_ip4_api.h>
+#include <rte_node_ip6_api.h>
#include <rte_per_lcore.h>
#include <rte_string_fns.h>
#include <rte_vect.h>
@@ -142,6 +144,12 @@ struct ipv4_l3fwd_lpm_route {
uint8_t if_out;
};
+struct ipv6_l3fwd_lpm_route {
+ uint8_t ip[RTE_LPM6_IPV6_ADDR_SIZE];
+ uint8_t depth;
+ uint8_t if_out;
+};
+
#define IPV4_L3FWD_LPM_NUM_ROUTES \
(sizeof(ipv4_l3fwd_lpm_route_array) / \
sizeof(ipv4_l3fwd_lpm_route_array[0]))
@@ -153,6 +161,28 @@ static struct ipv4_l3fwd_lpm_route ipv4_l3fwd_lpm_route_array[] = {
{RTE_IPV4(198, 18, 6, 0), 24, 6}, {RTE_IPV4(198, 18, 7, 0), 24, 7},
};
+#define IPV6_L3FWD_LPM_NUM_ROUTES \
+ (sizeof(ipv6_l3fwd_lpm_route_array) / \
+ sizeof(ipv6_l3fwd_lpm_route_array[0]))
+static struct ipv6_l3fwd_lpm_route ipv6_l3fwd_lpm_route_array[] = {
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00}, 48, 0},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01}, 48, 1},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02}, 48, 2},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03}, 48, 3},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04}, 48, 4},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05}, 48, 5},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06}, 48, 6},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02}, 48, 7},
+};
+
static int
check_lcore_params(void)
{
@@ -1128,7 +1158,7 @@ main(int argc, char **argv)
memset(&rewrite_data, 0, sizeof(rewrite_data));
rewrite_len = sizeof(rewrite_data);
- /* Add route to ip4 graph infra. 8< */
+ /* Add routes and rewrite data to graph infra. 8< */
for (i = 0; i < IPV4_L3FWD_LPM_NUM_ROUTES; i++) {
char route_str[INET6_ADDRSTRLEN * 4];
char abuf[INET6_ADDRSTRLEN];
@@ -1172,7 +1202,50 @@ main(int argc, char **argv)
RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n",
route_str, i);
}
- /* >8 End of adding route to ip4 graph infa. */
+
+ for (i = 0; i < IPV6_L3FWD_LPM_NUM_ROUTES; i++) {
+ char route_str[INET6_ADDRSTRLEN * 4];
+ char abuf[INET6_ADDRSTRLEN];
+ struct in6_addr in6;
+ uint32_t dst_port;
+
+ /* Skip unused ports */
+ if ((1 << ipv6_l3fwd_lpm_route_array[i].if_out &
+ enabled_port_mask) == 0)
+ continue;
+
+ dst_port = ipv6_l3fwd_lpm_route_array[i].if_out;
+
+ memcpy(in6.s6_addr, ipv6_l3fwd_lpm_route_array[i].ip, RTE_LPM6_IPV6_ADDR_SIZE);
+ snprintf(route_str, sizeof(route_str), "%s / %d (%d)",
+ inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf)),
+ ipv6_l3fwd_lpm_route_array[i].depth,
+ ipv6_l3fwd_lpm_route_array[i].if_out);
+
+ /* Use route index 'i' as next hop id */
+ ret = rte_node_ip6_route_add(ipv6_l3fwd_lpm_route_array[i].ip,
+ ipv6_l3fwd_lpm_route_array[i].depth, i,
+ RTE_NODE_IP6_LOOKUP_NEXT_REWRITE);
+
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "Unable to add ip6 route %s to graph\n",
+ route_str);
+
+ memcpy(rewrite_data, val_eth + dst_port, rewrite_len);
+
+ /* Add next hop rewrite data for id 'i' */
+ ret = rte_node_ip6_rewrite_add(i, rewrite_data,
+ rewrite_len, dst_port);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "Unable to add next hop %u for "
+ "route %s\n", i, route_str);
+
+ RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n",
+ route_str, i);
+ }
+ /* >8 End of adding routes and rewrite data to graph infa. */
/* Launch per-lcore init on every worker lcore */
rte_eal_mp_remote_launch(graph_main_loop, NULL, SKIP_MAIN);
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support
2023-05-18 15:56 ` [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
@ 2023-05-22 5:49 ` Sunil Kumar Kori
2023-05-29 6:27 ` Sunil Kumar Kori
0 siblings, 1 reply; 18+ messages in thread
From: Sunil Kumar Kori @ 2023-05-22 5:49 UTC (permalink / raw)
To: Amit Prakash Shukla, Jerin Jacob Kollanukkaran,
Kiran Kumar Kokkilagadda, Nithin Kumar Dabilpuram
Cc: dev, Amit Prakash Shukla
Hi Amit,
Please look into build failure.
http://mails.dpdk.org/archives/test-report/2023-May/396241.html
Thanks & Regards
Sunil Kumar Kori
> -----Original Message-----
> From: Amit Prakash Shukla <amitprakashs@marvell.com>
> Sent: Thursday, May 18, 2023 9:27 PM
> To: Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Kiran Kumar
> Kokkilagadda <kirankumark@marvell.com>; Nithin Kumar Dabilpuram
> <ndabilpuram@marvell.com>
> Cc: dev@dpdk.org; Sunil Kumar Kori <skori@marvell.com>; Amit Prakash
> Shukla <amitprakashs@marvell.com>
> Subject: [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite
> support
>
> From: Sunil Kumar Kori <skori@marvell.com>
>
> Similar to ipv4, to support IPv6 lookup and rewrite node routes and rewrite
> data needs to be added.
>
> Patch adds routes for ipv6 to validate ip6_lookup node and rewrite data to
> validate ip6_rewrite node.
>
> Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
> v2:
> - Performance related changes
>
> doc/guides/sample_app_ug/l3_forward_graph.rst | 40 ++++++----
> examples/l3fwd-graph/main.c | 77 ++++++++++++++++++-
> 2 files changed, 98 insertions(+), 19 deletions(-)
>
[snipped]
> 2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support
2023-05-22 5:49 ` Sunil Kumar Kori
@ 2023-05-29 6:27 ` Sunil Kumar Kori
0 siblings, 0 replies; 18+ messages in thread
From: Sunil Kumar Kori @ 2023-05-29 6:27 UTC (permalink / raw)
To: Amit Prakash Shukla
Cc: dev, Jerin Jacob Kollanukkaran, Kiran Kumar Kokkilagadda,
Nithin Kumar Dabilpuram
Hi Amit,
Did you get time to check build error mentioned in previous mail ?
Regards
Sunil Kumar Kori
> -----Original Message-----
> From: Sunil Kumar Kori <skori@marvell.com>
> Sent: Monday, May 22, 2023 11:20 AM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>; Jerin Jacob
> Kollanukkaran <jerinj@marvell.com>; Kiran Kumar Kokkilagadda
> <kirankumark@marvell.com>; Nithin Kumar Dabilpuram
> <ndabilpuram@marvell.com>
> Cc: dev@dpdk.org; Amit Prakash Shukla <amitprakashs@marvell.com>
> Subject: [EXT] RE: [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup
> and rewrite support
>
> External Email
>
> ----------------------------------------------------------------------
> Hi Amit,
>
> Please look into build failure.
> https://urldefense.proofpoint.com/v2/url?u=http-
> 3A__mails.dpdk.org_archives_test-2Dreport_2023-
> 2DMay_396241.html&d=DwIFAg&c=nKjWec2b6R0mOyPaz7xtfQ&r=dXeXaAM
> kP5COgn1zxHMyaF1_d9IIuq6vHQO6NrIPjaE&m=zTb1-
> _jN4zpc1HXoemLgQSj9JDAgE3vn-
> Cw_LdW29znc70FYi75BnYGNMN2PwaGj&s=uLOxl_GycqIBg3mdoxkQ9I0zuCK
> QzKkdoXvi-FOW9gA&e=
>
> Thanks & Regards
> Sunil Kumar Kori
>
> > -----Original Message-----
> > From: Amit Prakash Shukla <amitprakashs@marvell.com>
> > Sent: Thursday, May 18, 2023 9:27 PM
> > To: Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Kiran Kumar
> > Kokkilagadda <kirankumark@marvell.com>; Nithin Kumar Dabilpuram
> > <ndabilpuram@marvell.com>
> > Cc: dev@dpdk.org; Sunil Kumar Kori <skori@marvell.com>; Amit Prakash
> > Shukla <amitprakashs@marvell.com>
> > Subject: [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup and
> > rewrite support
> >
> > From: Sunil Kumar Kori <skori@marvell.com>
> >
> > Similar to ipv4, to support IPv6 lookup and rewrite node routes and
> > rewrite data needs to be added.
> >
> > Patch adds routes for ipv6 to validate ip6_lookup node and rewrite
> > data to validate ip6_rewrite node.
> >
> > Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
> > Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> > ---
> > v2:
> > - Performance related changes
> >
> > doc/guides/sample_app_ug/l3_forward_graph.rst | 40 ++++++----
> > examples/l3fwd-graph/main.c | 77 ++++++++++++++++++-
> > 2 files changed, 98 insertions(+), 19 deletions(-)
> >
>
> [snipped]
>
> > 2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v2 1/3] lib: add IPv6 lookup node
2023-05-18 15:56 ` [PATCH v2 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
@ 2023-05-30 8:51 ` Nithin Dabilpuram
2023-05-31 11:37 ` [PATCH v3 " Amit Prakash Shukla
3 siblings, 0 replies; 18+ messages in thread
From: Nithin Dabilpuram @ 2023-05-30 8:51 UTC (permalink / raw)
To: Amit Prakash Shukla
Cc: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh,
dev, skori
On Thu, May 18, 2023 at 9:27 PM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
>
> From: Sunil Kumar Kori <skori@marvell.com>
>
> Similar to IPv4 lookup node, patch adds IPv6 lookup
> node.
>
> Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
> v2:
> - Performance related changes
>
> doc/guides/prog_guide/graph_lib.rst | 13 +
> lib/node/ip6_lookup.c | 374 ++++++++++++++++++++++++++++
> lib/node/meson.build | 3 +-
> lib/node/node_private.h | 3 +-
> lib/node/pkt_cls.c | 14 ++
> lib/node/pkt_cls_priv.h | 1 +
> lib/node/rte_node_ip6_api.h | 80 ++++++
> lib/node/version.map | 2 +
> 8 files changed, 488 insertions(+), 2 deletions(-)
> create mode 100644 lib/node/ip6_lookup.c
> create mode 100644 lib/node/rte_node_ip6_api.h
>
> diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
> index 1cfdc86433..1f70d63628 100644
> --- a/doc/guides/prog_guide/graph_lib.rst
> +++ b/doc/guides/prog_guide/graph_lib.rst
> @@ -388,6 +388,19 @@ 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.
>
> +ip6_lookup
> +~~~~~~~~~~
> +This node is an intermediate node that does LPM lookup for the received
> +ipv6 packets and the result determines each packets next node.
> +
> +On successful LPM lookup, the result contains the ``next_node`` id and
> +``next-hop`` id with which the packet needs to be further processed.
> +
> +On LPM lookup failure, objects are redirected to pkt_drop node.
> +``rte_node_ip6_route_add()`` is control path API to add ipv6 routes.
> +To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
> +sections.
> +
> null
> ~~~~
> This node ignores the set of objects passed to it and reports that all are
> diff --git a/lib/node/ip6_lookup.c b/lib/node/ip6_lookup.c
> new file mode 100644
> index 0000000000..a377c06072
> --- /dev/null
> +++ b/lib/node/ip6_lookup.c
> @@ -0,0 +1,374 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(C) 2023 Marvell.
> + */
> +
> +#include <arpa/inet.h>
> +#include <sys/socket.h>
> +
> +#include <rte_ethdev.h>
> +#include <rte_ether.h>
> +#include <rte_graph.h>
> +#include <rte_graph_worker.h>
> +#include <rte_ip.h>
> +#include <rte_lpm6.h>
> +
> +#include "rte_node_ip6_api.h"
> +
> +#include "node_private.h"
> +
> +#define IPV6_L3FWD_LPM_MAX_RULES 1024
> +#define IPV6_L3FWD_LPM_NUMBER_TBL8S (1 << 8)
> +
> +/* IP6 Lookup global data struct */
> +struct ip6_lookup_node_main {
> + struct rte_lpm6 *lpm_tbl[RTE_MAX_NUMA_NODES];
> +};
> +
> +struct ip6_lookup_node_ctx {
> + /* Socket's LPM table */
> + struct rte_lpm6 *lpm6;
> + /* Dynamic offset to mbuf priv1 */
> + int mbuf_priv1_off;
> +};
> +
> +int ip6_node_mbuf_priv1_dynfield_offset = -1;
> +
> +static struct ip6_lookup_node_main ip6_lookup_nm;
> +
> +#define IP6_LOOKUP_NODE_LPM(ctx) \
> + (((struct ip6_lookup_node_ctx *)ctx)->lpm6)
> +
> +#define IP6_LOOKUP_NODE_PRIV1_OFF(ctx) \
> + (((struct ip6_lookup_node_ctx *)ctx)->mbuf_priv1_off)
> +
> +static uint16_t
> +ip6_lookup_node_process_scalar(struct rte_graph *graph, struct rte_node *node,
> + void **objs, uint16_t nb_objs)
> +{
> + struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
> + struct rte_lpm6 *lpm6 = IP6_LOOKUP_NODE_LPM(node->ctx);
> + const int dyn = IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx);
> + struct rte_ipv6_hdr *ipv6_hdr;
> + void **to_next, **from;
> + uint16_t last_spec = 0;
> + rte_edge_t next_index;
> + uint16_t n_left_from;
> + uint16_t held = 0;
> + uint32_t drop_nh;
> + int i, rc;
> +
> + /* Speculative next */
> + next_index = RTE_NODE_IP6_LOOKUP_NEXT_REWRITE;
> + /* Drop node */
> + drop_nh = ((uint32_t)RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP) << 16;
> +
> + pkts = (struct rte_mbuf **)objs;
> + from = objs;
> + n_left_from = nb_objs;
> +
> + for (i = OBJS_PER_CLINE; i < RTE_GRAPH_BURST_SIZE; i += OBJS_PER_CLINE)
> + rte_prefetch0(&objs[i]);
> +
> + for (i = 0; i < 4 && i < n_left_from; i++)
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[i], void *,
> + sizeof(struct rte_ether_hdr)));
> +
> + /* Get stream for the speculated next node */
> + to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
> + while (n_left_from >= 4) {
> +#if RTE_GRAPH_BURST_SIZE > 64
> + /* Prefetch next-next mbufs */
> + if (likely(n_left_from > 11)) {
> + rte_prefetch0(pkts[8]);
> + rte_prefetch0(pkts[9]);
> + rte_prefetch0(pkts[10]);
> + rte_prefetch0(pkts[11]);
> + }
> +#endif
> + /* Prefetch next mbuf data */
> + if (likely(n_left_from > 7)) {
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[4], void *,
> + sizeof(struct rte_ether_hdr)));
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[5], void *,
> + sizeof(struct rte_ether_hdr)));
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[6], void *,
> + sizeof(struct rte_ether_hdr)));
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[7], void *,
> + sizeof(struct rte_ether_hdr)));
> + }
> +
> + mbuf0 = pkts[0];
> + mbuf1 = pkts[1];
> + mbuf2 = pkts[2];
> + mbuf3 = pkts[3];
> +
> + pkts += 4;
> + n_left_from -= 4;
> +
> + uint8_t ip_batch[4][16];
> + int32_t next_hop[4];
> + uint16_t next[4];
Can you move these variables to beginning of scope
> +
> + /* Extract DIP of mbuf0 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract hop_limits as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
> + rte_memcpy(ip_batch[0], ipv6_hdr->dst_addr, 16);
> +
> + /* Extract DIP of mbuf1 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf1, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract hop_limits as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf1, dyn)->ttl = ipv6_hdr->hop_limits;
> + rte_memcpy(ip_batch[1], ipv6_hdr->dst_addr, 16);
> +
> + /* Extract DIP of mbuf2 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf2, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract hop_limits as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf2, dyn)->ttl = ipv6_hdr->hop_limits;
> + rte_memcpy(ip_batch[2], ipv6_hdr->dst_addr, 16);
> +
> + /* Extract DIP of mbuf3 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf3, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract hop_limits as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf3, dyn)->ttl = ipv6_hdr->hop_limits;
> + rte_memcpy(ip_batch[3], ipv6_hdr->dst_addr, 16);
> +
> + rc = rte_lpm6_lookup_bulk_func(lpm6, ip_batch, next_hop, 4);
> +
> + next_hop[0] = (next_hop[0] < 0) ? (int32_t)drop_nh : next_hop[0];
> + node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop[0];
> + next[0] = (uint16_t)(next_hop[0] >> 16);
> +
> + next_hop[1] = (next_hop[1] < 0) ? (int32_t)drop_nh : next_hop[1];
> + node_mbuf_priv1(mbuf1, dyn)->nh = (uint16_t)next_hop[1];
> + next[1] = (uint16_t)(next_hop[1] >> 16);
> +
> + next_hop[2] = (next_hop[2] < 0) ? (int32_t)drop_nh : next_hop[2];
> + node_mbuf_priv1(mbuf2, dyn)->nh = (uint16_t)next_hop[2];
> + next[2] = (uint16_t)(next_hop[2] >> 16);
> +
> + next_hop[3] = (next_hop[3] < 0) ? (int32_t)drop_nh : next_hop[3];
> + node_mbuf_priv1(mbuf3, dyn)->nh = (uint16_t)next_hop[3];
> + next[3] = (uint16_t)(next_hop[3] >> 16);
> +
> + rte_edge_t fix_spec = ((next_index == next[0]) &&
> + (next_index == next[1]) &&
> + (next_index == next[2]) &&
> + (next_index == next[3]));
> +
> + if (unlikely(fix_spec == 0)) {
> + /* Copy things successfully speculated till now */
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + from += last_spec;
> + to_next += last_spec;
> + held += last_spec;
> + last_spec = 0;
> +
> + /* Next0 */
> + if (next_index == next[0]) {
> + to_next[0] = from[0];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next[0], from[0]);
> + }
> +
> + /* Next1 */
> + if (next_index == next[1]) {
> + to_next[0] = from[1];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next[1], from[1]);
> + }
> +
> + /* Next2 */
> + if (next_index == next[2]) {
> + to_next[0] = from[2];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next[2], from[2]);
> + }
> +
> + /* Next3 */
> + if (next_index == next[3]) {
> + to_next[0] = from[3];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next[3], from[3]);
> + }
> +
> + from += 4;
> + } else {
> + last_spec += 4;
> + }
> + }
> +
> + while (n_left_from > 0) {
> + uint32_t next_hop;
> + uint16_t next0;
> +
> + mbuf0 = pkts[0];
> +
> + pkts += 1;
> + n_left_from -= 1;
> +
> + /* Extract DIP of mbuf0 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract ttl as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
> +
> + rc = rte_lpm6_lookup(lpm6, ipv6_hdr->dst_addr, &next_hop);
> + next_hop = (rc == 0) ? next_hop : drop_nh;
> +
> + node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop;
> + next_hop = next_hop >> 16;
> + next0 = (uint16_t)next_hop;
> +
> + if (unlikely(next_index ^ next0)) {
> + /* Copy things successfully speculated till now */
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + from += last_spec;
> + to_next += last_spec;
> + held += last_spec;
> + last_spec = 0;
> +
> + rte_node_enqueue_x1(graph, node, next0, from[0]);
> + from += 1;
> + } else {
> + last_spec += 1;
> + }
> + }
> +
> + /* !!! Home run !!! */
> + if (likely(last_spec == nb_objs)) {
> + rte_node_next_stream_move(graph, node, next_index);
> + return nb_objs;
> + }
> + held += last_spec;
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + rte_node_next_stream_put(graph, node, next_index, held);
> +
> + return nb_objs;
> +}
> +
> +int
> +rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
> + enum rte_node_ip6_lookup_next next_node)
> +{
> + char abuf[INET6_ADDRSTRLEN];
> + struct in6_addr in6;
> + uint8_t socket;
> + uint32_t val;
> + int ret;
> +
> + memcpy(in6.s6_addr, ip, RTE_LPM6_IPV6_ADDR_SIZE);
> + inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf));
> + /* Embedded next node id into 24 bit next hop */
> + val = ((next_node << 16) | next_hop) & ((1ull << 24) - 1);
> + node_dbg("ip6_lookup", "LPM: Adding route %s / %d nh (0x%x)", abuf,
> + depth, val);
> +
> + for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
> + if (!ip6_lookup_nm.lpm_tbl[socket])
> + continue;
> +
> + ret = rte_lpm6_add(ip6_lookup_nm.lpm_tbl[socket], ip, depth,
> + val);
> + if (ret < 0) {
> + node_err("ip6_lookup",
> + "Unable to add entry %s / %d nh (%x) to LPM "
> + "table on sock %d, rc=%d\n",
> + abuf, depth, val, socket, ret);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int
> +setup_lpm6(struct ip6_lookup_node_main *nm, int socket)
> +{
> + struct rte_lpm6_config config_ipv6;
> + char s[RTE_LPM6_NAMESIZE];
> +
> + /* One LPM table per socket */
> + if (nm->lpm_tbl[socket])
> + return 0;
> +
> + /* create the LPM table */
> + config_ipv6.max_rules = IPV6_L3FWD_LPM_MAX_RULES;
> + config_ipv6.number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S;
> + config_ipv6.flags = 0;
> + snprintf(s, sizeof(s), "IPV6_L3FWD_LPM_%d", socket);
> + nm->lpm_tbl[socket] = rte_lpm6_create(s, socket, &config_ipv6);
> + if (nm->lpm_tbl[socket] == NULL)
> + return -rte_errno;
> +
> + return 0;
> +}
> +
> +static int
> +ip6_lookup_node_init(const struct rte_graph *graph, struct rte_node *node)
> +{
> + uint16_t socket, lcore_id;
> + static uint8_t init_once;
> + int rc;
> +
> + RTE_SET_USED(graph);
> + RTE_BUILD_BUG_ON(sizeof(struct ip6_lookup_node_ctx) > RTE_NODE_CTX_SZ);
> +
> + if (!init_once) {
> + ip6_node_mbuf_priv1_dynfield_offset =
> + rte_mbuf_dynfield_register(
> + &node_mbuf_priv1_dynfield_desc);
You can use node_mbuf_priv1_dynfield_offset itself for this right
which is already extern instead of using another variable
ip6_node_mbuf_priv1_dynfield_offset ?
> + if (ip6_node_mbuf_priv1_dynfield_offset < 0)
> + return -rte_errno;
> +
> + /* Setup LPM tables for all sockets */
> + RTE_LCORE_FOREACH(lcore_id)
> + {
> + socket = rte_lcore_to_socket_id(lcore_id);
> + rc = setup_lpm6(&ip6_lookup_nm, socket);
> + if (rc) {
> + node_err("ip6_lookup",
> + "Failed to setup lpm6 tbl for "
> + "sock %u, rc=%d", socket, rc);
> + return rc;
> + }
> + }
> + init_once = 1;
> + }
> +
> + /* Update socket's LPM and mbuf dyn priv1 offset in node ctx */
> + IP6_LOOKUP_NODE_LPM(node->ctx) = ip6_lookup_nm.lpm_tbl[graph->socket];
> + IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx) =
> + ip6_node_mbuf_priv1_dynfield_offset;
> +
> + node_dbg("ip6_lookup", "Initialized ip6_lookup node");
> +
> + return 0;
> +}
> +
> +static struct rte_node_register ip6_lookup_node = {
> + .process = ip6_lookup_node_process_scalar,
> + .name = "ip6_lookup",
> +
> + .init = ip6_lookup_node_init,
> +
> + .nb_edges = RTE_NODE_IP6_LOOKUP_NEXT_MAX,
> + .next_nodes = {
> + [RTE_NODE_IP6_LOOKUP_NEXT_REWRITE] = "ip6_rewrite",
> + [RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP] = "pkt_drop",
> + },
> +};
> +
> +RTE_NODE_REGISTER(ip6_lookup_node);
> diff --git a/lib/node/meson.build b/lib/node/meson.build
> index dbdf673c86..cd30847a0b 100644
> --- a/lib/node/meson.build
> +++ b/lib/node/meson.build
> @@ -12,13 +12,14 @@ sources = files(
> 'ethdev_rx.c',
> 'ethdev_tx.c',
> 'ip4_lookup.c',
> + 'ip6_lookup.c',
> 'ip4_rewrite.c',
> 'log.c',
> 'null.c',
> 'pkt_cls.c',
> 'pkt_drop.c',
> )
> -headers = files('rte_node_ip4_api.h', 'rte_node_eth_api.h')
> +headers = files('rte_node_ip4_api.h', 'rte_node_ip6_api.h', 'rte_node_eth_api.h')
> # Strict-aliasing rules are violated by uint8_t[] to context size casts.
> cflags += '-fno-strict-aliasing'
> deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev']
> diff --git a/lib/node/node_private.h b/lib/node/node_private.h
> index 8c73d5dc10..27555cbfd8 100644
> --- a/lib/node/node_private.h
> +++ b/lib/node/node_private.h
> @@ -26,7 +26,7 @@ extern int rte_node_logtype;
> */
> struct node_mbuf_priv1 {
> union {
> - /* IP4 rewrite */
> + /* IP4/IP6 rewrite */
> struct {
> uint16_t nh;
> uint16_t ttl;
> @@ -43,6 +43,7 @@ static const struct rte_mbuf_dynfield node_mbuf_priv1_dynfield_desc = {
> .align = __alignof__(struct node_mbuf_priv1),
> };
> extern int node_mbuf_priv1_dynfield_offset;
> +extern int ip6_node_mbuf_priv1_dynfield_offset;
>
> /**
> * Node mbuf private area 2.
> diff --git a/lib/node/pkt_cls.c b/lib/node/pkt_cls.c
> index 3e75f2cf78..a8302b8d28 100644
> --- a/lib/node/pkt_cls.c
> +++ b/lib/node/pkt_cls.c
> @@ -24,6 +24,19 @@ static const uint8_t p_nxt[256] __rte_cache_aligned = {
>
> [RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
> PKT_CLS_NEXT_IP4_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6_EXT] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
> + PKT_CLS_NEXT_IP6_LOOKUP,
> };
>
> static uint16_t
> @@ -216,6 +229,7 @@ struct rte_node_register pkt_cls_node = {
> /* Pkt drop node starts at '0' */
> [PKT_CLS_NEXT_PKT_DROP] = "pkt_drop",
> [PKT_CLS_NEXT_IP4_LOOKUP] = "ip4_lookup",
> + [PKT_CLS_NEXT_IP6_LOOKUP] = "ip6_lookup",
> },
> };
> RTE_NODE_REGISTER(pkt_cls_node);
> diff --git a/lib/node/pkt_cls_priv.h b/lib/node/pkt_cls_priv.h
> index 6f5374f0be..16135807a1 100644
> --- a/lib/node/pkt_cls_priv.h
> +++ b/lib/node/pkt_cls_priv.h
> @@ -13,6 +13,7 @@ struct pkt_cls_node_ctx {
> enum pkt_cls_next_nodes {
> PKT_CLS_NEXT_PKT_DROP,
> PKT_CLS_NEXT_IP4_LOOKUP,
> + PKT_CLS_NEXT_IP6_LOOKUP,
> PKT_CLS_NEXT_MAX,
> };
>
> diff --git a/lib/node/rte_node_ip6_api.h b/lib/node/rte_node_ip6_api.h
> new file mode 100644
> index 0000000000..1696ed154d
> --- /dev/null
> +++ b/lib/node/rte_node_ip6_api.h
> @@ -0,0 +1,80 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(C) 2023 Marvell.
> + */
> +
> +#ifndef __INCLUDE_RTE_NODE_IP6_API_H__
> +#define __INCLUDE_RTE_NODE_IP6_API_H__
> +
> +/**
> + * @file rte_node_ip6_api.h
> + *
> + * @warning
> + * @b EXPERIMENTAL:
> + * All functions in this file may be changed or removed without prior notice.
> + *
> + * This API allows to do control path functions of ip6_* nodes
> + * like ip6_lookup, ip6_rewrite.
> + *
> + */
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <rte_common.h>
> +#include <rte_compat.h>
> +
> +/**
> + * IP6 lookup next nodes.
> + */
> +enum rte_node_ip6_lookup_next {
> + RTE_NODE_IP6_LOOKUP_NEXT_REWRITE,
> + /**< Rewrite node. */
> + RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP,
> + /**< Packet drop node. */
> + RTE_NODE_IP6_LOOKUP_NEXT_MAX,
> + /**< Number of next nodes of lookup node. */
> +};
> +
> +/**
> + * Add ipv6 route to lookup table.
> + *
> + * @param ip
> + * IPv6 address of route to be added.
> + * @param depth
> + * Depth of the rule to be added.
> + * @param next_hop
> + * Next hop id of the rule result to be added.
> + * @param next_node
> + * Next node to redirect traffic to.
> + *
> + * @return
> + * 0 on success, negative otherwise.
> + */
> +__rte_experimental
> +int rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
> + enum rte_node_ip6_lookup_next next_node);
> +
> +/**
> + * Add a next hop's rewrite data.
> + *
> + * @param next_hop
> + * Next hop id to add rewrite data to.
> + * @param rewrite_data
> + * Rewrite data.
> + * @param rewrite_len
> + * Length of rewrite data.
> + * @param dst_port
> + * Destination port to redirect traffic to.
> + *
> + * @return
> + * 0 on success, negative otherwise.
> + */
> +__rte_experimental
> +int rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
> + uint8_t rewrite_len, uint16_t dst_port);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* __INCLUDE_RTE_NODE_IP6_API_H__ */
> diff --git a/lib/node/version.map b/lib/node/version.map
> index a799b0d389..40df308bfe 100644
> --- a/lib/node/version.map
> +++ b/lib/node/version.map
> @@ -4,6 +4,8 @@ EXPERIMENTAL {
> rte_node_eth_config;
> rte_node_ip4_route_add;
> rte_node_ip4_rewrite_add;
> + rte_node_ip6_rewrite_add;
> + rte_node_ip6_route_add;
> rte_node_logtype;
> local: *;
> };
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v3 1/3] lib: add IPv6 lookup node
2023-05-18 15:56 ` [PATCH v2 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
` (2 preceding siblings ...)
2023-05-30 8:51 ` [PATCH v2 1/3] lib: add IPv6 lookup node Nithin Dabilpuram
@ 2023-05-31 11:37 ` Amit Prakash Shukla
2023-05-31 11:37 ` [PATCH v3 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
` (2 more replies)
3 siblings, 3 replies; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-05-31 11:37 UTC (permalink / raw)
To: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh
Cc: dev, skori, Amit Prakash Shukla
From: Sunil Kumar Kori <skori@marvell.com>
Similar to IPv4 lookup node, patch adds IPv6 lookup
node.
Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Performance related changes
v3:
- Removing redundant dynamic variable
doc/guides/prog_guide/graph_lib.rst | 13 +
lib/node/ip6_lookup.c | 372 ++++++++++++++++++++++++++++
lib/node/meson.build | 3 +-
lib/node/node_private.h | 2 +-
lib/node/pkt_cls.c | 14 ++
lib/node/pkt_cls_priv.h | 1 +
lib/node/rte_node_ip6_api.h | 80 ++++++
lib/node/version.map | 2 +
8 files changed, 485 insertions(+), 2 deletions(-)
create mode 100644 lib/node/ip6_lookup.c
create mode 100644 lib/node/rte_node_ip6_api.h
diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
index 1cfdc86433..1f70d63628 100644
--- a/doc/guides/prog_guide/graph_lib.rst
+++ b/doc/guides/prog_guide/graph_lib.rst
@@ -388,6 +388,19 @@ 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.
+ip6_lookup
+~~~~~~~~~~
+This node is an intermediate node that does LPM lookup for the received
+ipv6 packets and the result determines each packets next node.
+
+On successful LPM lookup, the result contains the ``next_node`` id and
+``next-hop`` id with which the packet needs to be further processed.
+
+On LPM lookup failure, objects are redirected to pkt_drop node.
+``rte_node_ip6_route_add()`` is control path API to add ipv6 routes.
+To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
+sections.
+
null
~~~~
This node ignores the set of objects passed to it and reports that all are
diff --git a/lib/node/ip6_lookup.c b/lib/node/ip6_lookup.c
new file mode 100644
index 0000000000..e4bbc7ed67
--- /dev/null
+++ b/lib/node/ip6_lookup.c
@@ -0,0 +1,372 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_ip.h>
+#include <rte_lpm6.h>
+
+#include "rte_node_ip6_api.h"
+
+#include "node_private.h"
+
+#define IPV6_L3FWD_LPM_MAX_RULES 1024
+#define IPV6_L3FWD_LPM_NUMBER_TBL8S (1 << 8)
+
+/* IP6 Lookup global data struct */
+struct ip6_lookup_node_main {
+ struct rte_lpm6 *lpm_tbl[RTE_MAX_NUMA_NODES];
+};
+
+struct ip6_lookup_node_ctx {
+ /* Socket's LPM table */
+ struct rte_lpm6 *lpm6;
+ /* Dynamic offset to mbuf priv1 */
+ int mbuf_priv1_off;
+};
+
+static struct ip6_lookup_node_main ip6_lookup_nm;
+
+#define IP6_LOOKUP_NODE_LPM(ctx) \
+ (((struct ip6_lookup_node_ctx *)ctx)->lpm6)
+
+#define IP6_LOOKUP_NODE_PRIV1_OFF(ctx) \
+ (((struct ip6_lookup_node_ctx *)ctx)->mbuf_priv1_off)
+
+static uint16_t
+ip6_lookup_node_process_scalar(struct rte_graph *graph, struct rte_node *node,
+ void **objs, uint16_t nb_objs)
+{
+ struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
+ struct rte_lpm6 *lpm6 = IP6_LOOKUP_NODE_LPM(node->ctx);
+ const int dyn = IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx);
+ struct rte_ipv6_hdr *ipv6_hdr;
+ void **to_next, **from;
+ uint16_t last_spec = 0;
+ rte_edge_t next_index;
+ uint16_t n_left_from;
+ uint16_t held = 0;
+ uint32_t drop_nh;
+ int i, rc;
+
+ /* Speculative next */
+ next_index = RTE_NODE_IP6_LOOKUP_NEXT_REWRITE;
+ /* Drop node */
+ drop_nh = ((uint32_t)RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP) << 16;
+
+ pkts = (struct rte_mbuf **)objs;
+ from = objs;
+ n_left_from = nb_objs;
+
+ for (i = OBJS_PER_CLINE; i < RTE_GRAPH_BURST_SIZE; i += OBJS_PER_CLINE)
+ rte_prefetch0(&objs[i]);
+
+ for (i = 0; i < 4 && i < n_left_from; i++)
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[i], void *,
+ sizeof(struct rte_ether_hdr)));
+
+ /* Get stream for the speculated next node */
+ to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
+ while (n_left_from >= 4) {
+ uint8_t ip_batch[4][16];
+ int32_t next_hop[4];
+ uint16_t next[4];
+
+#if RTE_GRAPH_BURST_SIZE > 64
+ /* Prefetch next-next mbufs */
+ if (likely(n_left_from > 11)) {
+ rte_prefetch0(pkts[8]);
+ rte_prefetch0(pkts[9]);
+ rte_prefetch0(pkts[10]);
+ rte_prefetch0(pkts[11]);
+ }
+#endif
+ /* Prefetch next mbuf data */
+ if (likely(n_left_from > 7)) {
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[4], void *,
+ sizeof(struct rte_ether_hdr)));
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[5], void *,
+ sizeof(struct rte_ether_hdr)));
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[6], void *,
+ sizeof(struct rte_ether_hdr)));
+ rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[7], void *,
+ sizeof(struct rte_ether_hdr)));
+ }
+
+ mbuf0 = pkts[0];
+ mbuf1 = pkts[1];
+ mbuf2 = pkts[2];
+ mbuf3 = pkts[3];
+
+ pkts += 4;
+ n_left_from -= 4;
+
+ /* Extract DIP of mbuf0 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract hop_limits as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
+ rte_memcpy(ip_batch[0], ipv6_hdr->dst_addr, 16);
+
+ /* Extract DIP of mbuf1 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf1, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract hop_limits as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf1, dyn)->ttl = ipv6_hdr->hop_limits;
+ rte_memcpy(ip_batch[1], ipv6_hdr->dst_addr, 16);
+
+ /* Extract DIP of mbuf2 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf2, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract hop_limits as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf2, dyn)->ttl = ipv6_hdr->hop_limits;
+ rte_memcpy(ip_batch[2], ipv6_hdr->dst_addr, 16);
+
+ /* Extract DIP of mbuf3 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf3, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract hop_limits as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf3, dyn)->ttl = ipv6_hdr->hop_limits;
+ rte_memcpy(ip_batch[3], ipv6_hdr->dst_addr, 16);
+
+ rc = rte_lpm6_lookup_bulk_func(lpm6, ip_batch, next_hop, 4);
+
+ next_hop[0] = (next_hop[0] < 0) ? (int32_t)drop_nh : next_hop[0];
+ node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop[0];
+ next[0] = (uint16_t)(next_hop[0] >> 16);
+
+ next_hop[1] = (next_hop[1] < 0) ? (int32_t)drop_nh : next_hop[1];
+ node_mbuf_priv1(mbuf1, dyn)->nh = (uint16_t)next_hop[1];
+ next[1] = (uint16_t)(next_hop[1] >> 16);
+
+ next_hop[2] = (next_hop[2] < 0) ? (int32_t)drop_nh : next_hop[2];
+ node_mbuf_priv1(mbuf2, dyn)->nh = (uint16_t)next_hop[2];
+ next[2] = (uint16_t)(next_hop[2] >> 16);
+
+ next_hop[3] = (next_hop[3] < 0) ? (int32_t)drop_nh : next_hop[3];
+ node_mbuf_priv1(mbuf3, dyn)->nh = (uint16_t)next_hop[3];
+ next[3] = (uint16_t)(next_hop[3] >> 16);
+
+ rte_edge_t fix_spec = ((next_index == next[0]) &&
+ (next_index == next[1]) &&
+ (next_index == next[2]) &&
+ (next_index == next[3]));
+
+ if (unlikely(fix_spec == 0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ /* Next0 */
+ if (next_index == next[0]) {
+ to_next[0] = from[0];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next[0], from[0]);
+ }
+
+ /* Next1 */
+ if (next_index == next[1]) {
+ to_next[0] = from[1];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next[1], from[1]);
+ }
+
+ /* Next2 */
+ if (next_index == next[2]) {
+ to_next[0] = from[2];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next[2], from[2]);
+ }
+
+ /* Next3 */
+ if (next_index == next[3]) {
+ to_next[0] = from[3];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next[3], from[3]);
+ }
+
+ from += 4;
+ } else {
+ last_spec += 4;
+ }
+ }
+
+ while (n_left_from > 0) {
+ uint32_t next_hop;
+ uint16_t next0;
+
+ mbuf0 = pkts[0];
+
+ pkts += 1;
+ n_left_from -= 1;
+
+ /* Extract DIP of mbuf0 */
+ ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
+ sizeof(struct rte_ether_hdr));
+ /* Extract ttl as ipv6 hdr is in cache */
+ node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
+
+ rc = rte_lpm6_lookup(lpm6, ipv6_hdr->dst_addr, &next_hop);
+ next_hop = (rc == 0) ? next_hop : drop_nh;
+
+ node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop;
+ next_hop = next_hop >> 16;
+ next0 = (uint16_t)next_hop;
+
+ if (unlikely(next_index ^ next0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ rte_node_enqueue_x1(graph, node, next0, from[0]);
+ from += 1;
+ } else {
+ last_spec += 1;
+ }
+ }
+
+ /* !!! Home run !!! */
+ if (likely(last_spec == nb_objs)) {
+ rte_node_next_stream_move(graph, node, next_index);
+ return nb_objs;
+ }
+ held += last_spec;
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ rte_node_next_stream_put(graph, node, next_index, held);
+
+ return nb_objs;
+}
+
+int
+rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
+ enum rte_node_ip6_lookup_next next_node)
+{
+ char abuf[INET6_ADDRSTRLEN];
+ struct in6_addr in6;
+ uint8_t socket;
+ uint32_t val;
+ int ret;
+
+ memcpy(in6.s6_addr, ip, RTE_LPM6_IPV6_ADDR_SIZE);
+ inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf));
+ /* Embedded next node id into 24 bit next hop */
+ val = ((next_node << 16) | next_hop) & ((1ull << 24) - 1);
+ node_dbg("ip6_lookup", "LPM: Adding route %s / %d nh (0x%x)", abuf,
+ depth, val);
+
+ for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
+ if (!ip6_lookup_nm.lpm_tbl[socket])
+ continue;
+
+ ret = rte_lpm6_add(ip6_lookup_nm.lpm_tbl[socket], ip, depth,
+ val);
+ if (ret < 0) {
+ node_err("ip6_lookup",
+ "Unable to add entry %s / %d nh (%x) to LPM "
+ "table on sock %d, rc=%d\n",
+ abuf, depth, val, socket, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int
+setup_lpm6(struct ip6_lookup_node_main *nm, int socket)
+{
+ struct rte_lpm6_config config_ipv6;
+ char s[RTE_LPM6_NAMESIZE];
+
+ /* One LPM table per socket */
+ if (nm->lpm_tbl[socket])
+ return 0;
+
+ /* create the LPM table */
+ config_ipv6.max_rules = IPV6_L3FWD_LPM_MAX_RULES;
+ config_ipv6.number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S;
+ config_ipv6.flags = 0;
+ snprintf(s, sizeof(s), "IPV6_L3FWD_LPM_%d", socket);
+ nm->lpm_tbl[socket] = rte_lpm6_create(s, socket, &config_ipv6);
+ if (nm->lpm_tbl[socket] == NULL)
+ return -rte_errno;
+
+ return 0;
+}
+
+static int
+ip6_lookup_node_init(const struct rte_graph *graph, struct rte_node *node)
+{
+ uint16_t socket, lcore_id;
+ static uint8_t init_once;
+ int rc;
+
+ RTE_SET_USED(graph);
+ RTE_BUILD_BUG_ON(sizeof(struct ip6_lookup_node_ctx) > RTE_NODE_CTX_SZ);
+
+ if (!init_once) {
+ node_mbuf_priv1_dynfield_offset =
+ rte_mbuf_dynfield_register(
+ &node_mbuf_priv1_dynfield_desc);
+ if (node_mbuf_priv1_dynfield_offset < 0)
+ return -rte_errno;
+
+ /* Setup LPM tables for all sockets */
+ RTE_LCORE_FOREACH(lcore_id)
+ {
+ socket = rte_lcore_to_socket_id(lcore_id);
+ rc = setup_lpm6(&ip6_lookup_nm, socket);
+ if (rc) {
+ node_err("ip6_lookup",
+ "Failed to setup lpm6 tbl for "
+ "sock %u, rc=%d", socket, rc);
+ return rc;
+ }
+ }
+ init_once = 1;
+ }
+
+ /* Update socket's LPM and mbuf dyn priv1 offset in node ctx */
+ IP6_LOOKUP_NODE_LPM(node->ctx) = ip6_lookup_nm.lpm_tbl[graph->socket];
+ IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx) =
+ node_mbuf_priv1_dynfield_offset;
+
+ node_dbg("ip6_lookup", "Initialized ip6_lookup node");
+
+ return 0;
+}
+
+static struct rte_node_register ip6_lookup_node = {
+ .process = ip6_lookup_node_process_scalar,
+ .name = "ip6_lookup",
+
+ .init = ip6_lookup_node_init,
+
+ .nb_edges = RTE_NODE_IP6_LOOKUP_NEXT_MAX,
+ .next_nodes = {
+ [RTE_NODE_IP6_LOOKUP_NEXT_REWRITE] = "ip6_rewrite",
+ [RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP] = "pkt_drop",
+ },
+};
+
+RTE_NODE_REGISTER(ip6_lookup_node);
diff --git a/lib/node/meson.build b/lib/node/meson.build
index dbdf673c86..cd30847a0b 100644
--- a/lib/node/meson.build
+++ b/lib/node/meson.build
@@ -12,13 +12,14 @@ sources = files(
'ethdev_rx.c',
'ethdev_tx.c',
'ip4_lookup.c',
+ 'ip6_lookup.c',
'ip4_rewrite.c',
'log.c',
'null.c',
'pkt_cls.c',
'pkt_drop.c',
)
-headers = files('rte_node_ip4_api.h', 'rte_node_eth_api.h')
+headers = files('rte_node_ip4_api.h', 'rte_node_ip6_api.h', 'rte_node_eth_api.h')
# Strict-aliasing rules are violated by uint8_t[] to context size casts.
cflags += '-fno-strict-aliasing'
deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev']
diff --git a/lib/node/node_private.h b/lib/node/node_private.h
index 8c73d5dc10..26135aaa5b 100644
--- a/lib/node/node_private.h
+++ b/lib/node/node_private.h
@@ -26,7 +26,7 @@ extern int rte_node_logtype;
*/
struct node_mbuf_priv1 {
union {
- /* IP4 rewrite */
+ /* IP4/IP6 rewrite */
struct {
uint16_t nh;
uint16_t ttl;
diff --git a/lib/node/pkt_cls.c b/lib/node/pkt_cls.c
index 3e75f2cf78..a8302b8d28 100644
--- a/lib/node/pkt_cls.c
+++ b/lib/node/pkt_cls.c
@@ -24,6 +24,19 @@ static const uint8_t p_nxt[256] __rte_cache_aligned = {
[RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
PKT_CLS_NEXT_IP4_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
+
+ [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
+ PKT_CLS_NEXT_IP6_LOOKUP,
};
static uint16_t
@@ -216,6 +229,7 @@ struct rte_node_register pkt_cls_node = {
/* Pkt drop node starts at '0' */
[PKT_CLS_NEXT_PKT_DROP] = "pkt_drop",
[PKT_CLS_NEXT_IP4_LOOKUP] = "ip4_lookup",
+ [PKT_CLS_NEXT_IP6_LOOKUP] = "ip6_lookup",
},
};
RTE_NODE_REGISTER(pkt_cls_node);
diff --git a/lib/node/pkt_cls_priv.h b/lib/node/pkt_cls_priv.h
index 6f5374f0be..16135807a1 100644
--- a/lib/node/pkt_cls_priv.h
+++ b/lib/node/pkt_cls_priv.h
@@ -13,6 +13,7 @@ struct pkt_cls_node_ctx {
enum pkt_cls_next_nodes {
PKT_CLS_NEXT_PKT_DROP,
PKT_CLS_NEXT_IP4_LOOKUP,
+ PKT_CLS_NEXT_IP6_LOOKUP,
PKT_CLS_NEXT_MAX,
};
diff --git a/lib/node/rte_node_ip6_api.h b/lib/node/rte_node_ip6_api.h
new file mode 100644
index 0000000000..1696ed154d
--- /dev/null
+++ b/lib/node/rte_node_ip6_api.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#ifndef __INCLUDE_RTE_NODE_IP6_API_H__
+#define __INCLUDE_RTE_NODE_IP6_API_H__
+
+/**
+ * @file rte_node_ip6_api.h
+ *
+ * @warning
+ * @b EXPERIMENTAL:
+ * All functions in this file may be changed or removed without prior notice.
+ *
+ * This API allows to do control path functions of ip6_* nodes
+ * like ip6_lookup, ip6_rewrite.
+ *
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_common.h>
+#include <rte_compat.h>
+
+/**
+ * IP6 lookup next nodes.
+ */
+enum rte_node_ip6_lookup_next {
+ RTE_NODE_IP6_LOOKUP_NEXT_REWRITE,
+ /**< Rewrite node. */
+ RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP,
+ /**< Packet drop node. */
+ RTE_NODE_IP6_LOOKUP_NEXT_MAX,
+ /**< Number of next nodes of lookup node. */
+};
+
+/**
+ * Add ipv6 route to lookup table.
+ *
+ * @param ip
+ * IPv6 address of route to be added.
+ * @param depth
+ * Depth of the rule to be added.
+ * @param next_hop
+ * Next hop id of the rule result to be added.
+ * @param next_node
+ * Next node to redirect traffic to.
+ *
+ * @return
+ * 0 on success, negative otherwise.
+ */
+__rte_experimental
+int rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
+ enum rte_node_ip6_lookup_next next_node);
+
+/**
+ * Add a next hop's rewrite data.
+ *
+ * @param next_hop
+ * Next hop id to add rewrite data to.
+ * @param rewrite_data
+ * Rewrite data.
+ * @param rewrite_len
+ * Length of rewrite data.
+ * @param dst_port
+ * Destination port to redirect traffic to.
+ *
+ * @return
+ * 0 on success, negative otherwise.
+ */
+__rte_experimental
+int rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
+ uint8_t rewrite_len, uint16_t dst_port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_RTE_NODE_IP6_API_H__ */
diff --git a/lib/node/version.map b/lib/node/version.map
index a799b0d389..40df308bfe 100644
--- a/lib/node/version.map
+++ b/lib/node/version.map
@@ -4,6 +4,8 @@ EXPERIMENTAL {
rte_node_eth_config;
rte_node_ip4_route_add;
rte_node_ip4_rewrite_add;
+ rte_node_ip6_rewrite_add;
+ rte_node_ip6_route_add;
rte_node_logtype;
local: *;
};
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v3 2/3] lib: add IPv6 rewrite node
2023-05-31 11:37 ` [PATCH v3 " Amit Prakash Shukla
@ 2023-05-31 11:37 ` Amit Prakash Shukla
2023-06-01 2:26 ` Nithin Dabilpuram
2023-06-05 16:29 ` Nithin Dabilpuram
2023-05-31 11:37 ` [PATCH v3 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
2023-06-01 2:24 ` [PATCH v3 1/3] lib: add IPv6 lookup node Nithin Dabilpuram
2 siblings, 2 replies; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-05-31 11:37 UTC (permalink / raw)
To: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh
Cc: dev, skori, Amit Prakash Shukla
Similar to IPv4 rewrite node, patch adds IPv6 rewrite node.
Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Performance related changes
v3:
- Removing redundant dynamic variable
doc/guides/prog_guide/graph_lib.rst | 8 +
lib/node/ethdev_ctrl.c | 13 ++
lib/node/ip6_rewrite.c | 331 ++++++++++++++++++++++++++++
lib/node/ip6_rewrite_priv.h | 69 ++++++
lib/node/meson.build | 1 +
5 files changed, 422 insertions(+)
create mode 100644 lib/node/ip6_rewrite.c
create mode 100644 lib/node/ip6_rewrite_priv.h
diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
index 1f70d63628..841cabe259 100644
--- a/doc/guides/prog_guide/graph_lib.rst
+++ b/doc/guides/prog_guide/graph_lib.rst
@@ -401,6 +401,14 @@ On LPM lookup failure, objects are redirected to pkt_drop node.
To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
sections.
+ip6_rewrite
+~~~~~~~~~~~
+This node gets packets from ``ip6_lookup`` node with next-hop id for each
+packet is embedded in ``node_mbuf_priv1(mbuf)->nh``. This id is used
+to determine the L2 header to be written to the packet before sending
+the packet out to a particular ethdev_tx node.
+``rte_node_ip6_rewrite_add()`` is control path API to add next-hop info.
+
null
~~~~
This node ignores the set of objects passed to it and reports that all are
diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
index 37df0431b8..ea7dc8210b 100644
--- a/lib/node/ethdev_ctrl.c
+++ b/lib/node/ethdev_ctrl.c
@@ -12,6 +12,7 @@
#include "ethdev_rx_priv.h"
#include "ethdev_tx_priv.h"
#include "ip4_rewrite_priv.h"
+#include "ip6_rewrite_priv.h"
#include "node_private.h"
static struct ethdev_ctrl {
@@ -23,6 +24,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
uint16_t nb_graphs)
{
struct rte_node_register *ip4_rewrite_node;
+ struct rte_node_register *ip6_rewrite_node;
struct ethdev_tx_node_main *tx_node_data;
uint16_t tx_q_used, rx_q_used, port_id;
struct rte_node_register *tx_node;
@@ -33,6 +35,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
uint32_t id;
ip4_rewrite_node = ip4_rewrite_node_get();
+ ip6_rewrite_node = ip6_rewrite_node_get();
tx_node_data = ethdev_tx_node_data_get();
tx_node = ethdev_tx_node_get();
for (i = 0; i < nb_confs; i++) {
@@ -110,6 +113,16 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
port_id, rte_node_edge_count(ip4_rewrite_node->id) - 1);
if (rc < 0)
return rc;
+
+ /* Add this tx port node as next to ip6_rewrite_node */
+ rte_node_edge_update(ip6_rewrite_node->id, RTE_EDGE_ID_INVALID,
+ &next_nodes, 1);
+ /* Assuming edge id is the last one alloc'ed */
+ rc = ip6_rewrite_set_next(
+ port_id, rte_node_edge_count(ip6_rewrite_node->id) - 1);
+ if (rc < 0)
+ return rc;
+
}
ctrl.nb_graphs = nb_graphs;
diff --git a/lib/node/ip6_rewrite.c b/lib/node/ip6_rewrite.c
new file mode 100644
index 0000000000..198d8d8820
--- /dev/null
+++ b/lib/node/ip6_rewrite.c
@@ -0,0 +1,331 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <rte_ethdev.h>
+#include <rte_ether.h>
+#include <rte_graph.h>
+#include <rte_graph_worker.h>
+#include <rte_ip.h>
+#include <rte_malloc.h>
+#include <rte_vect.h>
+
+#include "rte_node_ip6_api.h"
+
+#include "ip6_rewrite_priv.h"
+#include "node_private.h"
+
+struct ip6_rewrite_node_ctx {
+ /* Dynamic offset to mbuf priv1 */
+ int mbuf_priv1_off;
+ /* Cached next index */
+ uint16_t next_index;
+};
+
+static struct ip6_rewrite_node_main *ip6_rewrite_nm;
+
+#define IP6_REWRITE_NODE_LAST_NEXT(ctx) \
+ (((struct ip6_rewrite_node_ctx *)ctx)->next_index)
+
+#define IP6_REWRITE_NODE_PRIV1_OFF(ctx) \
+ (((struct ip6_rewrite_node_ctx *)ctx)->mbuf_priv1_off)
+
+static uint16_t
+ip6_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
+ void **objs, uint16_t nb_objs)
+{
+ struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
+ struct ip6_rewrite_nh_header *nh = ip6_rewrite_nm->nh;
+ const int dyn = IP6_REWRITE_NODE_PRIV1_OFF(node->ctx);
+ uint16_t next0, next1, next2, next3, next_index;
+ uint16_t n_left_from, held = 0, last_spec = 0;
+ struct rte_ipv6_hdr *ip0, *ip1, *ip2, *ip3;
+ void *d0, *d1, *d2, *d3;
+ void **to_next, **from;
+ rte_xmm_t priv01;
+ rte_xmm_t priv23;
+ int i;
+
+ /* Speculative next as last next */
+ next_index = IP6_REWRITE_NODE_LAST_NEXT(node->ctx);
+ rte_prefetch0(nh);
+
+ pkts = (struct rte_mbuf **)objs;
+ from = objs;
+ n_left_from = nb_objs;
+
+ for (i = 0; i < 4 && i < n_left_from; i++)
+ rte_prefetch0(pkts[i]);
+
+ /* Get stream for the speculated next node */
+ to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
+ /* Update Ethernet header of pkts */
+ while (n_left_from >= 4) {
+ if (likely(n_left_from > 7)) {
+ /* Prefetch only next-mbuf struct and priv area.
+ * Data need not be prefetched as we only write.
+ */
+ rte_prefetch0(pkts[4]);
+ rte_prefetch0(pkts[5]);
+ rte_prefetch0(pkts[6]);
+ rte_prefetch0(pkts[7]);
+ }
+
+ mbuf0 = pkts[0];
+ mbuf1 = pkts[1];
+ mbuf2 = pkts[2];
+ mbuf3 = pkts[3];
+
+ pkts += 4;
+ n_left_from -= 4;
+ priv01.u64[0] = node_mbuf_priv1(mbuf0, dyn)->u;
+ priv01.u64[1] = node_mbuf_priv1(mbuf1, dyn)->u;
+ priv23.u64[0] = node_mbuf_priv1(mbuf2, dyn)->u;
+ priv23.u64[1] = node_mbuf_priv1(mbuf3, dyn)->u;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf0 */
+ d0 = rte_pktmbuf_mtod(mbuf0, void *);
+ rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,
+ nh[priv01.u16[0]].rewrite_len);
+
+ next0 = nh[priv01.u16[0]].tx_node;
+ ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
+ sizeof(struct rte_ether_hdr));
+ ip0->hop_limits = priv01.u16[1] - 1;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf1 */
+ d1 = rte_pktmbuf_mtod(mbuf1, void *);
+ rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,
+ nh[priv01.u16[4]].rewrite_len);
+
+ next1 = nh[priv01.u16[4]].tx_node;
+ ip1 = (struct rte_ipv6_hdr *)((uint8_t *)d1 +
+ sizeof(struct rte_ether_hdr));
+ ip1->hop_limits = priv01.u16[5] - 1;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf2 */
+ d2 = rte_pktmbuf_mtod(mbuf2, void *);
+ rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,
+ nh[priv23.u16[0]].rewrite_len);
+ next2 = nh[priv23.u16[0]].tx_node;
+ ip2 = (struct rte_ipv6_hdr *)((uint8_t *)d2 +
+ sizeof(struct rte_ether_hdr));
+ ip2->hop_limits = priv23.u16[1] - 1;
+
+ /* Update next_hop rewrite ethernet hdr on mbuf3 */
+ d3 = rte_pktmbuf_mtod(mbuf3, void *);
+ rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,
+ nh[priv23.u16[4]].rewrite_len);
+
+ next3 = nh[priv23.u16[4]].tx_node;
+ ip3 = (struct rte_ipv6_hdr *)((uint8_t *)d3 +
+ sizeof(struct rte_ether_hdr));
+ ip3->hop_limits = priv23.u16[5] - 1;
+
+ /* Enqueue four packets to next node */
+ rte_edge_t fix_spec =
+ ((next_index == next0) && (next0 == next1) &&
+ (next1 == next2) && (next2 == next3));
+
+ if (unlikely(fix_spec == 0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ /* next0 */
+ if (next_index == next0) {
+ to_next[0] = from[0];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next0,
+ from[0]);
+ }
+
+ /* next1 */
+ if (next_index == next1) {
+ to_next[0] = from[1];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next1,
+ from[1]);
+ }
+
+ /* next2 */
+ if (next_index == next2) {
+ to_next[0] = from[2];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next2,
+ from[2]);
+ }
+
+ /* next3 */
+ if (next_index == next3) {
+ to_next[0] = from[3];
+ to_next++;
+ held++;
+ } else {
+ rte_node_enqueue_x1(graph, node, next3,
+ from[3]);
+ }
+
+ from += 4;
+
+ /* Change speculation if last two are same */
+ if ((next_index != next3) && (next2 == next3)) {
+ /* Put the current speculated node */
+ rte_node_next_stream_put(graph, node,
+ next_index, held);
+ held = 0;
+
+ /* Get next speculated stream */
+ next_index = next3;
+ to_next = rte_node_next_stream_get(
+ graph, node, next_index, nb_objs);
+ }
+ } else {
+ last_spec += 4;
+ }
+ }
+
+ while (n_left_from > 0) {
+ mbuf0 = pkts[0];
+
+ pkts += 1;
+ n_left_from -= 1;
+
+ d0 = rte_pktmbuf_mtod(mbuf0, void *);
+ rte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,
+ nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);
+
+ next0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node;
+ ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
+ sizeof(struct rte_ether_hdr));
+ ip0->hop_limits = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;
+
+ if (unlikely(next_index ^ next0)) {
+ /* Copy things successfully speculated till now */
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ from += last_spec;
+ to_next += last_spec;
+ held += last_spec;
+ last_spec = 0;
+
+ rte_node_enqueue_x1(graph, node, next0, from[0]);
+ from += 1;
+ } else {
+ last_spec += 1;
+ }
+ }
+
+ /* !!! Home run !!! */
+ if (likely(last_spec == nb_objs)) {
+ rte_node_next_stream_move(graph, node, next_index);
+ return nb_objs;
+ }
+
+ held += last_spec;
+ rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
+ rte_node_next_stream_put(graph, node, next_index, held);
+ /* Save the last next used */
+ IP6_REWRITE_NODE_LAST_NEXT(node->ctx) = next_index;
+
+ return nb_objs;
+}
+
+static int
+ip6_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
+{
+ static bool init_once;
+
+ RTE_SET_USED(graph);
+ RTE_BUILD_BUG_ON(sizeof(struct ip6_rewrite_node_ctx) > RTE_NODE_CTX_SZ);
+
+ if (!init_once) {
+ node_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register(
+ &node_mbuf_priv1_dynfield_desc);
+ if (node_mbuf_priv1_dynfield_offset < 0)
+ return -rte_errno;
+ init_once = true;
+ }
+ IP6_REWRITE_NODE_PRIV1_OFF(node->ctx) = node_mbuf_priv1_dynfield_offset;
+
+ node_dbg("ip6_rewrite", "Initialized ip6_rewrite node");
+
+ return 0;
+}
+
+int
+ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index)
+{
+ if (ip6_rewrite_nm == NULL) {
+ ip6_rewrite_nm = rte_zmalloc(
+ "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
+ RTE_CACHE_LINE_SIZE);
+ if (ip6_rewrite_nm == NULL)
+ return -ENOMEM;
+ }
+ ip6_rewrite_nm->next_index[port_id] = next_index;
+
+ return 0;
+}
+
+int
+rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
+ uint8_t rewrite_len, uint16_t dst_port)
+{
+ struct ip6_rewrite_nh_header *nh;
+
+ if (next_hop >= RTE_GRAPH_IP6_REWRITE_MAX_NH)
+ return -EINVAL;
+
+ if (rewrite_len > RTE_GRAPH_IP6_REWRITE_MAX_LEN)
+ return -EINVAL;
+
+ if (ip6_rewrite_nm == NULL) {
+ ip6_rewrite_nm = rte_zmalloc(
+ "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
+ RTE_CACHE_LINE_SIZE);
+ if (ip6_rewrite_nm == NULL)
+ return -ENOMEM;
+ }
+
+ /* Check if dst port doesn't exist as edge */
+ if (!ip6_rewrite_nm->next_index[dst_port])
+ return -EINVAL;
+
+ /* Update next hop */
+ nh = &ip6_rewrite_nm->nh[next_hop];
+
+ memcpy(nh->rewrite_data, rewrite_data, rewrite_len);
+ nh->tx_node = ip6_rewrite_nm->next_index[dst_port];
+ nh->rewrite_len = rewrite_len;
+ nh->enabled = true;
+
+ return 0;
+}
+
+static struct rte_node_register ip6_rewrite_node = {
+ .process = ip6_rewrite_node_process,
+ .name = "ip6_rewrite",
+ /* Default edge i.e '0' is pkt drop */
+ .nb_edges = 1,
+ .next_nodes = {
+ [0] = "pkt_drop",
+ },
+ .init = ip6_rewrite_node_init,
+};
+
+struct rte_node_register *
+ip6_rewrite_node_get(void)
+{
+ return &ip6_rewrite_node;
+}
+
+RTE_NODE_REGISTER(ip6_rewrite_node);
diff --git a/lib/node/ip6_rewrite_priv.h b/lib/node/ip6_rewrite_priv.h
new file mode 100644
index 0000000000..93db28bec0
--- /dev/null
+++ b/lib/node/ip6_rewrite_priv.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+#ifndef __INCLUDE_IP6_REWRITE_PRIV_H__
+#define __INCLUDE_IP6_REWRITE_PRIV_H__
+
+#include <rte_common.h>
+
+#define RTE_GRAPH_IP6_REWRITE_MAX_NH 64
+#define RTE_GRAPH_IP6_REWRITE_MAX_LEN 56
+
+/**
+ * @internal
+ *
+ * Ipv6 rewrite next hop header data structure. Used to store port specific
+ * rewrite data.
+ */
+struct ip6_rewrite_nh_header {
+ uint16_t rewrite_len; /**< Header rewrite length. */
+ uint16_t tx_node; /**< Tx node next index identifier. */
+ uint16_t enabled; /**< NH enable flag */
+ uint16_t rsvd;
+ union {
+ struct {
+ struct rte_ether_addr dst;
+ /**< Destination mac address. */
+ struct rte_ether_addr src;
+ /**< Source mac address. */
+ };
+ uint8_t rewrite_data[RTE_GRAPH_IP6_REWRITE_MAX_LEN];
+ /**< Generic rewrite data */
+ };
+};
+
+/**
+ * @internal
+ *
+ * Ipv6 node main data structure.
+ */
+struct ip6_rewrite_node_main {
+ struct ip6_rewrite_nh_header nh[RTE_GRAPH_IP6_REWRITE_MAX_NH];
+ /**< Array of next hop header data */
+ uint16_t next_index[RTE_MAX_ETHPORTS];
+ /**< Next index of each configured port. */
+};
+
+/**
+ * @internal
+ *
+ * Get the ipv6 rewrite node.
+ *
+ * @return
+ * Pointer to the ipv6 rewrite node.
+ */
+struct rte_node_register *ip6_rewrite_node_get(void);
+
+/**
+ * @internal
+ *
+ * Set the Edge index of a given port_id.
+ *
+ * @param port_id
+ * Ethernet port identifier.
+ * @param next_index
+ * Edge index of the Given Tx node.
+ */
+int ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index);
+
+#endif /* __INCLUDE_IP6_REWRITE_PRIV_H__ */
diff --git a/lib/node/meson.build b/lib/node/meson.build
index cd30847a0b..b2f04269c5 100644
--- a/lib/node/meson.build
+++ b/lib/node/meson.build
@@ -14,6 +14,7 @@ sources = files(
'ip4_lookup.c',
'ip6_lookup.c',
'ip4_rewrite.c',
+ 'ip6_rewrite.c',
'log.c',
'null.c',
'pkt_cls.c',
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH v3 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support
2023-05-31 11:37 ` [PATCH v3 " Amit Prakash Shukla
2023-05-31 11:37 ` [PATCH v3 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
@ 2023-05-31 11:37 ` Amit Prakash Shukla
2023-06-05 16:32 ` Nithin Dabilpuram
2023-06-01 2:24 ` [PATCH v3 1/3] lib: add IPv6 lookup node Nithin Dabilpuram
2 siblings, 1 reply; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-05-31 11:37 UTC (permalink / raw)
To: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram
Cc: dev, skori, Amit Prakash Shukla
From: Sunil Kumar Kori <skori@marvell.com>
Similar to ipv4, to support IPv6 lookup and rewrite node
routes and rewrite data needs to be added.
Patch adds routes for ipv6 to validate ip6_lookup node
and rewrite data to validate ip6_rewrite node.
Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
---
v2:
- Performance related changes
v3:
- Removing redundant dynamic variable
doc/guides/sample_app_ug/l3_forward_graph.rst | 40 ++++++----
examples/l3fwd-graph/main.c | 77 ++++++++++++++++++-
2 files changed, 98 insertions(+), 19 deletions(-)
diff --git a/doc/guides/sample_app_ug/l3_forward_graph.rst b/doc/guides/sample_app_ug/l3_forward_graph.rst
index 585ac8c898..23f86e4785 100644
--- a/doc/guides/sample_app_ug/l3_forward_graph.rst
+++ b/doc/guides/sample_app_ug/l3_forward_graph.rst
@@ -12,7 +12,8 @@ Overview
--------
The application demonstrates the use of the graph framework and graph nodes
-``ethdev_rx``, ``ip4_lookup``, ``ip4_rewrite``, ``ethdev_tx`` and ``pkt_drop`` in DPDK to
+``ethdev_rx``, ``pkt_cls``, ``ip4_lookup``/``ip6_lookup``,
+``ip4_rewrite``/``ip6_rewrite``, ``ethdev_tx`` and ``pkt_drop`` in DPDK to
implement packet forwarding.
The initialization is very similar to those of the :doc:`l3_forward`.
@@ -24,13 +25,15 @@ TTL update and finally Tx is implemented inside graph nodes. These nodes are
interconnected in graph framework. Application main loop needs to walk over
graph using ``rte_graph_walk()`` with graph objects created one per worker lcore.
-The lookup method is as per implementation of ``ip4_lookup`` graph node.
+The lookup method is as per implementation of ``ip4_lookup``/``ip6_lookup`` graph node.
The ID of the output interface for the input packet is the next hop returned by
the LPM lookup. The set of LPM rules used by the application is statically
-configured and provided to ``ip4_lookup`` graph node and ``ip4_rewrite`` graph node
-using node control API ``rte_node_ip4_route_add()`` and ``rte_node_ip4_rewrite_add()``.
+configured and provided to ``ip4_lookup``/``ip6_lookup`` graph node and
+``ip4_rewrite``/``ip6_rewrite`` graph node using node control API
+``rte_node_ip4_route_add()``/``rte_node_ip6_route_add`` and
+``rte_node_ip4_rewrite_add()``/``rte_node_ip6_rewrite_add``.
-In the sample application, only IPv4 forwarding is supported as of now.
+In the sample application, IPv4 and IPv6 forwarding is supported.
Compiling the Application
-------------------------
@@ -149,8 +152,8 @@ lead to the clone of ``ethdev_rx`` and ``ethdev_tx`` nodes as ``ethdev_rx-X-Y``
In case of ``ethdev_tx-X`` nodes, tx queue id assigned per instance of the node
is same as graph id.
-These cloned nodes along with existing static nodes such as ``ip4_lookup`` and
-``ip4_rewrite`` will be used in graph creation to associate node's to lcore
+These cloned nodes along with existing static nodes such as ``ip4_lookup``/``ip6_lookup``
+and ``ip4_rewrite``/``ip6_rewrite`` will be used in graph creation to associate node's to lcore
specific graph object.
.. literalinclude:: ../../../examples/l3fwd-graph/main.c
@@ -186,20 +189,21 @@ Forwarding data(Route, Next-Hop) addition
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once graph objects are created, node specific info like routes and rewrite
-headers will be provided run-time using ``rte_node_ip4_route_add()`` and
-``rte_node_ip4_rewrite_add()`` API.
+headers will be provided run-time using ``rte_node_ip4_route_add()``/
+``rte_node_ip6_route_add`` and ``rte_node_ip4_rewrite_add()``/``rte_node_ip6_rewrite_add``
+API.
.. note::
- Since currently ``ip4_lookup`` and ``ip4_rewrite`` nodes don't support
- lock-less mechanisms(RCU, etc) to add run-time forwarding data like route and
- rewrite data, forwarding data is added before packet processing loop is
- launched on worker lcore.
+ Since currently ``ip4_lookup``/``ip6_lookup`` and ``ip4_rewrite``/``ip6_rewrite``
+ nodes don't support lock-less mechanisms(RCU, etc) to add run-time forwarding
+ data like route and rewrite data, forwarding data is added before packet
+ processing loop is launched on worker lcore.
.. literalinclude:: ../../../examples/l3fwd-graph/main.c
:language: c
- :start-after: Add route to ip4 graph infra. 8<
- :end-before: >8 End of adding route to ip4 graph infa.
+ :start-after: Add routes and rewrite data to graph infra. 8<
+ :end-before: >8 End of adding routes and rewrite data to graph infa.
:dedent: 1
Packet Forwarding using Graph Walk
@@ -215,8 +219,10 @@ specific graph object that was already created.
rte_graph_walk() will walk over all the sources nodes i.e ``ethdev_rx-X-Y``
associated with a given graph and Rx the available packets and enqueue them
- to the following node ``ip4_lookup`` which then will enqueue them to ``ip4_rewrite``
- node if LPM lookup succeeds. ``ip4_rewrite`` node then will update Ethernet header
+ to the following node ``pkt_cls`` which based on the packet type will enqueue
+ them to ``ip4_lookup``/``ip6_lookup`` which then will enqueue them to
+ ``ip4_rewrite``/``ip6_rewrite`` node if LPM lookup succeeds.
+ ``ip4_rewrite``/``ip6_rewrite`` node then will update Ethernet header
as per next-hop data and transmit the packet via port 'Z' by enqueuing
to ``ethdev_tx-Z`` node instance in its graph object.
diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c
index 5feeab4f0f..0c82e24513 100644
--- a/examples/l3fwd-graph/main.c
+++ b/examples/l3fwd-graph/main.c
@@ -27,9 +27,11 @@
#include <rte_launch.h>
#include <rte_lcore.h>
#include <rte_log.h>
+#include <rte_lpm6.h>
#include <rte_mempool.h>
#include <rte_node_eth_api.h>
#include <rte_node_ip4_api.h>
+#include <rte_node_ip6_api.h>
#include <rte_per_lcore.h>
#include <rte_string_fns.h>
#include <rte_vect.h>
@@ -142,6 +144,12 @@ struct ipv4_l3fwd_lpm_route {
uint8_t if_out;
};
+struct ipv6_l3fwd_lpm_route {
+ uint8_t ip[RTE_LPM6_IPV6_ADDR_SIZE];
+ uint8_t depth;
+ uint8_t if_out;
+};
+
#define IPV4_L3FWD_LPM_NUM_ROUTES \
(sizeof(ipv4_l3fwd_lpm_route_array) / \
sizeof(ipv4_l3fwd_lpm_route_array[0]))
@@ -153,6 +161,28 @@ static struct ipv4_l3fwd_lpm_route ipv4_l3fwd_lpm_route_array[] = {
{RTE_IPV4(198, 18, 6, 0), 24, 6}, {RTE_IPV4(198, 18, 7, 0), 24, 7},
};
+#define IPV6_L3FWD_LPM_NUM_ROUTES \
+ (sizeof(ipv6_l3fwd_lpm_route_array) / \
+ sizeof(ipv6_l3fwd_lpm_route_array[0]))
+static struct ipv6_l3fwd_lpm_route ipv6_l3fwd_lpm_route_array[] = {
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00}, 48, 0},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01}, 48, 1},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02}, 48, 2},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03}, 48, 3},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04}, 48, 4},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05}, 48, 5},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06}, 48, 6},
+ {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02}, 48, 7},
+};
+
static int
check_lcore_params(void)
{
@@ -1128,7 +1158,7 @@ main(int argc, char **argv)
memset(&rewrite_data, 0, sizeof(rewrite_data));
rewrite_len = sizeof(rewrite_data);
- /* Add route to ip4 graph infra. 8< */
+ /* Add routes and rewrite data to graph infra. 8< */
for (i = 0; i < IPV4_L3FWD_LPM_NUM_ROUTES; i++) {
char route_str[INET6_ADDRSTRLEN * 4];
char abuf[INET6_ADDRSTRLEN];
@@ -1172,7 +1202,50 @@ main(int argc, char **argv)
RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n",
route_str, i);
}
- /* >8 End of adding route to ip4 graph infa. */
+
+ for (i = 0; i < IPV6_L3FWD_LPM_NUM_ROUTES; i++) {
+ char route_str[INET6_ADDRSTRLEN * 4];
+ char abuf[INET6_ADDRSTRLEN];
+ struct in6_addr in6;
+ uint32_t dst_port;
+
+ /* Skip unused ports */
+ if ((1 << ipv6_l3fwd_lpm_route_array[i].if_out &
+ enabled_port_mask) == 0)
+ continue;
+
+ dst_port = ipv6_l3fwd_lpm_route_array[i].if_out;
+
+ memcpy(in6.s6_addr, ipv6_l3fwd_lpm_route_array[i].ip, RTE_LPM6_IPV6_ADDR_SIZE);
+ snprintf(route_str, sizeof(route_str), "%s / %d (%d)",
+ inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf)),
+ ipv6_l3fwd_lpm_route_array[i].depth,
+ ipv6_l3fwd_lpm_route_array[i].if_out);
+
+ /* Use route index 'i' as next hop id */
+ ret = rte_node_ip6_route_add(ipv6_l3fwd_lpm_route_array[i].ip,
+ ipv6_l3fwd_lpm_route_array[i].depth, i,
+ RTE_NODE_IP6_LOOKUP_NEXT_REWRITE);
+
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "Unable to add ip6 route %s to graph\n",
+ route_str);
+
+ memcpy(rewrite_data, val_eth + dst_port, rewrite_len);
+
+ /* Add next hop rewrite data for id 'i' */
+ ret = rte_node_ip6_rewrite_add(i, rewrite_data,
+ rewrite_len, dst_port);
+ if (ret < 0)
+ rte_exit(EXIT_FAILURE,
+ "Unable to add next hop %u for "
+ "route %s\n", i, route_str);
+
+ RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n",
+ route_str, i);
+ }
+ /* >8 End of adding routes and rewrite data to graph infa. */
/* Launch per-lcore init on every worker lcore */
rte_eal_mp_remote_launch(graph_main_loop, NULL, SKIP_MAIN);
--
2.25.1
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 1/3] lib: add IPv6 lookup node
2023-05-31 11:37 ` [PATCH v3 " Amit Prakash Shukla
2023-05-31 11:37 ` [PATCH v3 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
2023-05-31 11:37 ` [PATCH v3 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
@ 2023-06-01 2:24 ` Nithin Dabilpuram
2023-06-12 17:58 ` [EXT] " Amit Prakash Shukla
2 siblings, 1 reply; 18+ messages in thread
From: Nithin Dabilpuram @ 2023-06-01 2:24 UTC (permalink / raw)
To: Amit Prakash Shukla
Cc: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh,
dev, skori
Acked-by: Nithin Dabilpuram<ndabilpuram@marvell.com>
On Wed, May 31, 2023 at 5:08 PM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
>
> From: Sunil Kumar Kori <skori@marvell.com>
>
> Similar to IPv4 lookup node, patch adds IPv6 lookup
> node.
>
> Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
> v2:
> - Performance related changes
>
> v3:
> - Removing redundant dynamic variable
>
> doc/guides/prog_guide/graph_lib.rst | 13 +
> lib/node/ip6_lookup.c | 372 ++++++++++++++++++++++++++++
> lib/node/meson.build | 3 +-
> lib/node/node_private.h | 2 +-
> lib/node/pkt_cls.c | 14 ++
> lib/node/pkt_cls_priv.h | 1 +
> lib/node/rte_node_ip6_api.h | 80 ++++++
> lib/node/version.map | 2 +
> 8 files changed, 485 insertions(+), 2 deletions(-)
> create mode 100644 lib/node/ip6_lookup.c
> create mode 100644 lib/node/rte_node_ip6_api.h
>
> diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
> index 1cfdc86433..1f70d63628 100644
> --- a/doc/guides/prog_guide/graph_lib.rst
> +++ b/doc/guides/prog_guide/graph_lib.rst
> @@ -388,6 +388,19 @@ 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.
>
> +ip6_lookup
> +~~~~~~~~~~
> +This node is an intermediate node that does LPM lookup for the received
> +ipv6 packets and the result determines each packets next node.
> +
> +On successful LPM lookup, the result contains the ``next_node`` id and
> +``next-hop`` id with which the packet needs to be further processed.
> +
> +On LPM lookup failure, objects are redirected to pkt_drop node.
> +``rte_node_ip6_route_add()`` is control path API to add ipv6 routes.
> +To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
> +sections.
> +
> null
> ~~~~
> This node ignores the set of objects passed to it and reports that all are
> diff --git a/lib/node/ip6_lookup.c b/lib/node/ip6_lookup.c
> new file mode 100644
> index 0000000000..e4bbc7ed67
> --- /dev/null
> +++ b/lib/node/ip6_lookup.c
> @@ -0,0 +1,372 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(C) 2023 Marvell.
> + */
> +
> +#include <arpa/inet.h>
> +#include <sys/socket.h>
> +
> +#include <rte_ethdev.h>
> +#include <rte_ether.h>
> +#include <rte_graph.h>
> +#include <rte_graph_worker.h>
> +#include <rte_ip.h>
> +#include <rte_lpm6.h>
> +
> +#include "rte_node_ip6_api.h"
> +
> +#include "node_private.h"
> +
> +#define IPV6_L3FWD_LPM_MAX_RULES 1024
> +#define IPV6_L3FWD_LPM_NUMBER_TBL8S (1 << 8)
> +
> +/* IP6 Lookup global data struct */
> +struct ip6_lookup_node_main {
> + struct rte_lpm6 *lpm_tbl[RTE_MAX_NUMA_NODES];
> +};
> +
> +struct ip6_lookup_node_ctx {
> + /* Socket's LPM table */
> + struct rte_lpm6 *lpm6;
> + /* Dynamic offset to mbuf priv1 */
> + int mbuf_priv1_off;
> +};
> +
> +static struct ip6_lookup_node_main ip6_lookup_nm;
> +
> +#define IP6_LOOKUP_NODE_LPM(ctx) \
> + (((struct ip6_lookup_node_ctx *)ctx)->lpm6)
> +
> +#define IP6_LOOKUP_NODE_PRIV1_OFF(ctx) \
> + (((struct ip6_lookup_node_ctx *)ctx)->mbuf_priv1_off)
> +
> +static uint16_t
> +ip6_lookup_node_process_scalar(struct rte_graph *graph, struct rte_node *node,
> + void **objs, uint16_t nb_objs)
> +{
> + struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
> + struct rte_lpm6 *lpm6 = IP6_LOOKUP_NODE_LPM(node->ctx);
> + const int dyn = IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx);
> + struct rte_ipv6_hdr *ipv6_hdr;
> + void **to_next, **from;
> + uint16_t last_spec = 0;
> + rte_edge_t next_index;
> + uint16_t n_left_from;
> + uint16_t held = 0;
> + uint32_t drop_nh;
> + int i, rc;
> +
> + /* Speculative next */
> + next_index = RTE_NODE_IP6_LOOKUP_NEXT_REWRITE;
> + /* Drop node */
> + drop_nh = ((uint32_t)RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP) << 16;
> +
> + pkts = (struct rte_mbuf **)objs;
> + from = objs;
> + n_left_from = nb_objs;
> +
> + for (i = OBJS_PER_CLINE; i < RTE_GRAPH_BURST_SIZE; i += OBJS_PER_CLINE)
> + rte_prefetch0(&objs[i]);
> +
> + for (i = 0; i < 4 && i < n_left_from; i++)
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[i], void *,
> + sizeof(struct rte_ether_hdr)));
> +
> + /* Get stream for the speculated next node */
> + to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
> + while (n_left_from >= 4) {
> + uint8_t ip_batch[4][16];
> + int32_t next_hop[4];
> + uint16_t next[4];
> +
> +#if RTE_GRAPH_BURST_SIZE > 64
> + /* Prefetch next-next mbufs */
> + if (likely(n_left_from > 11)) {
> + rte_prefetch0(pkts[8]);
> + rte_prefetch0(pkts[9]);
> + rte_prefetch0(pkts[10]);
> + rte_prefetch0(pkts[11]);
> + }
> +#endif
> + /* Prefetch next mbuf data */
> + if (likely(n_left_from > 7)) {
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[4], void *,
> + sizeof(struct rte_ether_hdr)));
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[5], void *,
> + sizeof(struct rte_ether_hdr)));
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[6], void *,
> + sizeof(struct rte_ether_hdr)));
> + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[7], void *,
> + sizeof(struct rte_ether_hdr)));
> + }
> +
> + mbuf0 = pkts[0];
> + mbuf1 = pkts[1];
> + mbuf2 = pkts[2];
> + mbuf3 = pkts[3];
> +
> + pkts += 4;
> + n_left_from -= 4;
> +
> + /* Extract DIP of mbuf0 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract hop_limits as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
> + rte_memcpy(ip_batch[0], ipv6_hdr->dst_addr, 16);
> +
> + /* Extract DIP of mbuf1 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf1, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract hop_limits as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf1, dyn)->ttl = ipv6_hdr->hop_limits;
> + rte_memcpy(ip_batch[1], ipv6_hdr->dst_addr, 16);
> +
> + /* Extract DIP of mbuf2 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf2, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract hop_limits as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf2, dyn)->ttl = ipv6_hdr->hop_limits;
> + rte_memcpy(ip_batch[2], ipv6_hdr->dst_addr, 16);
> +
> + /* Extract DIP of mbuf3 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf3, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract hop_limits as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf3, dyn)->ttl = ipv6_hdr->hop_limits;
> + rte_memcpy(ip_batch[3], ipv6_hdr->dst_addr, 16);
> +
> + rc = rte_lpm6_lookup_bulk_func(lpm6, ip_batch, next_hop, 4);
> +
> + next_hop[0] = (next_hop[0] < 0) ? (int32_t)drop_nh : next_hop[0];
> + node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop[0];
> + next[0] = (uint16_t)(next_hop[0] >> 16);
> +
> + next_hop[1] = (next_hop[1] < 0) ? (int32_t)drop_nh : next_hop[1];
> + node_mbuf_priv1(mbuf1, dyn)->nh = (uint16_t)next_hop[1];
> + next[1] = (uint16_t)(next_hop[1] >> 16);
> +
> + next_hop[2] = (next_hop[2] < 0) ? (int32_t)drop_nh : next_hop[2];
> + node_mbuf_priv1(mbuf2, dyn)->nh = (uint16_t)next_hop[2];
> + next[2] = (uint16_t)(next_hop[2] >> 16);
> +
> + next_hop[3] = (next_hop[3] < 0) ? (int32_t)drop_nh : next_hop[3];
> + node_mbuf_priv1(mbuf3, dyn)->nh = (uint16_t)next_hop[3];
> + next[3] = (uint16_t)(next_hop[3] >> 16);
> +
> + rte_edge_t fix_spec = ((next_index == next[0]) &&
> + (next_index == next[1]) &&
> + (next_index == next[2]) &&
> + (next_index == next[3]));
> +
> + if (unlikely(fix_spec == 0)) {
> + /* Copy things successfully speculated till now */
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + from += last_spec;
> + to_next += last_spec;
> + held += last_spec;
> + last_spec = 0;
> +
> + /* Next0 */
> + if (next_index == next[0]) {
> + to_next[0] = from[0];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next[0], from[0]);
> + }
> +
> + /* Next1 */
> + if (next_index == next[1]) {
> + to_next[0] = from[1];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next[1], from[1]);
> + }
> +
> + /* Next2 */
> + if (next_index == next[2]) {
> + to_next[0] = from[2];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next[2], from[2]);
> + }
> +
> + /* Next3 */
> + if (next_index == next[3]) {
> + to_next[0] = from[3];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next[3], from[3]);
> + }
> +
> + from += 4;
> + } else {
> + last_spec += 4;
> + }
> + }
> +
> + while (n_left_from > 0) {
> + uint32_t next_hop;
> + uint16_t next0;
> +
> + mbuf0 = pkts[0];
> +
> + pkts += 1;
> + n_left_from -= 1;
> +
> + /* Extract DIP of mbuf0 */
> + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr *,
> + sizeof(struct rte_ether_hdr));
> + /* Extract ttl as ipv6 hdr is in cache */
> + node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
> +
> + rc = rte_lpm6_lookup(lpm6, ipv6_hdr->dst_addr, &next_hop);
> + next_hop = (rc == 0) ? next_hop : drop_nh;
> +
> + node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop;
> + next_hop = next_hop >> 16;
> + next0 = (uint16_t)next_hop;
> +
> + if (unlikely(next_index ^ next0)) {
> + /* Copy things successfully speculated till now */
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + from += last_spec;
> + to_next += last_spec;
> + held += last_spec;
> + last_spec = 0;
> +
> + rte_node_enqueue_x1(graph, node, next0, from[0]);
> + from += 1;
> + } else {
> + last_spec += 1;
> + }
> + }
> +
> + /* !!! Home run !!! */
> + if (likely(last_spec == nb_objs)) {
> + rte_node_next_stream_move(graph, node, next_index);
> + return nb_objs;
> + }
> + held += last_spec;
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + rte_node_next_stream_put(graph, node, next_index, held);
> +
> + return nb_objs;
> +}
> +
> +int
> +rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
> + enum rte_node_ip6_lookup_next next_node)
> +{
> + char abuf[INET6_ADDRSTRLEN];
> + struct in6_addr in6;
> + uint8_t socket;
> + uint32_t val;
> + int ret;
> +
> + memcpy(in6.s6_addr, ip, RTE_LPM6_IPV6_ADDR_SIZE);
> + inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf));
> + /* Embedded next node id into 24 bit next hop */
> + val = ((next_node << 16) | next_hop) & ((1ull << 24) - 1);
> + node_dbg("ip6_lookup", "LPM: Adding route %s / %d nh (0x%x)", abuf,
> + depth, val);
> +
> + for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
> + if (!ip6_lookup_nm.lpm_tbl[socket])
> + continue;
> +
> + ret = rte_lpm6_add(ip6_lookup_nm.lpm_tbl[socket], ip, depth,
> + val);
> + if (ret < 0) {
> + node_err("ip6_lookup",
> + "Unable to add entry %s / %d nh (%x) to LPM "
> + "table on sock %d, rc=%d\n",
> + abuf, depth, val, socket, ret);
> + return ret;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int
> +setup_lpm6(struct ip6_lookup_node_main *nm, int socket)
> +{
> + struct rte_lpm6_config config_ipv6;
> + char s[RTE_LPM6_NAMESIZE];
> +
> + /* One LPM table per socket */
> + if (nm->lpm_tbl[socket])
> + return 0;
> +
> + /* create the LPM table */
> + config_ipv6.max_rules = IPV6_L3FWD_LPM_MAX_RULES;
> + config_ipv6.number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S;
> + config_ipv6.flags = 0;
> + snprintf(s, sizeof(s), "IPV6_L3FWD_LPM_%d", socket);
> + nm->lpm_tbl[socket] = rte_lpm6_create(s, socket, &config_ipv6);
> + if (nm->lpm_tbl[socket] == NULL)
> + return -rte_errno;
> +
> + return 0;
> +}
> +
> +static int
> +ip6_lookup_node_init(const struct rte_graph *graph, struct rte_node *node)
> +{
> + uint16_t socket, lcore_id;
> + static uint8_t init_once;
> + int rc;
> +
> + RTE_SET_USED(graph);
> + RTE_BUILD_BUG_ON(sizeof(struct ip6_lookup_node_ctx) > RTE_NODE_CTX_SZ);
> +
> + if (!init_once) {
> + node_mbuf_priv1_dynfield_offset =
> + rte_mbuf_dynfield_register(
> + &node_mbuf_priv1_dynfield_desc);
> + if (node_mbuf_priv1_dynfield_offset < 0)
> + return -rte_errno;
> +
> + /* Setup LPM tables for all sockets */
> + RTE_LCORE_FOREACH(lcore_id)
> + {
> + socket = rte_lcore_to_socket_id(lcore_id);
> + rc = setup_lpm6(&ip6_lookup_nm, socket);
> + if (rc) {
> + node_err("ip6_lookup",
> + "Failed to setup lpm6 tbl for "
> + "sock %u, rc=%d", socket, rc);
> + return rc;
> + }
> + }
> + init_once = 1;
> + }
> +
> + /* Update socket's LPM and mbuf dyn priv1 offset in node ctx */
> + IP6_LOOKUP_NODE_LPM(node->ctx) = ip6_lookup_nm.lpm_tbl[graph->socket];
> + IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx) =
> + node_mbuf_priv1_dynfield_offset;
> +
> + node_dbg("ip6_lookup", "Initialized ip6_lookup node");
> +
> + return 0;
> +}
> +
> +static struct rte_node_register ip6_lookup_node = {
> + .process = ip6_lookup_node_process_scalar,
> + .name = "ip6_lookup",
> +
> + .init = ip6_lookup_node_init,
> +
> + .nb_edges = RTE_NODE_IP6_LOOKUP_NEXT_MAX,
> + .next_nodes = {
> + [RTE_NODE_IP6_LOOKUP_NEXT_REWRITE] = "ip6_rewrite",
> + [RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP] = "pkt_drop",
> + },
> +};
> +
> +RTE_NODE_REGISTER(ip6_lookup_node);
> diff --git a/lib/node/meson.build b/lib/node/meson.build
> index dbdf673c86..cd30847a0b 100644
> --- a/lib/node/meson.build
> +++ b/lib/node/meson.build
> @@ -12,13 +12,14 @@ sources = files(
> 'ethdev_rx.c',
> 'ethdev_tx.c',
> 'ip4_lookup.c',
> + 'ip6_lookup.c',
> 'ip4_rewrite.c',
> 'log.c',
> 'null.c',
> 'pkt_cls.c',
> 'pkt_drop.c',
> )
> -headers = files('rte_node_ip4_api.h', 'rte_node_eth_api.h')
> +headers = files('rte_node_ip4_api.h', 'rte_node_ip6_api.h', 'rte_node_eth_api.h')
> # Strict-aliasing rules are violated by uint8_t[] to context size casts.
> cflags += '-fno-strict-aliasing'
> deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev']
> diff --git a/lib/node/node_private.h b/lib/node/node_private.h
> index 8c73d5dc10..26135aaa5b 100644
> --- a/lib/node/node_private.h
> +++ b/lib/node/node_private.h
> @@ -26,7 +26,7 @@ extern int rte_node_logtype;
> */
> struct node_mbuf_priv1 {
> union {
> - /* IP4 rewrite */
> + /* IP4/IP6 rewrite */
> struct {
> uint16_t nh;
> uint16_t ttl;
> diff --git a/lib/node/pkt_cls.c b/lib/node/pkt_cls.c
> index 3e75f2cf78..a8302b8d28 100644
> --- a/lib/node/pkt_cls.c
> +++ b/lib/node/pkt_cls.c
> @@ -24,6 +24,19 @@ static const uint8_t p_nxt[256] __rte_cache_aligned = {
>
> [RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
> PKT_CLS_NEXT_IP4_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6_EXT] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L2_ETHER] = PKT_CLS_NEXT_IP6_LOOKUP,
> +
> + [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
> + PKT_CLS_NEXT_IP6_LOOKUP,
> };
>
> static uint16_t
> @@ -216,6 +229,7 @@ struct rte_node_register pkt_cls_node = {
> /* Pkt drop node starts at '0' */
> [PKT_CLS_NEXT_PKT_DROP] = "pkt_drop",
> [PKT_CLS_NEXT_IP4_LOOKUP] = "ip4_lookup",
> + [PKT_CLS_NEXT_IP6_LOOKUP] = "ip6_lookup",
> },
> };
> RTE_NODE_REGISTER(pkt_cls_node);
> diff --git a/lib/node/pkt_cls_priv.h b/lib/node/pkt_cls_priv.h
> index 6f5374f0be..16135807a1 100644
> --- a/lib/node/pkt_cls_priv.h
> +++ b/lib/node/pkt_cls_priv.h
> @@ -13,6 +13,7 @@ struct pkt_cls_node_ctx {
> enum pkt_cls_next_nodes {
> PKT_CLS_NEXT_PKT_DROP,
> PKT_CLS_NEXT_IP4_LOOKUP,
> + PKT_CLS_NEXT_IP6_LOOKUP,
> PKT_CLS_NEXT_MAX,
> };
>
> diff --git a/lib/node/rte_node_ip6_api.h b/lib/node/rte_node_ip6_api.h
> new file mode 100644
> index 0000000000..1696ed154d
> --- /dev/null
> +++ b/lib/node/rte_node_ip6_api.h
> @@ -0,0 +1,80 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(C) 2023 Marvell.
> + */
> +
> +#ifndef __INCLUDE_RTE_NODE_IP6_API_H__
> +#define __INCLUDE_RTE_NODE_IP6_API_H__
> +
> +/**
> + * @file rte_node_ip6_api.h
> + *
> + * @warning
> + * @b EXPERIMENTAL:
> + * All functions in this file may be changed or removed without prior notice.
> + *
> + * This API allows to do control path functions of ip6_* nodes
> + * like ip6_lookup, ip6_rewrite.
> + *
> + */
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +#include <rte_common.h>
> +#include <rte_compat.h>
> +
> +/**
> + * IP6 lookup next nodes.
> + */
> +enum rte_node_ip6_lookup_next {
> + RTE_NODE_IP6_LOOKUP_NEXT_REWRITE,
> + /**< Rewrite node. */
> + RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP,
> + /**< Packet drop node. */
> + RTE_NODE_IP6_LOOKUP_NEXT_MAX,
> + /**< Number of next nodes of lookup node. */
> +};
> +
> +/**
> + * Add ipv6 route to lookup table.
> + *
> + * @param ip
> + * IPv6 address of route to be added.
> + * @param depth
> + * Depth of the rule to be added.
> + * @param next_hop
> + * Next hop id of the rule result to be added.
> + * @param next_node
> + * Next node to redirect traffic to.
> + *
> + * @return
> + * 0 on success, negative otherwise.
> + */
> +__rte_experimental
> +int rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t next_hop,
> + enum rte_node_ip6_lookup_next next_node);
> +
> +/**
> + * Add a next hop's rewrite data.
> + *
> + * @param next_hop
> + * Next hop id to add rewrite data to.
> + * @param rewrite_data
> + * Rewrite data.
> + * @param rewrite_len
> + * Length of rewrite data.
> + * @param dst_port
> + * Destination port to redirect traffic to.
> + *
> + * @return
> + * 0 on success, negative otherwise.
> + */
> +__rte_experimental
> +int rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
> + uint8_t rewrite_len, uint16_t dst_port);
> +
> +#ifdef __cplusplus
> +}
> +#endif
> +
> +#endif /* __INCLUDE_RTE_NODE_IP6_API_H__ */
> diff --git a/lib/node/version.map b/lib/node/version.map
> index a799b0d389..40df308bfe 100644
> --- a/lib/node/version.map
> +++ b/lib/node/version.map
> @@ -4,6 +4,8 @@ EXPERIMENTAL {
> rte_node_eth_config;
> rte_node_ip4_route_add;
> rte_node_ip4_rewrite_add;
> + rte_node_ip6_rewrite_add;
> + rte_node_ip6_route_add;
> rte_node_logtype;
> local: *;
> };
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 2/3] lib: add IPv6 rewrite node
2023-05-31 11:37 ` [PATCH v3 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
@ 2023-06-01 2:26 ` Nithin Dabilpuram
2023-06-05 16:29 ` Nithin Dabilpuram
1 sibling, 0 replies; 18+ messages in thread
From: Nithin Dabilpuram @ 2023-06-01 2:26 UTC (permalink / raw)
To: Amit Prakash Shukla
Cc: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh,
dev, skori
Series Acked-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
On Wed, May 31, 2023 at 5:08 PM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
>
> Similar to IPv4 rewrite node, patch adds IPv6 rewrite node.
>
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
> v2:
> - Performance related changes
>
> v3:
> - Removing redundant dynamic variable
>
> doc/guides/prog_guide/graph_lib.rst | 8 +
> lib/node/ethdev_ctrl.c | 13 ++
> lib/node/ip6_rewrite.c | 331 ++++++++++++++++++++++++++++
> lib/node/ip6_rewrite_priv.h | 69 ++++++
> lib/node/meson.build | 1 +
> 5 files changed, 422 insertions(+)
> create mode 100644 lib/node/ip6_rewrite.c
> create mode 100644 lib/node/ip6_rewrite_priv.h
>
> diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
> index 1f70d63628..841cabe259 100644
> --- a/doc/guides/prog_guide/graph_lib.rst
> +++ b/doc/guides/prog_guide/graph_lib.rst
> @@ -401,6 +401,14 @@ On LPM lookup failure, objects are redirected to pkt_drop node.
> To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
> sections.
>
> +ip6_rewrite
> +~~~~~~~~~~~
> +This node gets packets from ``ip6_lookup`` node with next-hop id for each
> +packet is embedded in ``node_mbuf_priv1(mbuf)->nh``. This id is used
> +to determine the L2 header to be written to the packet before sending
> +the packet out to a particular ethdev_tx node.
> +``rte_node_ip6_rewrite_add()`` is control path API to add next-hop info.
> +
> null
> ~~~~
> This node ignores the set of objects passed to it and reports that all are
> diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
> index 37df0431b8..ea7dc8210b 100644
> --- a/lib/node/ethdev_ctrl.c
> +++ b/lib/node/ethdev_ctrl.c
> @@ -12,6 +12,7 @@
> #include "ethdev_rx_priv.h"
> #include "ethdev_tx_priv.h"
> #include "ip4_rewrite_priv.h"
> +#include "ip6_rewrite_priv.h"
> #include "node_private.h"
>
> static struct ethdev_ctrl {
> @@ -23,6 +24,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
> uint16_t nb_graphs)
> {
> struct rte_node_register *ip4_rewrite_node;
> + struct rte_node_register *ip6_rewrite_node;
> struct ethdev_tx_node_main *tx_node_data;
> uint16_t tx_q_used, rx_q_used, port_id;
> struct rte_node_register *tx_node;
> @@ -33,6 +35,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
> uint32_t id;
>
> ip4_rewrite_node = ip4_rewrite_node_get();
> + ip6_rewrite_node = ip6_rewrite_node_get();
> tx_node_data = ethdev_tx_node_data_get();
> tx_node = ethdev_tx_node_get();
> for (i = 0; i < nb_confs; i++) {
> @@ -110,6 +113,16 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
> port_id, rte_node_edge_count(ip4_rewrite_node->id) - 1);
> if (rc < 0)
> return rc;
> +
> + /* Add this tx port node as next to ip6_rewrite_node */
> + rte_node_edge_update(ip6_rewrite_node->id, RTE_EDGE_ID_INVALID,
> + &next_nodes, 1);
> + /* Assuming edge id is the last one alloc'ed */
> + rc = ip6_rewrite_set_next(
> + port_id, rte_node_edge_count(ip6_rewrite_node->id) - 1);
> + if (rc < 0)
> + return rc;
> +
> }
>
> ctrl.nb_graphs = nb_graphs;
> diff --git a/lib/node/ip6_rewrite.c b/lib/node/ip6_rewrite.c
> new file mode 100644
> index 0000000000..198d8d8820
> --- /dev/null
> +++ b/lib/node/ip6_rewrite.c
> @@ -0,0 +1,331 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(C) 2023 Marvell.
> + */
> +
> +#include <rte_ethdev.h>
> +#include <rte_ether.h>
> +#include <rte_graph.h>
> +#include <rte_graph_worker.h>
> +#include <rte_ip.h>
> +#include <rte_malloc.h>
> +#include <rte_vect.h>
> +
> +#include "rte_node_ip6_api.h"
> +
> +#include "ip6_rewrite_priv.h"
> +#include "node_private.h"
> +
> +struct ip6_rewrite_node_ctx {
> + /* Dynamic offset to mbuf priv1 */
> + int mbuf_priv1_off;
> + /* Cached next index */
> + uint16_t next_index;
> +};
> +
> +static struct ip6_rewrite_node_main *ip6_rewrite_nm;
> +
> +#define IP6_REWRITE_NODE_LAST_NEXT(ctx) \
> + (((struct ip6_rewrite_node_ctx *)ctx)->next_index)
> +
> +#define IP6_REWRITE_NODE_PRIV1_OFF(ctx) \
> + (((struct ip6_rewrite_node_ctx *)ctx)->mbuf_priv1_off)
> +
> +static uint16_t
> +ip6_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
> + void **objs, uint16_t nb_objs)
> +{
> + struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
> + struct ip6_rewrite_nh_header *nh = ip6_rewrite_nm->nh;
> + const int dyn = IP6_REWRITE_NODE_PRIV1_OFF(node->ctx);
> + uint16_t next0, next1, next2, next3, next_index;
> + uint16_t n_left_from, held = 0, last_spec = 0;
> + struct rte_ipv6_hdr *ip0, *ip1, *ip2, *ip3;
> + void *d0, *d1, *d2, *d3;
> + void **to_next, **from;
> + rte_xmm_t priv01;
> + rte_xmm_t priv23;
> + int i;
> +
> + /* Speculative next as last next */
> + next_index = IP6_REWRITE_NODE_LAST_NEXT(node->ctx);
> + rte_prefetch0(nh);
> +
> + pkts = (struct rte_mbuf **)objs;
> + from = objs;
> + n_left_from = nb_objs;
> +
> + for (i = 0; i < 4 && i < n_left_from; i++)
> + rte_prefetch0(pkts[i]);
> +
> + /* Get stream for the speculated next node */
> + to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
> + /* Update Ethernet header of pkts */
> + while (n_left_from >= 4) {
> + if (likely(n_left_from > 7)) {
> + /* Prefetch only next-mbuf struct and priv area.
> + * Data need not be prefetched as we only write.
> + */
> + rte_prefetch0(pkts[4]);
> + rte_prefetch0(pkts[5]);
> + rte_prefetch0(pkts[6]);
> + rte_prefetch0(pkts[7]);
> + }
> +
> + mbuf0 = pkts[0];
> + mbuf1 = pkts[1];
> + mbuf2 = pkts[2];
> + mbuf3 = pkts[3];
> +
> + pkts += 4;
> + n_left_from -= 4;
> + priv01.u64[0] = node_mbuf_priv1(mbuf0, dyn)->u;
> + priv01.u64[1] = node_mbuf_priv1(mbuf1, dyn)->u;
> + priv23.u64[0] = node_mbuf_priv1(mbuf2, dyn)->u;
> + priv23.u64[1] = node_mbuf_priv1(mbuf3, dyn)->u;
> +
> + /* Update next_hop rewrite ethernet hdr on mbuf0 */
> + d0 = rte_pktmbuf_mtod(mbuf0, void *);
> + rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,
> + nh[priv01.u16[0]].rewrite_len);
> +
> + next0 = nh[priv01.u16[0]].tx_node;
> + ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
> + sizeof(struct rte_ether_hdr));
> + ip0->hop_limits = priv01.u16[1] - 1;
> +
> + /* Update next_hop rewrite ethernet hdr on mbuf1 */
> + d1 = rte_pktmbuf_mtod(mbuf1, void *);
> + rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,
> + nh[priv01.u16[4]].rewrite_len);
> +
> + next1 = nh[priv01.u16[4]].tx_node;
> + ip1 = (struct rte_ipv6_hdr *)((uint8_t *)d1 +
> + sizeof(struct rte_ether_hdr));
> + ip1->hop_limits = priv01.u16[5] - 1;
> +
> + /* Update next_hop rewrite ethernet hdr on mbuf2 */
> + d2 = rte_pktmbuf_mtod(mbuf2, void *);
> + rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,
> + nh[priv23.u16[0]].rewrite_len);
> + next2 = nh[priv23.u16[0]].tx_node;
> + ip2 = (struct rte_ipv6_hdr *)((uint8_t *)d2 +
> + sizeof(struct rte_ether_hdr));
> + ip2->hop_limits = priv23.u16[1] - 1;
> +
> + /* Update next_hop rewrite ethernet hdr on mbuf3 */
> + d3 = rte_pktmbuf_mtod(mbuf3, void *);
> + rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,
> + nh[priv23.u16[4]].rewrite_len);
> +
> + next3 = nh[priv23.u16[4]].tx_node;
> + ip3 = (struct rte_ipv6_hdr *)((uint8_t *)d3 +
> + sizeof(struct rte_ether_hdr));
> + ip3->hop_limits = priv23.u16[5] - 1;
> +
> + /* Enqueue four packets to next node */
> + rte_edge_t fix_spec =
> + ((next_index == next0) && (next0 == next1) &&
> + (next1 == next2) && (next2 == next3));
> +
> + if (unlikely(fix_spec == 0)) {
> + /* Copy things successfully speculated till now */
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + from += last_spec;
> + to_next += last_spec;
> + held += last_spec;
> + last_spec = 0;
> +
> + /* next0 */
> + if (next_index == next0) {
> + to_next[0] = from[0];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next0,
> + from[0]);
> + }
> +
> + /* next1 */
> + if (next_index == next1) {
> + to_next[0] = from[1];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next1,
> + from[1]);
> + }
> +
> + /* next2 */
> + if (next_index == next2) {
> + to_next[0] = from[2];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next2,
> + from[2]);
> + }
> +
> + /* next3 */
> + if (next_index == next3) {
> + to_next[0] = from[3];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next3,
> + from[3]);
> + }
> +
> + from += 4;
> +
> + /* Change speculation if last two are same */
> + if ((next_index != next3) && (next2 == next3)) {
> + /* Put the current speculated node */
> + rte_node_next_stream_put(graph, node,
> + next_index, held);
> + held = 0;
> +
> + /* Get next speculated stream */
> + next_index = next3;
> + to_next = rte_node_next_stream_get(
> + graph, node, next_index, nb_objs);
> + }
> + } else {
> + last_spec += 4;
> + }
> + }
> +
> + while (n_left_from > 0) {
> + mbuf0 = pkts[0];
> +
> + pkts += 1;
> + n_left_from -= 1;
> +
> + d0 = rte_pktmbuf_mtod(mbuf0, void *);
> + rte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,
> + nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);
> +
> + next0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node;
> + ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
> + sizeof(struct rte_ether_hdr));
> + ip0->hop_limits = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;
> +
> + if (unlikely(next_index ^ next0)) {
> + /* Copy things successfully speculated till now */
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + from += last_spec;
> + to_next += last_spec;
> + held += last_spec;
> + last_spec = 0;
> +
> + rte_node_enqueue_x1(graph, node, next0, from[0]);
> + from += 1;
> + } else {
> + last_spec += 1;
> + }
> + }
> +
> + /* !!! Home run !!! */
> + if (likely(last_spec == nb_objs)) {
> + rte_node_next_stream_move(graph, node, next_index);
> + return nb_objs;
> + }
> +
> + held += last_spec;
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + rte_node_next_stream_put(graph, node, next_index, held);
> + /* Save the last next used */
> + IP6_REWRITE_NODE_LAST_NEXT(node->ctx) = next_index;
> +
> + return nb_objs;
> +}
> +
> +static int
> +ip6_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
> +{
> + static bool init_once;
> +
> + RTE_SET_USED(graph);
> + RTE_BUILD_BUG_ON(sizeof(struct ip6_rewrite_node_ctx) > RTE_NODE_CTX_SZ);
> +
> + if (!init_once) {
> + node_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register(
> + &node_mbuf_priv1_dynfield_desc);
> + if (node_mbuf_priv1_dynfield_offset < 0)
> + return -rte_errno;
> + init_once = true;
> + }
> + IP6_REWRITE_NODE_PRIV1_OFF(node->ctx) = node_mbuf_priv1_dynfield_offset;
> +
> + node_dbg("ip6_rewrite", "Initialized ip6_rewrite node");
> +
> + return 0;
> +}
> +
> +int
> +ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index)
> +{
> + if (ip6_rewrite_nm == NULL) {
> + ip6_rewrite_nm = rte_zmalloc(
> + "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
> + RTE_CACHE_LINE_SIZE);
> + if (ip6_rewrite_nm == NULL)
> + return -ENOMEM;
> + }
> + ip6_rewrite_nm->next_index[port_id] = next_index;
> +
> + return 0;
> +}
> +
> +int
> +rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
> + uint8_t rewrite_len, uint16_t dst_port)
> +{
> + struct ip6_rewrite_nh_header *nh;
> +
> + if (next_hop >= RTE_GRAPH_IP6_REWRITE_MAX_NH)
> + return -EINVAL;
> +
> + if (rewrite_len > RTE_GRAPH_IP6_REWRITE_MAX_LEN)
> + return -EINVAL;
> +
> + if (ip6_rewrite_nm == NULL) {
> + ip6_rewrite_nm = rte_zmalloc(
> + "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
> + RTE_CACHE_LINE_SIZE);
> + if (ip6_rewrite_nm == NULL)
> + return -ENOMEM;
> + }
> +
> + /* Check if dst port doesn't exist as edge */
> + if (!ip6_rewrite_nm->next_index[dst_port])
> + return -EINVAL;
> +
> + /* Update next hop */
> + nh = &ip6_rewrite_nm->nh[next_hop];
> +
> + memcpy(nh->rewrite_data, rewrite_data, rewrite_len);
> + nh->tx_node = ip6_rewrite_nm->next_index[dst_port];
> + nh->rewrite_len = rewrite_len;
> + nh->enabled = true;
> +
> + return 0;
> +}
> +
> +static struct rte_node_register ip6_rewrite_node = {
> + .process = ip6_rewrite_node_process,
> + .name = "ip6_rewrite",
> + /* Default edge i.e '0' is pkt drop */
> + .nb_edges = 1,
> + .next_nodes = {
> + [0] = "pkt_drop",
> + },
> + .init = ip6_rewrite_node_init,
> +};
> +
> +struct rte_node_register *
> +ip6_rewrite_node_get(void)
> +{
> + return &ip6_rewrite_node;
> +}
> +
> +RTE_NODE_REGISTER(ip6_rewrite_node);
> diff --git a/lib/node/ip6_rewrite_priv.h b/lib/node/ip6_rewrite_priv.h
> new file mode 100644
> index 0000000000..93db28bec0
> --- /dev/null
> +++ b/lib/node/ip6_rewrite_priv.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(C) 2023 Marvell.
> + */
> +#ifndef __INCLUDE_IP6_REWRITE_PRIV_H__
> +#define __INCLUDE_IP6_REWRITE_PRIV_H__
> +
> +#include <rte_common.h>
> +
> +#define RTE_GRAPH_IP6_REWRITE_MAX_NH 64
> +#define RTE_GRAPH_IP6_REWRITE_MAX_LEN 56
> +
> +/**
> + * @internal
> + *
> + * Ipv6 rewrite next hop header data structure. Used to store port specific
> + * rewrite data.
> + */
> +struct ip6_rewrite_nh_header {
> + uint16_t rewrite_len; /**< Header rewrite length. */
> + uint16_t tx_node; /**< Tx node next index identifier. */
> + uint16_t enabled; /**< NH enable flag */
> + uint16_t rsvd;
> + union {
> + struct {
> + struct rte_ether_addr dst;
> + /**< Destination mac address. */
> + struct rte_ether_addr src;
> + /**< Source mac address. */
> + };
> + uint8_t rewrite_data[RTE_GRAPH_IP6_REWRITE_MAX_LEN];
> + /**< Generic rewrite data */
> + };
> +};
> +
> +/**
> + * @internal
> + *
> + * Ipv6 node main data structure.
> + */
> +struct ip6_rewrite_node_main {
> + struct ip6_rewrite_nh_header nh[RTE_GRAPH_IP6_REWRITE_MAX_NH];
> + /**< Array of next hop header data */
> + uint16_t next_index[RTE_MAX_ETHPORTS];
> + /**< Next index of each configured port. */
> +};
> +
> +/**
> + * @internal
> + *
> + * Get the ipv6 rewrite node.
> + *
> + * @return
> + * Pointer to the ipv6 rewrite node.
> + */
> +struct rte_node_register *ip6_rewrite_node_get(void);
> +
> +/**
> + * @internal
> + *
> + * Set the Edge index of a given port_id.
> + *
> + * @param port_id
> + * Ethernet port identifier.
> + * @param next_index
> + * Edge index of the Given Tx node.
> + */
> +int ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index);
> +
> +#endif /* __INCLUDE_IP6_REWRITE_PRIV_H__ */
> diff --git a/lib/node/meson.build b/lib/node/meson.build
> index cd30847a0b..b2f04269c5 100644
> --- a/lib/node/meson.build
> +++ b/lib/node/meson.build
> @@ -14,6 +14,7 @@ sources = files(
> 'ip4_lookup.c',
> 'ip6_lookup.c',
> 'ip4_rewrite.c',
> + 'ip6_rewrite.c',
> 'log.c',
> 'null.c',
> 'pkt_cls.c',
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 2/3] lib: add IPv6 rewrite node
2023-05-31 11:37 ` [PATCH v3 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
2023-06-01 2:26 ` Nithin Dabilpuram
@ 2023-06-05 16:29 ` Nithin Dabilpuram
1 sibling, 0 replies; 18+ messages in thread
From: Nithin Dabilpuram @ 2023-06-05 16:29 UTC (permalink / raw)
To: Amit Prakash Shukla
Cc: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, Pavan Nikhilesh,
dev, skori
Acked-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
On Wed, May 31, 2023 at 5:08 PM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
>
> Similar to IPv4 rewrite node, patch adds IPv6 rewrite node.
>
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
> v2:
> - Performance related changes
>
> v3:
> - Removing redundant dynamic variable
>
> doc/guides/prog_guide/graph_lib.rst | 8 +
> lib/node/ethdev_ctrl.c | 13 ++
> lib/node/ip6_rewrite.c | 331 ++++++++++++++++++++++++++++
> lib/node/ip6_rewrite_priv.h | 69 ++++++
> lib/node/meson.build | 1 +
> 5 files changed, 422 insertions(+)
> create mode 100644 lib/node/ip6_rewrite.c
> create mode 100644 lib/node/ip6_rewrite_priv.h
>
> diff --git a/doc/guides/prog_guide/graph_lib.rst b/doc/guides/prog_guide/graph_lib.rst
> index 1f70d63628..841cabe259 100644
> --- a/doc/guides/prog_guide/graph_lib.rst
> +++ b/doc/guides/prog_guide/graph_lib.rst
> @@ -401,6 +401,14 @@ On LPM lookup failure, objects are redirected to pkt_drop node.
> To achieve home run, node use ``rte_node_stream_move()`` as mentioned in above
> sections.
>
> +ip6_rewrite
> +~~~~~~~~~~~
> +This node gets packets from ``ip6_lookup`` node with next-hop id for each
> +packet is embedded in ``node_mbuf_priv1(mbuf)->nh``. This id is used
> +to determine the L2 header to be written to the packet before sending
> +the packet out to a particular ethdev_tx node.
> +``rte_node_ip6_rewrite_add()`` is control path API to add next-hop info.
> +
> null
> ~~~~
> This node ignores the set of objects passed to it and reports that all are
> diff --git a/lib/node/ethdev_ctrl.c b/lib/node/ethdev_ctrl.c
> index 37df0431b8..ea7dc8210b 100644
> --- a/lib/node/ethdev_ctrl.c
> +++ b/lib/node/ethdev_ctrl.c
> @@ -12,6 +12,7 @@
> #include "ethdev_rx_priv.h"
> #include "ethdev_tx_priv.h"
> #include "ip4_rewrite_priv.h"
> +#include "ip6_rewrite_priv.h"
> #include "node_private.h"
>
> static struct ethdev_ctrl {
> @@ -23,6 +24,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
> uint16_t nb_graphs)
> {
> struct rte_node_register *ip4_rewrite_node;
> + struct rte_node_register *ip6_rewrite_node;
> struct ethdev_tx_node_main *tx_node_data;
> uint16_t tx_q_used, rx_q_used, port_id;
> struct rte_node_register *tx_node;
> @@ -33,6 +35,7 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
> uint32_t id;
>
> ip4_rewrite_node = ip4_rewrite_node_get();
> + ip6_rewrite_node = ip6_rewrite_node_get();
> tx_node_data = ethdev_tx_node_data_get();
> tx_node = ethdev_tx_node_get();
> for (i = 0; i < nb_confs; i++) {
> @@ -110,6 +113,16 @@ rte_node_eth_config(struct rte_node_ethdev_config *conf, uint16_t nb_confs,
> port_id, rte_node_edge_count(ip4_rewrite_node->id) - 1);
> if (rc < 0)
> return rc;
> +
> + /* Add this tx port node as next to ip6_rewrite_node */
> + rte_node_edge_update(ip6_rewrite_node->id, RTE_EDGE_ID_INVALID,
> + &next_nodes, 1);
> + /* Assuming edge id is the last one alloc'ed */
> + rc = ip6_rewrite_set_next(
> + port_id, rte_node_edge_count(ip6_rewrite_node->id) - 1);
> + if (rc < 0)
> + return rc;
> +
> }
>
> ctrl.nb_graphs = nb_graphs;
> diff --git a/lib/node/ip6_rewrite.c b/lib/node/ip6_rewrite.c
> new file mode 100644
> index 0000000000..198d8d8820
> --- /dev/null
> +++ b/lib/node/ip6_rewrite.c
> @@ -0,0 +1,331 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(C) 2023 Marvell.
> + */
> +
> +#include <rte_ethdev.h>
> +#include <rte_ether.h>
> +#include <rte_graph.h>
> +#include <rte_graph_worker.h>
> +#include <rte_ip.h>
> +#include <rte_malloc.h>
> +#include <rte_vect.h>
> +
> +#include "rte_node_ip6_api.h"
> +
> +#include "ip6_rewrite_priv.h"
> +#include "node_private.h"
> +
> +struct ip6_rewrite_node_ctx {
> + /* Dynamic offset to mbuf priv1 */
> + int mbuf_priv1_off;
> + /* Cached next index */
> + uint16_t next_index;
> +};
> +
> +static struct ip6_rewrite_node_main *ip6_rewrite_nm;
> +
> +#define IP6_REWRITE_NODE_LAST_NEXT(ctx) \
> + (((struct ip6_rewrite_node_ctx *)ctx)->next_index)
> +
> +#define IP6_REWRITE_NODE_PRIV1_OFF(ctx) \
> + (((struct ip6_rewrite_node_ctx *)ctx)->mbuf_priv1_off)
> +
> +static uint16_t
> +ip6_rewrite_node_process(struct rte_graph *graph, struct rte_node *node,
> + void **objs, uint16_t nb_objs)
> +{
> + struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
> + struct ip6_rewrite_nh_header *nh = ip6_rewrite_nm->nh;
> + const int dyn = IP6_REWRITE_NODE_PRIV1_OFF(node->ctx);
> + uint16_t next0, next1, next2, next3, next_index;
> + uint16_t n_left_from, held = 0, last_spec = 0;
> + struct rte_ipv6_hdr *ip0, *ip1, *ip2, *ip3;
> + void *d0, *d1, *d2, *d3;
> + void **to_next, **from;
> + rte_xmm_t priv01;
> + rte_xmm_t priv23;
> + int i;
> +
> + /* Speculative next as last next */
> + next_index = IP6_REWRITE_NODE_LAST_NEXT(node->ctx);
> + rte_prefetch0(nh);
> +
> + pkts = (struct rte_mbuf **)objs;
> + from = objs;
> + n_left_from = nb_objs;
> +
> + for (i = 0; i < 4 && i < n_left_from; i++)
> + rte_prefetch0(pkts[i]);
> +
> + /* Get stream for the speculated next node */
> + to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
> + /* Update Ethernet header of pkts */
> + while (n_left_from >= 4) {
> + if (likely(n_left_from > 7)) {
> + /* Prefetch only next-mbuf struct and priv area.
> + * Data need not be prefetched as we only write.
> + */
> + rte_prefetch0(pkts[4]);
> + rte_prefetch0(pkts[5]);
> + rte_prefetch0(pkts[6]);
> + rte_prefetch0(pkts[7]);
> + }
> +
> + mbuf0 = pkts[0];
> + mbuf1 = pkts[1];
> + mbuf2 = pkts[2];
> + mbuf3 = pkts[3];
> +
> + pkts += 4;
> + n_left_from -= 4;
> + priv01.u64[0] = node_mbuf_priv1(mbuf0, dyn)->u;
> + priv01.u64[1] = node_mbuf_priv1(mbuf1, dyn)->u;
> + priv23.u64[0] = node_mbuf_priv1(mbuf2, dyn)->u;
> + priv23.u64[1] = node_mbuf_priv1(mbuf3, dyn)->u;
> +
> + /* Update next_hop rewrite ethernet hdr on mbuf0 */
> + d0 = rte_pktmbuf_mtod(mbuf0, void *);
> + rte_memcpy(d0, nh[priv01.u16[0]].rewrite_data,
> + nh[priv01.u16[0]].rewrite_len);
> +
> + next0 = nh[priv01.u16[0]].tx_node;
> + ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
> + sizeof(struct rte_ether_hdr));
> + ip0->hop_limits = priv01.u16[1] - 1;
> +
> + /* Update next_hop rewrite ethernet hdr on mbuf1 */
> + d1 = rte_pktmbuf_mtod(mbuf1, void *);
> + rte_memcpy(d1, nh[priv01.u16[4]].rewrite_data,
> + nh[priv01.u16[4]].rewrite_len);
> +
> + next1 = nh[priv01.u16[4]].tx_node;
> + ip1 = (struct rte_ipv6_hdr *)((uint8_t *)d1 +
> + sizeof(struct rte_ether_hdr));
> + ip1->hop_limits = priv01.u16[5] - 1;
> +
> + /* Update next_hop rewrite ethernet hdr on mbuf2 */
> + d2 = rte_pktmbuf_mtod(mbuf2, void *);
> + rte_memcpy(d2, nh[priv23.u16[0]].rewrite_data,
> + nh[priv23.u16[0]].rewrite_len);
> + next2 = nh[priv23.u16[0]].tx_node;
> + ip2 = (struct rte_ipv6_hdr *)((uint8_t *)d2 +
> + sizeof(struct rte_ether_hdr));
> + ip2->hop_limits = priv23.u16[1] - 1;
> +
> + /* Update next_hop rewrite ethernet hdr on mbuf3 */
> + d3 = rte_pktmbuf_mtod(mbuf3, void *);
> + rte_memcpy(d3, nh[priv23.u16[4]].rewrite_data,
> + nh[priv23.u16[4]].rewrite_len);
> +
> + next3 = nh[priv23.u16[4]].tx_node;
> + ip3 = (struct rte_ipv6_hdr *)((uint8_t *)d3 +
> + sizeof(struct rte_ether_hdr));
> + ip3->hop_limits = priv23.u16[5] - 1;
> +
> + /* Enqueue four packets to next node */
> + rte_edge_t fix_spec =
> + ((next_index == next0) && (next0 == next1) &&
> + (next1 == next2) && (next2 == next3));
> +
> + if (unlikely(fix_spec == 0)) {
> + /* Copy things successfully speculated till now */
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + from += last_spec;
> + to_next += last_spec;
> + held += last_spec;
> + last_spec = 0;
> +
> + /* next0 */
> + if (next_index == next0) {
> + to_next[0] = from[0];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next0,
> + from[0]);
> + }
> +
> + /* next1 */
> + if (next_index == next1) {
> + to_next[0] = from[1];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next1,
> + from[1]);
> + }
> +
> + /* next2 */
> + if (next_index == next2) {
> + to_next[0] = from[2];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next2,
> + from[2]);
> + }
> +
> + /* next3 */
> + if (next_index == next3) {
> + to_next[0] = from[3];
> + to_next++;
> + held++;
> + } else {
> + rte_node_enqueue_x1(graph, node, next3,
> + from[3]);
> + }
> +
> + from += 4;
> +
> + /* Change speculation if last two are same */
> + if ((next_index != next3) && (next2 == next3)) {
> + /* Put the current speculated node */
> + rte_node_next_stream_put(graph, node,
> + next_index, held);
> + held = 0;
> +
> + /* Get next speculated stream */
> + next_index = next3;
> + to_next = rte_node_next_stream_get(
> + graph, node, next_index, nb_objs);
> + }
> + } else {
> + last_spec += 4;
> + }
> + }
> +
> + while (n_left_from > 0) {
> + mbuf0 = pkts[0];
> +
> + pkts += 1;
> + n_left_from -= 1;
> +
> + d0 = rte_pktmbuf_mtod(mbuf0, void *);
> + rte_memcpy(d0, nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_data,
> + nh[node_mbuf_priv1(mbuf0, dyn)->nh].rewrite_len);
> +
> + next0 = nh[node_mbuf_priv1(mbuf0, dyn)->nh].tx_node;
> + ip0 = (struct rte_ipv6_hdr *)((uint8_t *)d0 +
> + sizeof(struct rte_ether_hdr));
> + ip0->hop_limits = node_mbuf_priv1(mbuf0, dyn)->ttl - 1;
> +
> + if (unlikely(next_index ^ next0)) {
> + /* Copy things successfully speculated till now */
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + from += last_spec;
> + to_next += last_spec;
> + held += last_spec;
> + last_spec = 0;
> +
> + rte_node_enqueue_x1(graph, node, next0, from[0]);
> + from += 1;
> + } else {
> + last_spec += 1;
> + }
> + }
> +
> + /* !!! Home run !!! */
> + if (likely(last_spec == nb_objs)) {
> + rte_node_next_stream_move(graph, node, next_index);
> + return nb_objs;
> + }
> +
> + held += last_spec;
> + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> + rte_node_next_stream_put(graph, node, next_index, held);
> + /* Save the last next used */
> + IP6_REWRITE_NODE_LAST_NEXT(node->ctx) = next_index;
> +
> + return nb_objs;
> +}
> +
> +static int
> +ip6_rewrite_node_init(const struct rte_graph *graph, struct rte_node *node)
> +{
> + static bool init_once;
> +
> + RTE_SET_USED(graph);
> + RTE_BUILD_BUG_ON(sizeof(struct ip6_rewrite_node_ctx) > RTE_NODE_CTX_SZ);
> +
> + if (!init_once) {
> + node_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register(
> + &node_mbuf_priv1_dynfield_desc);
> + if (node_mbuf_priv1_dynfield_offset < 0)
> + return -rte_errno;
> + init_once = true;
> + }
> + IP6_REWRITE_NODE_PRIV1_OFF(node->ctx) = node_mbuf_priv1_dynfield_offset;
> +
> + node_dbg("ip6_rewrite", "Initialized ip6_rewrite node");
> +
> + return 0;
> +}
> +
> +int
> +ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index)
> +{
> + if (ip6_rewrite_nm == NULL) {
> + ip6_rewrite_nm = rte_zmalloc(
> + "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
> + RTE_CACHE_LINE_SIZE);
> + if (ip6_rewrite_nm == NULL)
> + return -ENOMEM;
> + }
> + ip6_rewrite_nm->next_index[port_id] = next_index;
> +
> + return 0;
> +}
> +
> +int
> +rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
> + uint8_t rewrite_len, uint16_t dst_port)
> +{
> + struct ip6_rewrite_nh_header *nh;
> +
> + if (next_hop >= RTE_GRAPH_IP6_REWRITE_MAX_NH)
> + return -EINVAL;
> +
> + if (rewrite_len > RTE_GRAPH_IP6_REWRITE_MAX_LEN)
> + return -EINVAL;
> +
> + if (ip6_rewrite_nm == NULL) {
> + ip6_rewrite_nm = rte_zmalloc(
> + "ip6_rewrite", sizeof(struct ip6_rewrite_node_main),
> + RTE_CACHE_LINE_SIZE);
> + if (ip6_rewrite_nm == NULL)
> + return -ENOMEM;
> + }
> +
> + /* Check if dst port doesn't exist as edge */
> + if (!ip6_rewrite_nm->next_index[dst_port])
> + return -EINVAL;
> +
> + /* Update next hop */
> + nh = &ip6_rewrite_nm->nh[next_hop];
> +
> + memcpy(nh->rewrite_data, rewrite_data, rewrite_len);
> + nh->tx_node = ip6_rewrite_nm->next_index[dst_port];
> + nh->rewrite_len = rewrite_len;
> + nh->enabled = true;
> +
> + return 0;
> +}
> +
> +static struct rte_node_register ip6_rewrite_node = {
> + .process = ip6_rewrite_node_process,
> + .name = "ip6_rewrite",
> + /* Default edge i.e '0' is pkt drop */
> + .nb_edges = 1,
> + .next_nodes = {
> + [0] = "pkt_drop",
> + },
> + .init = ip6_rewrite_node_init,
> +};
> +
> +struct rte_node_register *
> +ip6_rewrite_node_get(void)
> +{
> + return &ip6_rewrite_node;
> +}
> +
> +RTE_NODE_REGISTER(ip6_rewrite_node);
> diff --git a/lib/node/ip6_rewrite_priv.h b/lib/node/ip6_rewrite_priv.h
> new file mode 100644
> index 0000000000..93db28bec0
> --- /dev/null
> +++ b/lib/node/ip6_rewrite_priv.h
> @@ -0,0 +1,69 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(C) 2023 Marvell.
> + */
> +#ifndef __INCLUDE_IP6_REWRITE_PRIV_H__
> +#define __INCLUDE_IP6_REWRITE_PRIV_H__
> +
> +#include <rte_common.h>
> +
> +#define RTE_GRAPH_IP6_REWRITE_MAX_NH 64
> +#define RTE_GRAPH_IP6_REWRITE_MAX_LEN 56
> +
> +/**
> + * @internal
> + *
> + * Ipv6 rewrite next hop header data structure. Used to store port specific
> + * rewrite data.
> + */
> +struct ip6_rewrite_nh_header {
> + uint16_t rewrite_len; /**< Header rewrite length. */
> + uint16_t tx_node; /**< Tx node next index identifier. */
> + uint16_t enabled; /**< NH enable flag */
> + uint16_t rsvd;
> + union {
> + struct {
> + struct rte_ether_addr dst;
> + /**< Destination mac address. */
> + struct rte_ether_addr src;
> + /**< Source mac address. */
> + };
> + uint8_t rewrite_data[RTE_GRAPH_IP6_REWRITE_MAX_LEN];
> + /**< Generic rewrite data */
> + };
> +};
> +
> +/**
> + * @internal
> + *
> + * Ipv6 node main data structure.
> + */
> +struct ip6_rewrite_node_main {
> + struct ip6_rewrite_nh_header nh[RTE_GRAPH_IP6_REWRITE_MAX_NH];
> + /**< Array of next hop header data */
> + uint16_t next_index[RTE_MAX_ETHPORTS];
> + /**< Next index of each configured port. */
> +};
> +
> +/**
> + * @internal
> + *
> + * Get the ipv6 rewrite node.
> + *
> + * @return
> + * Pointer to the ipv6 rewrite node.
> + */
> +struct rte_node_register *ip6_rewrite_node_get(void);
> +
> +/**
> + * @internal
> + *
> + * Set the Edge index of a given port_id.
> + *
> + * @param port_id
> + * Ethernet port identifier.
> + * @param next_index
> + * Edge index of the Given Tx node.
> + */
> +int ip6_rewrite_set_next(uint16_t port_id, uint16_t next_index);
> +
> +#endif /* __INCLUDE_IP6_REWRITE_PRIV_H__ */
> diff --git a/lib/node/meson.build b/lib/node/meson.build
> index cd30847a0b..b2f04269c5 100644
> --- a/lib/node/meson.build
> +++ b/lib/node/meson.build
> @@ -14,6 +14,7 @@ sources = files(
> 'ip4_lookup.c',
> 'ip6_lookup.c',
> 'ip4_rewrite.c',
> + 'ip6_rewrite.c',
> 'log.c',
> 'null.c',
> 'pkt_cls.c',
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH v3 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support
2023-05-31 11:37 ` [PATCH v3 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
@ 2023-06-05 16:32 ` Nithin Dabilpuram
0 siblings, 0 replies; 18+ messages in thread
From: Nithin Dabilpuram @ 2023-06-05 16:32 UTC (permalink / raw)
To: Amit Prakash Shukla
Cc: Jerin Jacob, Kiran Kumar K, Nithin Dabilpuram, dev, skori
Acked-by: Nithin Dabilpuram <ndabilpuram@marvell.com>
On Wed, May 31, 2023 at 5:08 PM Amit Prakash Shukla
<amitprakashs@marvell.com> wrote:
>
> From: Sunil Kumar Kori <skori@marvell.com>
>
> Similar to ipv4, to support IPv6 lookup and rewrite node
> routes and rewrite data needs to be added.
>
> Patch adds routes for ipv6 to validate ip6_lookup node
> and rewrite data to validate ip6_rewrite node.
>
> Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
> Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> ---
> v2:
> - Performance related changes
>
> v3:
> - Removing redundant dynamic variable
>
> doc/guides/sample_app_ug/l3_forward_graph.rst | 40 ++++++----
> examples/l3fwd-graph/main.c | 77 ++++++++++++++++++-
> 2 files changed, 98 insertions(+), 19 deletions(-)
>
> diff --git a/doc/guides/sample_app_ug/l3_forward_graph.rst b/doc/guides/sample_app_ug/l3_forward_graph.rst
> index 585ac8c898..23f86e4785 100644
> --- a/doc/guides/sample_app_ug/l3_forward_graph.rst
> +++ b/doc/guides/sample_app_ug/l3_forward_graph.rst
> @@ -12,7 +12,8 @@ Overview
> --------
>
> The application demonstrates the use of the graph framework and graph nodes
> -``ethdev_rx``, ``ip4_lookup``, ``ip4_rewrite``, ``ethdev_tx`` and ``pkt_drop`` in DPDK to
> +``ethdev_rx``, ``pkt_cls``, ``ip4_lookup``/``ip6_lookup``,
> +``ip4_rewrite``/``ip6_rewrite``, ``ethdev_tx`` and ``pkt_drop`` in DPDK to
> implement packet forwarding.
>
> The initialization is very similar to those of the :doc:`l3_forward`.
> @@ -24,13 +25,15 @@ TTL update and finally Tx is implemented inside graph nodes. These nodes are
> interconnected in graph framework. Application main loop needs to walk over
> graph using ``rte_graph_walk()`` with graph objects created one per worker lcore.
>
> -The lookup method is as per implementation of ``ip4_lookup`` graph node.
> +The lookup method is as per implementation of ``ip4_lookup``/``ip6_lookup`` graph node.
> The ID of the output interface for the input packet is the next hop returned by
> the LPM lookup. The set of LPM rules used by the application is statically
> -configured and provided to ``ip4_lookup`` graph node and ``ip4_rewrite`` graph node
> -using node control API ``rte_node_ip4_route_add()`` and ``rte_node_ip4_rewrite_add()``.
> +configured and provided to ``ip4_lookup``/``ip6_lookup`` graph node and
> +``ip4_rewrite``/``ip6_rewrite`` graph node using node control API
> +``rte_node_ip4_route_add()``/``rte_node_ip6_route_add`` and
> +``rte_node_ip4_rewrite_add()``/``rte_node_ip6_rewrite_add``.
>
> -In the sample application, only IPv4 forwarding is supported as of now.
> +In the sample application, IPv4 and IPv6 forwarding is supported.
>
> Compiling the Application
> -------------------------
> @@ -149,8 +152,8 @@ lead to the clone of ``ethdev_rx`` and ``ethdev_tx`` nodes as ``ethdev_rx-X-Y``
> In case of ``ethdev_tx-X`` nodes, tx queue id assigned per instance of the node
> is same as graph id.
>
> -These cloned nodes along with existing static nodes such as ``ip4_lookup`` and
> -``ip4_rewrite`` will be used in graph creation to associate node's to lcore
> +These cloned nodes along with existing static nodes such as ``ip4_lookup``/``ip6_lookup``
> +and ``ip4_rewrite``/``ip6_rewrite`` will be used in graph creation to associate node's to lcore
> specific graph object.
>
> .. literalinclude:: ../../../examples/l3fwd-graph/main.c
> @@ -186,20 +189,21 @@ Forwarding data(Route, Next-Hop) addition
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>
> Once graph objects are created, node specific info like routes and rewrite
> -headers will be provided run-time using ``rte_node_ip4_route_add()`` and
> -``rte_node_ip4_rewrite_add()`` API.
> +headers will be provided run-time using ``rte_node_ip4_route_add()``/
> +``rte_node_ip6_route_add`` and ``rte_node_ip4_rewrite_add()``/``rte_node_ip6_rewrite_add``
> +API.
>
> .. note::
>
> - Since currently ``ip4_lookup`` and ``ip4_rewrite`` nodes don't support
> - lock-less mechanisms(RCU, etc) to add run-time forwarding data like route and
> - rewrite data, forwarding data is added before packet processing loop is
> - launched on worker lcore.
> + Since currently ``ip4_lookup``/``ip6_lookup`` and ``ip4_rewrite``/``ip6_rewrite``
> + nodes don't support lock-less mechanisms(RCU, etc) to add run-time forwarding
> + data like route and rewrite data, forwarding data is added before packet
> + processing loop is launched on worker lcore.
>
> .. literalinclude:: ../../../examples/l3fwd-graph/main.c
> :language: c
> - :start-after: Add route to ip4 graph infra. 8<
> - :end-before: >8 End of adding route to ip4 graph infa.
> + :start-after: Add routes and rewrite data to graph infra. 8<
> + :end-before: >8 End of adding routes and rewrite data to graph infa.
> :dedent: 1
>
> Packet Forwarding using Graph Walk
> @@ -215,8 +219,10 @@ specific graph object that was already created.
>
> rte_graph_walk() will walk over all the sources nodes i.e ``ethdev_rx-X-Y``
> associated with a given graph and Rx the available packets and enqueue them
> - to the following node ``ip4_lookup`` which then will enqueue them to ``ip4_rewrite``
> - node if LPM lookup succeeds. ``ip4_rewrite`` node then will update Ethernet header
> + to the following node ``pkt_cls`` which based on the packet type will enqueue
> + them to ``ip4_lookup``/``ip6_lookup`` which then will enqueue them to
> + ``ip4_rewrite``/``ip6_rewrite`` node if LPM lookup succeeds.
> + ``ip4_rewrite``/``ip6_rewrite`` node then will update Ethernet header
> as per next-hop data and transmit the packet via port 'Z' by enqueuing
> to ``ethdev_tx-Z`` node instance in its graph object.
>
> diff --git a/examples/l3fwd-graph/main.c b/examples/l3fwd-graph/main.c
> index 5feeab4f0f..0c82e24513 100644
> --- a/examples/l3fwd-graph/main.c
> +++ b/examples/l3fwd-graph/main.c
> @@ -27,9 +27,11 @@
> #include <rte_launch.h>
> #include <rte_lcore.h>
> #include <rte_log.h>
> +#include <rte_lpm6.h>
> #include <rte_mempool.h>
> #include <rte_node_eth_api.h>
> #include <rte_node_ip4_api.h>
> +#include <rte_node_ip6_api.h>
> #include <rte_per_lcore.h>
> #include <rte_string_fns.h>
> #include <rte_vect.h>
> @@ -142,6 +144,12 @@ struct ipv4_l3fwd_lpm_route {
> uint8_t if_out;
> };
>
> +struct ipv6_l3fwd_lpm_route {
> + uint8_t ip[RTE_LPM6_IPV6_ADDR_SIZE];
> + uint8_t depth;
> + uint8_t if_out;
> +};
> +
> #define IPV4_L3FWD_LPM_NUM_ROUTES \
> (sizeof(ipv4_l3fwd_lpm_route_array) / \
> sizeof(ipv4_l3fwd_lpm_route_array[0]))
> @@ -153,6 +161,28 @@ static struct ipv4_l3fwd_lpm_route ipv4_l3fwd_lpm_route_array[] = {
> {RTE_IPV4(198, 18, 6, 0), 24, 6}, {RTE_IPV4(198, 18, 7, 0), 24, 7},
> };
>
> +#define IPV6_L3FWD_LPM_NUM_ROUTES \
> + (sizeof(ipv6_l3fwd_lpm_route_array) / \
> + sizeof(ipv6_l3fwd_lpm_route_array[0]))
> +static struct ipv6_l3fwd_lpm_route ipv6_l3fwd_lpm_route_array[] = {
> + {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00}, 48, 0},
> + {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x01}, 48, 1},
> + {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x02}, 48, 2},
> + {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x03}, 48, 3},
> + {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x04}, 48, 4},
> + {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x05}, 48, 5},
> + {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x06}, 48, 6},
> + {{0x20, 0x01, 0xdb, 0x08, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x02}, 48, 7},
> +};
> +
> static int
> check_lcore_params(void)
> {
> @@ -1128,7 +1158,7 @@ main(int argc, char **argv)
> memset(&rewrite_data, 0, sizeof(rewrite_data));
> rewrite_len = sizeof(rewrite_data);
>
> - /* Add route to ip4 graph infra. 8< */
> + /* Add routes and rewrite data to graph infra. 8< */
> for (i = 0; i < IPV4_L3FWD_LPM_NUM_ROUTES; i++) {
> char route_str[INET6_ADDRSTRLEN * 4];
> char abuf[INET6_ADDRSTRLEN];
> @@ -1172,7 +1202,50 @@ main(int argc, char **argv)
> RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n",
> route_str, i);
> }
> - /* >8 End of adding route to ip4 graph infa. */
> +
> + for (i = 0; i < IPV6_L3FWD_LPM_NUM_ROUTES; i++) {
> + char route_str[INET6_ADDRSTRLEN * 4];
> + char abuf[INET6_ADDRSTRLEN];
> + struct in6_addr in6;
> + uint32_t dst_port;
> +
> + /* Skip unused ports */
> + if ((1 << ipv6_l3fwd_lpm_route_array[i].if_out &
> + enabled_port_mask) == 0)
> + continue;
> +
> + dst_port = ipv6_l3fwd_lpm_route_array[i].if_out;
> +
> + memcpy(in6.s6_addr, ipv6_l3fwd_lpm_route_array[i].ip, RTE_LPM6_IPV6_ADDR_SIZE);
> + snprintf(route_str, sizeof(route_str), "%s / %d (%d)",
> + inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf)),
> + ipv6_l3fwd_lpm_route_array[i].depth,
> + ipv6_l3fwd_lpm_route_array[i].if_out);
> +
> + /* Use route index 'i' as next hop id */
> + ret = rte_node_ip6_route_add(ipv6_l3fwd_lpm_route_array[i].ip,
> + ipv6_l3fwd_lpm_route_array[i].depth, i,
> + RTE_NODE_IP6_LOOKUP_NEXT_REWRITE);
> +
> + if (ret < 0)
> + rte_exit(EXIT_FAILURE,
> + "Unable to add ip6 route %s to graph\n",
> + route_str);
> +
> + memcpy(rewrite_data, val_eth + dst_port, rewrite_len);
> +
> + /* Add next hop rewrite data for id 'i' */
> + ret = rte_node_ip6_rewrite_add(i, rewrite_data,
> + rewrite_len, dst_port);
> + if (ret < 0)
> + rte_exit(EXIT_FAILURE,
> + "Unable to add next hop %u for "
> + "route %s\n", i, route_str);
> +
> + RTE_LOG(INFO, L3FWD_GRAPH, "Added route %s, next_hop %u\n",
> + route_str, i);
> + }
> + /* >8 End of adding routes and rewrite data to graph infa. */
>
> /* Launch per-lcore init on every worker lcore */
> rte_eal_mp_remote_launch(graph_main_loop, NULL, SKIP_MAIN);
> --
> 2.25.1
>
^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [EXT] Re: [PATCH v3 1/3] lib: add IPv6 lookup node
2023-06-01 2:24 ` [PATCH v3 1/3] lib: add IPv6 lookup node Nithin Dabilpuram
@ 2023-06-12 17:58 ` Amit Prakash Shukla
2023-06-12 20:14 ` Thomas Monjalon
0 siblings, 1 reply; 18+ messages in thread
From: Amit Prakash Shukla @ 2023-06-12 17:58 UTC (permalink / raw)
To: Thomas Monjalon
Cc: Jerin Jacob Kollanukkaran, Kiran Kumar Kokkilagadda,
Nithin Kumar Dabilpuram, Pavan Nikhilesh Bhagavatula, dev,
Sunil Kumar Kori
Hi Thomas,
This series is acked by node maintainer. Please consider merging.
CI is failing in the doc build, but I believe it is picking up wrong l3_forward_graph.rst file, as with this latest patch the string "Add route to ip4 graph infra." has been removed.
Thanks,
Amit Shukla
> -----Original Message-----
> From: Nithin Dabilpuram <nithind1988@gmail.com>
> Sent: Thursday, June 1, 2023 7:55 AM
> To: Amit Prakash Shukla <amitprakashs@marvell.com>
> Cc: Jerin Jacob Kollanukkaran <jerinj@marvell.com>; Kiran Kumar
> Kokkilagadda <kirankumark@marvell.com>; Nithin Kumar Dabilpuram
> <ndabilpuram@marvell.com>; Pavan Nikhilesh Bhagavatula
> <pbhagavatula@marvell.com>; dev@dpdk.org; Sunil Kumar Kori
> <skori@marvell.com>
> Subject: [EXT] Re: [PATCH v3 1/3] lib: add IPv6 lookup node
>
> External Email
>
> ----------------------------------------------------------------------
> Acked-by: Nithin Dabilpuram<ndabilpuram@marvell.com>
>
> On Wed, May 31, 2023 at 5:08 PM Amit Prakash Shukla
> <amitprakashs@marvell.com> wrote:
> >
> > From: Sunil Kumar Kori <skori@marvell.com>
> >
> > Similar to IPv4 lookup node, patch adds IPv6 lookup node.
> >
> > Signed-off-by: Sunil Kumar Kori <skori@marvell.com>
> > Signed-off-by: Amit Prakash Shukla <amitprakashs@marvell.com>
> > ---
> > v2:
> > - Performance related changes
> >
> > v3:
> > - Removing redundant dynamic variable
> >
> > doc/guides/prog_guide/graph_lib.rst | 13 +
> > lib/node/ip6_lookup.c | 372 ++++++++++++++++++++++++++++
> > lib/node/meson.build | 3 +-
> > lib/node/node_private.h | 2 +-
> > lib/node/pkt_cls.c | 14 ++
> > lib/node/pkt_cls_priv.h | 1 +
> > lib/node/rte_node_ip6_api.h | 80 ++++++
> > lib/node/version.map | 2 +
> > 8 files changed, 485 insertions(+), 2 deletions(-) create mode
> > 100644 lib/node/ip6_lookup.c create mode 100644
> > lib/node/rte_node_ip6_api.h
> >
> > diff --git a/doc/guides/prog_guide/graph_lib.rst
> > b/doc/guides/prog_guide/graph_lib.rst
> > index 1cfdc86433..1f70d63628 100644
> > --- a/doc/guides/prog_guide/graph_lib.rst
> > +++ b/doc/guides/prog_guide/graph_lib.rst
> > @@ -388,6 +388,19 @@ 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.
> >
> > +ip6_lookup
> > +~~~~~~~~~~
> > +This node is an intermediate node that does LPM lookup for the
> > +received
> > +ipv6 packets and the result determines each packets next node.
> > +
> > +On successful LPM lookup, the result contains the ``next_node`` id
> > +and ``next-hop`` id with which the packet needs to be further processed.
> > +
> > +On LPM lookup failure, objects are redirected to pkt_drop node.
> > +``rte_node_ip6_route_add()`` is control path API to add ipv6 routes.
> > +To achieve home run, node use ``rte_node_stream_move()`` as
> mentioned
> > +in above sections.
> > +
> > null
> > ~~~~
> > This node ignores the set of objects passed to it and reports that
> > all are diff --git a/lib/node/ip6_lookup.c b/lib/node/ip6_lookup.c new
> > file mode 100644 index 0000000000..e4bbc7ed67
> > --- /dev/null
> > +++ b/lib/node/ip6_lookup.c
> > @@ -0,0 +1,372 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(C) 2023 Marvell.
> > + */
> > +
> > +#include <arpa/inet.h>
> > +#include <sys/socket.h>
> > +
> > +#include <rte_ethdev.h>
> > +#include <rte_ether.h>
> > +#include <rte_graph.h>
> > +#include <rte_graph_worker.h>
> > +#include <rte_ip.h>
> > +#include <rte_lpm6.h>
> > +
> > +#include "rte_node_ip6_api.h"
> > +
> > +#include "node_private.h"
> > +
> > +#define IPV6_L3FWD_LPM_MAX_RULES 1024 #define
> > +IPV6_L3FWD_LPM_NUMBER_TBL8S (1 << 8)
> > +
> > +/* IP6 Lookup global data struct */
> > +struct ip6_lookup_node_main {
> > + struct rte_lpm6 *lpm_tbl[RTE_MAX_NUMA_NODES]; };
> > +
> > +struct ip6_lookup_node_ctx {
> > + /* Socket's LPM table */
> > + struct rte_lpm6 *lpm6;
> > + /* Dynamic offset to mbuf priv1 */
> > + int mbuf_priv1_off;
> > +};
> > +
> > +static struct ip6_lookup_node_main ip6_lookup_nm;
> > +
> > +#define IP6_LOOKUP_NODE_LPM(ctx) \
> > + (((struct ip6_lookup_node_ctx *)ctx)->lpm6)
> > +
> > +#define IP6_LOOKUP_NODE_PRIV1_OFF(ctx) \
> > + (((struct ip6_lookup_node_ctx *)ctx)->mbuf_priv1_off)
> > +
> > +static uint16_t
> > +ip6_lookup_node_process_scalar(struct rte_graph *graph, struct
> rte_node *node,
> > + void **objs, uint16_t nb_objs) {
> > + struct rte_mbuf *mbuf0, *mbuf1, *mbuf2, *mbuf3, **pkts;
> > + struct rte_lpm6 *lpm6 = IP6_LOOKUP_NODE_LPM(node->ctx);
> > + const int dyn = IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx);
> > + struct rte_ipv6_hdr *ipv6_hdr;
> > + void **to_next, **from;
> > + uint16_t last_spec = 0;
> > + rte_edge_t next_index;
> > + uint16_t n_left_from;
> > + uint16_t held = 0;
> > + uint32_t drop_nh;
> > + int i, rc;
> > +
> > + /* Speculative next */
> > + next_index = RTE_NODE_IP6_LOOKUP_NEXT_REWRITE;
> > + /* Drop node */
> > + drop_nh = ((uint32_t)RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP) <<
> 16;
> > +
> > + pkts = (struct rte_mbuf **)objs;
> > + from = objs;
> > + n_left_from = nb_objs;
> > +
> > + for (i = OBJS_PER_CLINE; i < RTE_GRAPH_BURST_SIZE; i +=
> OBJS_PER_CLINE)
> > + rte_prefetch0(&objs[i]);
> > +
> > + for (i = 0; i < 4 && i < n_left_from; i++)
> > + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[i], void *,
> > + sizeof(struct
> > + rte_ether_hdr)));
> > +
> > + /* Get stream for the speculated next node */
> > + to_next = rte_node_next_stream_get(graph, node, next_index,
> nb_objs);
> > + while (n_left_from >= 4) {
> > + uint8_t ip_batch[4][16];
> > + int32_t next_hop[4];
> > + uint16_t next[4];
> > +
> > +#if RTE_GRAPH_BURST_SIZE > 64
> > + /* Prefetch next-next mbufs */
> > + if (likely(n_left_from > 11)) {
> > + rte_prefetch0(pkts[8]);
> > + rte_prefetch0(pkts[9]);
> > + rte_prefetch0(pkts[10]);
> > + rte_prefetch0(pkts[11]);
> > + }
> > +#endif
> > + /* Prefetch next mbuf data */
> > + if (likely(n_left_from > 7)) {
> > + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[4], void *,
> > + sizeof(struct rte_ether_hdr)));
> > + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[5], void *,
> > + sizeof(struct rte_ether_hdr)));
> > + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[6], void *,
> > + sizeof(struct rte_ether_hdr)));
> > + rte_prefetch0(rte_pktmbuf_mtod_offset(pkts[7], void *,
> > + sizeof(struct rte_ether_hdr)));
> > + }
> > +
> > + mbuf0 = pkts[0];
> > + mbuf1 = pkts[1];
> > + mbuf2 = pkts[2];
> > + mbuf3 = pkts[3];
> > +
> > + pkts += 4;
> > + n_left_from -= 4;
> > +
> > + /* Extract DIP of mbuf0 */
> > + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr
> *,
> > + sizeof(struct rte_ether_hdr));
> > + /* Extract hop_limits as ipv6 hdr is in cache */
> > + node_mbuf_priv1(mbuf0, dyn)->ttl = ipv6_hdr->hop_limits;
> > + rte_memcpy(ip_batch[0], ipv6_hdr->dst_addr, 16);
> > +
> > + /* Extract DIP of mbuf1 */
> > + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf1, struct rte_ipv6_hdr
> *,
> > + sizeof(struct rte_ether_hdr));
> > + /* Extract hop_limits as ipv6 hdr is in cache */
> > + node_mbuf_priv1(mbuf1, dyn)->ttl = ipv6_hdr->hop_limits;
> > + rte_memcpy(ip_batch[1], ipv6_hdr->dst_addr, 16);
> > +
> > + /* Extract DIP of mbuf2 */
> > + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf2, struct rte_ipv6_hdr
> *,
> > + sizeof(struct rte_ether_hdr));
> > + /* Extract hop_limits as ipv6 hdr is in cache */
> > + node_mbuf_priv1(mbuf2, dyn)->ttl = ipv6_hdr->hop_limits;
> > + rte_memcpy(ip_batch[2], ipv6_hdr->dst_addr, 16);
> > +
> > + /* Extract DIP of mbuf3 */
> > + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf3, struct rte_ipv6_hdr
> *,
> > + sizeof(struct rte_ether_hdr));
> > + /* Extract hop_limits as ipv6 hdr is in cache */
> > + node_mbuf_priv1(mbuf3, dyn)->ttl = ipv6_hdr->hop_limits;
> > + rte_memcpy(ip_batch[3], ipv6_hdr->dst_addr, 16);
> > +
> > + rc = rte_lpm6_lookup_bulk_func(lpm6, ip_batch,
> > + next_hop, 4);
> > +
> > + next_hop[0] = (next_hop[0] < 0) ? (int32_t)drop_nh : next_hop[0];
> > + node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop[0];
> > + next[0] = (uint16_t)(next_hop[0] >> 16);
> > +
> > + next_hop[1] = (next_hop[1] < 0) ? (int32_t)drop_nh : next_hop[1];
> > + node_mbuf_priv1(mbuf1, dyn)->nh = (uint16_t)next_hop[1];
> > + next[1] = (uint16_t)(next_hop[1] >> 16);
> > +
> > + next_hop[2] = (next_hop[2] < 0) ? (int32_t)drop_nh : next_hop[2];
> > + node_mbuf_priv1(mbuf2, dyn)->nh = (uint16_t)next_hop[2];
> > + next[2] = (uint16_t)(next_hop[2] >> 16);
> > +
> > + next_hop[3] = (next_hop[3] < 0) ? (int32_t)drop_nh : next_hop[3];
> > + node_mbuf_priv1(mbuf3, dyn)->nh = (uint16_t)next_hop[3];
> > + next[3] = (uint16_t)(next_hop[3] >> 16);
> > +
> > + rte_edge_t fix_spec = ((next_index == next[0]) &&
> > + (next_index == next[1]) &&
> > + (next_index == next[2]) &&
> > + (next_index == next[3]));
> > +
> > + if (unlikely(fix_spec == 0)) {
> > + /* Copy things successfully speculated till now */
> > + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> > + from += last_spec;
> > + to_next += last_spec;
> > + held += last_spec;
> > + last_spec = 0;
> > +
> > + /* Next0 */
> > + if (next_index == next[0]) {
> > + to_next[0] = from[0];
> > + to_next++;
> > + held++;
> > + } else {
> > + rte_node_enqueue_x1(graph, node, next[0], from[0]);
> > + }
> > +
> > + /* Next1 */
> > + if (next_index == next[1]) {
> > + to_next[0] = from[1];
> > + to_next++;
> > + held++;
> > + } else {
> > + rte_node_enqueue_x1(graph, node, next[1], from[1]);
> > + }
> > +
> > + /* Next2 */
> > + if (next_index == next[2]) {
> > + to_next[0] = from[2];
> > + to_next++;
> > + held++;
> > + } else {
> > + rte_node_enqueue_x1(graph, node, next[2], from[2]);
> > + }
> > +
> > + /* Next3 */
> > + if (next_index == next[3]) {
> > + to_next[0] = from[3];
> > + to_next++;
> > + held++;
> > + } else {
> > + rte_node_enqueue_x1(graph, node, next[3], from[3]);
> > + }
> > +
> > + from += 4;
> > + } else {
> > + last_spec += 4;
> > + }
> > + }
> > +
> > + while (n_left_from > 0) {
> > + uint32_t next_hop;
> > + uint16_t next0;
> > +
> > + mbuf0 = pkts[0];
> > +
> > + pkts += 1;
> > + n_left_from -= 1;
> > +
> > + /* Extract DIP of mbuf0 */
> > + ipv6_hdr = rte_pktmbuf_mtod_offset(mbuf0, struct rte_ipv6_hdr
> *,
> > + sizeof(struct rte_ether_hdr));
> > + /* Extract ttl as ipv6 hdr is in cache */
> > + node_mbuf_priv1(mbuf0, dyn)->ttl =
> > + ipv6_hdr->hop_limits;
> > +
> > + rc = rte_lpm6_lookup(lpm6, ipv6_hdr->dst_addr, &next_hop);
> > + next_hop = (rc == 0) ? next_hop : drop_nh;
> > +
> > + node_mbuf_priv1(mbuf0, dyn)->nh = (uint16_t)next_hop;
> > + next_hop = next_hop >> 16;
> > + next0 = (uint16_t)next_hop;
> > +
> > + if (unlikely(next_index ^ next0)) {
> > + /* Copy things successfully speculated till now */
> > + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> > + from += last_spec;
> > + to_next += last_spec;
> > + held += last_spec;
> > + last_spec = 0;
> > +
> > + rte_node_enqueue_x1(graph, node, next0, from[0]);
> > + from += 1;
> > + } else {
> > + last_spec += 1;
> > + }
> > + }
> > +
> > + /* !!! Home run !!! */
> > + if (likely(last_spec == nb_objs)) {
> > + rte_node_next_stream_move(graph, node, next_index);
> > + return nb_objs;
> > + }
> > + held += last_spec;
> > + rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
> > + rte_node_next_stream_put(graph, node, next_index, held);
> > +
> > + return nb_objs;
> > +}
> > +
> > +int
> > +rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t
> next_hop,
> > + enum rte_node_ip6_lookup_next next_node) {
> > + char abuf[INET6_ADDRSTRLEN];
> > + struct in6_addr in6;
> > + uint8_t socket;
> > + uint32_t val;
> > + int ret;
> > +
> > + memcpy(in6.s6_addr, ip, RTE_LPM6_IPV6_ADDR_SIZE);
> > + inet_ntop(AF_INET6, &in6, abuf, sizeof(abuf));
> > + /* Embedded next node id into 24 bit next hop */
> > + val = ((next_node << 16) | next_hop) & ((1ull << 24) - 1);
> > + node_dbg("ip6_lookup", "LPM: Adding route %s / %d nh (0x%x)",
> abuf,
> > + depth, val);
> > +
> > + for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
> > + if (!ip6_lookup_nm.lpm_tbl[socket])
> > + continue;
> > +
> > + ret = rte_lpm6_add(ip6_lookup_nm.lpm_tbl[socket], ip, depth,
> > + val);
> > + if (ret < 0) {
> > + node_err("ip6_lookup",
> > + "Unable to add entry %s / %d nh (%x) to LPM "
> > + "table on sock %d, rc=%d\n",
> > + abuf, depth, val, socket, ret);
> > + return ret;
> > + }
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static int
> > +setup_lpm6(struct ip6_lookup_node_main *nm, int socket) {
> > + struct rte_lpm6_config config_ipv6;
> > + char s[RTE_LPM6_NAMESIZE];
> > +
> > + /* One LPM table per socket */
> > + if (nm->lpm_tbl[socket])
> > + return 0;
> > +
> > + /* create the LPM table */
> > + config_ipv6.max_rules = IPV6_L3FWD_LPM_MAX_RULES;
> > + config_ipv6.number_tbl8s = IPV6_L3FWD_LPM_NUMBER_TBL8S;
> > + config_ipv6.flags = 0;
> > + snprintf(s, sizeof(s), "IPV6_L3FWD_LPM_%d", socket);
> > + nm->lpm_tbl[socket] = rte_lpm6_create(s, socket, &config_ipv6);
> > + if (nm->lpm_tbl[socket] == NULL)
> > + return -rte_errno;
> > +
> > + return 0;
> > +}
> > +
> > +static int
> > +ip6_lookup_node_init(const struct rte_graph *graph, struct rte_node
> > +*node) {
> > + uint16_t socket, lcore_id;
> > + static uint8_t init_once;
> > + int rc;
> > +
> > + RTE_SET_USED(graph);
> > + RTE_BUILD_BUG_ON(sizeof(struct ip6_lookup_node_ctx) >
> > + RTE_NODE_CTX_SZ);
> > +
> > + if (!init_once) {
> > + node_mbuf_priv1_dynfield_offset =
> > + rte_mbuf_dynfield_register(
> > + &node_mbuf_priv1_dynfield_desc);
> > + if (node_mbuf_priv1_dynfield_offset < 0)
> > + return -rte_errno;
> > +
> > + /* Setup LPM tables for all sockets */
> > + RTE_LCORE_FOREACH(lcore_id)
> > + {
> > + socket = rte_lcore_to_socket_id(lcore_id);
> > + rc = setup_lpm6(&ip6_lookup_nm, socket);
> > + if (rc) {
> > + node_err("ip6_lookup",
> > + "Failed to setup lpm6 tbl for "
> > + "sock %u, rc=%d", socket, rc);
> > + return rc;
> > + }
> > + }
> > + init_once = 1;
> > + }
> > +
> > + /* Update socket's LPM and mbuf dyn priv1 offset in node ctx */
> > + IP6_LOOKUP_NODE_LPM(node->ctx) = ip6_lookup_nm.lpm_tbl[graph-
> >socket];
> > + IP6_LOOKUP_NODE_PRIV1_OFF(node->ctx) =
> > +
> > + node_mbuf_priv1_dynfield_offset;
> > +
> > + node_dbg("ip6_lookup", "Initialized ip6_lookup node");
> > +
> > + return 0;
> > +}
> > +
> > +static struct rte_node_register ip6_lookup_node = {
> > + .process = ip6_lookup_node_process_scalar,
> > + .name = "ip6_lookup",
> > +
> > + .init = ip6_lookup_node_init,
> > +
> > + .nb_edges = RTE_NODE_IP6_LOOKUP_NEXT_MAX,
> > + .next_nodes = {
> > + [RTE_NODE_IP6_LOOKUP_NEXT_REWRITE] = "ip6_rewrite",
> > + [RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP] = "pkt_drop",
> > + },
> > +};
> > +
> > +RTE_NODE_REGISTER(ip6_lookup_node);
> > diff --git a/lib/node/meson.build b/lib/node/meson.build index
> > dbdf673c86..cd30847a0b 100644
> > --- a/lib/node/meson.build
> > +++ b/lib/node/meson.build
> > @@ -12,13 +12,14 @@ sources = files(
> > 'ethdev_rx.c',
> > 'ethdev_tx.c',
> > 'ip4_lookup.c',
> > + 'ip6_lookup.c',
> > 'ip4_rewrite.c',
> > 'log.c',
> > 'null.c',
> > 'pkt_cls.c',
> > 'pkt_drop.c',
> > )
> > -headers = files('rte_node_ip4_api.h', 'rte_node_eth_api.h')
> > +headers = files('rte_node_ip4_api.h', 'rte_node_ip6_api.h',
> > +'rte_node_eth_api.h')
> > # Strict-aliasing rules are violated by uint8_t[] to context size casts.
> > cflags += '-fno-strict-aliasing'
> > deps += ['graph', 'mbuf', 'lpm', 'ethdev', 'mempool', 'cryptodev']
> > diff --git a/lib/node/node_private.h b/lib/node/node_private.h index
> > 8c73d5dc10..26135aaa5b 100644
> > --- a/lib/node/node_private.h
> > +++ b/lib/node/node_private.h
> > @@ -26,7 +26,7 @@ extern int rte_node_logtype;
> > */
> > struct node_mbuf_priv1 {
> > union {
> > - /* IP4 rewrite */
> > + /* IP4/IP6 rewrite */
> > struct {
> > uint16_t nh;
> > uint16_t ttl;
> > diff --git a/lib/node/pkt_cls.c b/lib/node/pkt_cls.c index
> > 3e75f2cf78..a8302b8d28 100644
> > --- a/lib/node/pkt_cls.c
> > +++ b/lib/node/pkt_cls.c
> > @@ -24,6 +24,19 @@ static const uint8_t p_nxt[256] __rte_cache_aligned
> > = {
> >
> > [RTE_PTYPE_L3_IPV4_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
> > PKT_CLS_NEXT_IP4_LOOKUP,
> > +
> > + [RTE_PTYPE_L3_IPV6] = PKT_CLS_NEXT_IP6_LOOKUP,
> > +
> > + [RTE_PTYPE_L3_IPV6_EXT] = PKT_CLS_NEXT_IP6_LOOKUP,
> > +
> > + [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN] = PKT_CLS_NEXT_IP6_LOOKUP,
> > +
> > + [RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L2_ETHER] =
> > + PKT_CLS_NEXT_IP6_LOOKUP,
> > +
> > + [RTE_PTYPE_L3_IPV6_EXT | RTE_PTYPE_L2_ETHER] =
> > + PKT_CLS_NEXT_IP6_LOOKUP,
> > +
> > + [RTE_PTYPE_L3_IPV6_EXT_UNKNOWN | RTE_PTYPE_L2_ETHER] =
> > + PKT_CLS_NEXT_IP6_LOOKUP,
> > };
> >
> > static uint16_t
> > @@ -216,6 +229,7 @@ struct rte_node_register pkt_cls_node = {
> > /* Pkt drop node starts at '0' */
> > [PKT_CLS_NEXT_PKT_DROP] = "pkt_drop",
> > [PKT_CLS_NEXT_IP4_LOOKUP] = "ip4_lookup",
> > + [PKT_CLS_NEXT_IP6_LOOKUP] = "ip6_lookup",
> > },
> > };
> > RTE_NODE_REGISTER(pkt_cls_node);
> > diff --git a/lib/node/pkt_cls_priv.h b/lib/node/pkt_cls_priv.h index
> > 6f5374f0be..16135807a1 100644
> > --- a/lib/node/pkt_cls_priv.h
> > +++ b/lib/node/pkt_cls_priv.h
> > @@ -13,6 +13,7 @@ struct pkt_cls_node_ctx { enum pkt_cls_next_nodes {
> > PKT_CLS_NEXT_PKT_DROP,
> > PKT_CLS_NEXT_IP4_LOOKUP,
> > + PKT_CLS_NEXT_IP6_LOOKUP,
> > PKT_CLS_NEXT_MAX,
> > };
> >
> > diff --git a/lib/node/rte_node_ip6_api.h b/lib/node/rte_node_ip6_api.h
> > new file mode 100644 index 0000000000..1696ed154d
> > --- /dev/null
> > +++ b/lib/node/rte_node_ip6_api.h
> > @@ -0,0 +1,80 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(C) 2023 Marvell.
> > + */
> > +
> > +#ifndef __INCLUDE_RTE_NODE_IP6_API_H__ #define
> > +__INCLUDE_RTE_NODE_IP6_API_H__
> > +
> > +/**
> > + * @file rte_node_ip6_api.h
> > + *
> > + * @warning
> > + * @b EXPERIMENTAL:
> > + * All functions in this file may be changed or removed without prior
> notice.
> > + *
> > + * This API allows to do control path functions of ip6_* nodes
> > + * like ip6_lookup, ip6_rewrite.
> > + *
> > + */
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +#include <rte_common.h>
> > +#include <rte_compat.h>
> > +
> > +/**
> > + * IP6 lookup next nodes.
> > + */
> > +enum rte_node_ip6_lookup_next {
> > + RTE_NODE_IP6_LOOKUP_NEXT_REWRITE,
> > + /**< Rewrite node. */
> > + RTE_NODE_IP6_LOOKUP_NEXT_PKT_DROP,
> > + /**< Packet drop node. */
> > + RTE_NODE_IP6_LOOKUP_NEXT_MAX,
> > + /**< Number of next nodes of lookup node. */ };
> > +
> > +/**
> > + * Add ipv6 route to lookup table.
> > + *
> > + * @param ip
> > + * IPv6 address of route to be added.
> > + * @param depth
> > + * Depth of the rule to be added.
> > + * @param next_hop
> > + * Next hop id of the rule result to be added.
> > + * @param next_node
> > + * Next node to redirect traffic to.
> > + *
> > + * @return
> > + * 0 on success, negative otherwise.
> > + */
> > +__rte_experimental
> > +int rte_node_ip6_route_add(const uint8_t *ip, uint8_t depth, uint16_t
> next_hop,
> > + enum rte_node_ip6_lookup_next next_node);
> > +
> > +/**
> > + * Add a next hop's rewrite data.
> > + *
> > + * @param next_hop
> > + * Next hop id to add rewrite data to.
> > + * @param rewrite_data
> > + * Rewrite data.
> > + * @param rewrite_len
> > + * Length of rewrite data.
> > + * @param dst_port
> > + * Destination port to redirect traffic to.
> > + *
> > + * @return
> > + * 0 on success, negative otherwise.
> > + */
> > +__rte_experimental
> > +int rte_node_ip6_rewrite_add(uint16_t next_hop, uint8_t *rewrite_data,
> > + uint8_t rewrite_len, uint16_t dst_port);
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif /* __INCLUDE_RTE_NODE_IP6_API_H__ */
> > diff --git a/lib/node/version.map b/lib/node/version.map index
> > a799b0d389..40df308bfe 100644
> > --- a/lib/node/version.map
> > +++ b/lib/node/version.map
> > @@ -4,6 +4,8 @@ EXPERIMENTAL {
> > rte_node_eth_config;
> > rte_node_ip4_route_add;
> > rte_node_ip4_rewrite_add;
> > + rte_node_ip6_rewrite_add;
> > + rte_node_ip6_route_add;
> > rte_node_logtype;
> > local: *;
> > };
> > --
> > 2.25.1
> >
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [EXT] Re: [PATCH v3 1/3] lib: add IPv6 lookup node
2023-06-12 17:58 ` [EXT] " Amit Prakash Shukla
@ 2023-06-12 20:14 ` Thomas Monjalon
0 siblings, 0 replies; 18+ messages in thread
From: Thomas Monjalon @ 2023-06-12 20:14 UTC (permalink / raw)
To: Sunil Kumar Kori, Amit Prakash Shukla
Cc: dev, Jerin Jacob Kollanukkaran, Kiran Kumar Kokkilagadda,
Nithin Kumar Dabilpuram, Pavan Nikhilesh Bhagavatula, dev
12/06/2023 19:58, Amit Prakash Shukla:
> Hi Thomas,
>
> This series is acked by node maintainer. Please consider merging.
>
> CI is failing in the doc build, but I believe it is picking up wrong l3_forward_graph.rst file, as with this latest patch the string "Add route to ip4 graph infra." has been removed.
When it happens, you should ping earlier and try to send a new version.
Applied with minor changes in doc and comments, thanks.
^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2023-06-12 20:15 UTC | newest]
Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-05-16 9:11 [PATCH 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
2023-05-16 9:11 ` [PATCH 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
2023-05-16 9:11 ` [PATCH 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 1/3] lib: add IPv6 lookup node Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
2023-05-18 15:56 ` [PATCH v2 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
2023-05-22 5:49 ` Sunil Kumar Kori
2023-05-29 6:27 ` Sunil Kumar Kori
2023-05-30 8:51 ` [PATCH v2 1/3] lib: add IPv6 lookup node Nithin Dabilpuram
2023-05-31 11:37 ` [PATCH v3 " Amit Prakash Shukla
2023-05-31 11:37 ` [PATCH v3 2/3] lib: add IPv6 rewrite node Amit Prakash Shukla
2023-06-01 2:26 ` Nithin Dabilpuram
2023-06-05 16:29 ` Nithin Dabilpuram
2023-05-31 11:37 ` [PATCH v3 3/3] examples/l3fwd-graph: add IPv6 lookup and rewrite support Amit Prakash Shukla
2023-06-05 16:32 ` Nithin Dabilpuram
2023-06-01 2:24 ` [PATCH v3 1/3] lib: add IPv6 lookup node Nithin Dabilpuram
2023-06-12 17:58 ` [EXT] " Amit Prakash Shukla
2023-06-12 20:14 ` Thomas Monjalon
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).