1*51a3c7a1SRakesh Kudurumalla /* SPDX-License-Identifier: BSD-3-Clause
2*51a3c7a1SRakesh Kudurumalla * Copyright(C) 2023 Marvell International Ltd.
3*51a3c7a1SRakesh Kudurumalla */
4*51a3c7a1SRakesh Kudurumalla
5*51a3c7a1SRakesh Kudurumalla #include <arpa/inet.h>
6*51a3c7a1SRakesh Kudurumalla #include <sys/socket.h>
7*51a3c7a1SRakesh Kudurumalla
8*51a3c7a1SRakesh Kudurumalla #include <rte_ethdev.h>
9*51a3c7a1SRakesh Kudurumalla #include <rte_ether.h>
10*51a3c7a1SRakesh Kudurumalla #include <rte_graph.h>
11*51a3c7a1SRakesh Kudurumalla #include <rte_graph_worker.h>
12*51a3c7a1SRakesh Kudurumalla #include <rte_ip.h>
13*51a3c7a1SRakesh Kudurumalla #include <rte_lpm.h>
14*51a3c7a1SRakesh Kudurumalla #include <rte_hash.h>
15*51a3c7a1SRakesh Kudurumalla #include <rte_fbk_hash.h>
16*51a3c7a1SRakesh Kudurumalla #include <rte_jhash.h>
17*51a3c7a1SRakesh Kudurumalla #include <rte_hash_crc.h>
18*51a3c7a1SRakesh Kudurumalla
19*51a3c7a1SRakesh Kudurumalla #include "rte_node_udp4_input_api.h"
20*51a3c7a1SRakesh Kudurumalla
21*51a3c7a1SRakesh Kudurumalla #include "node_private.h"
22*51a3c7a1SRakesh Kudurumalla
23*51a3c7a1SRakesh Kudurumalla #define UDP4_INPUT_HASH_TBL_SIZE 1024
24*51a3c7a1SRakesh Kudurumalla
25*51a3c7a1SRakesh Kudurumalla #define UDP4_INPUT_NODE_HASH(ctx) \
26*51a3c7a1SRakesh Kudurumalla (((struct udp4_input_node_ctx *)ctx)->hash)
27*51a3c7a1SRakesh Kudurumalla
28*51a3c7a1SRakesh Kudurumalla #define UDP4_INPUT_NODE_NEXT_INDEX(ctx) \
29*51a3c7a1SRakesh Kudurumalla (((struct udp4_input_node_ctx *)ctx)->next_index)
30*51a3c7a1SRakesh Kudurumalla
31*51a3c7a1SRakesh Kudurumalla
32*51a3c7a1SRakesh Kudurumalla /* UDP4 input global data struct */
33*51a3c7a1SRakesh Kudurumalla struct udp4_input_node_main {
34*51a3c7a1SRakesh Kudurumalla struct rte_hash *hash_tbl[RTE_MAX_NUMA_NODES];
35*51a3c7a1SRakesh Kudurumalla };
36*51a3c7a1SRakesh Kudurumalla
37*51a3c7a1SRakesh Kudurumalla static struct udp4_input_node_main udp4_input_nm;
38*51a3c7a1SRakesh Kudurumalla
39*51a3c7a1SRakesh Kudurumalla struct udp4_input_node_ctx {
40*51a3c7a1SRakesh Kudurumalla /* Socket's Hash table */
41*51a3c7a1SRakesh Kudurumalla struct rte_hash *hash;
42*51a3c7a1SRakesh Kudurumalla /* Cached next index */
43*51a3c7a1SRakesh Kudurumalla uint16_t next_index;
44*51a3c7a1SRakesh Kudurumalla };
45*51a3c7a1SRakesh Kudurumalla
46*51a3c7a1SRakesh Kudurumalla struct flow_key {
47*51a3c7a1SRakesh Kudurumalla uint32_t prt_dst;
48*51a3c7a1SRakesh Kudurumalla };
49*51a3c7a1SRakesh Kudurumalla
50*51a3c7a1SRakesh Kudurumalla static struct rte_hash_parameters udp4_params = {
51*51a3c7a1SRakesh Kudurumalla .entries = UDP4_INPUT_HASH_TBL_SIZE,
52*51a3c7a1SRakesh Kudurumalla .key_len = sizeof(uint32_t),
53*51a3c7a1SRakesh Kudurumalla .hash_func = rte_jhash,
54*51a3c7a1SRakesh Kudurumalla .hash_func_init_val = 0,
55*51a3c7a1SRakesh Kudurumalla .socket_id = 0,
56*51a3c7a1SRakesh Kudurumalla };
57*51a3c7a1SRakesh Kudurumalla
58*51a3c7a1SRakesh Kudurumalla int
rte_node_udp4_dst_port_add(uint32_t dst_port,rte_edge_t next_node)59*51a3c7a1SRakesh Kudurumalla rte_node_udp4_dst_port_add(uint32_t dst_port, rte_edge_t next_node)
60*51a3c7a1SRakesh Kudurumalla {
61*51a3c7a1SRakesh Kudurumalla uint8_t socket;
62*51a3c7a1SRakesh Kudurumalla int rc;
63*51a3c7a1SRakesh Kudurumalla
64*51a3c7a1SRakesh Kudurumalla for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) {
65*51a3c7a1SRakesh Kudurumalla if (!udp4_input_nm.hash_tbl[socket])
66*51a3c7a1SRakesh Kudurumalla continue;
67*51a3c7a1SRakesh Kudurumalla
68*51a3c7a1SRakesh Kudurumalla rc = rte_hash_add_key_data(udp4_input_nm.hash_tbl[socket],
69*51a3c7a1SRakesh Kudurumalla &dst_port, (void *)(uintptr_t)next_node);
70*51a3c7a1SRakesh Kudurumalla if (rc < 0) {
71*51a3c7a1SRakesh Kudurumalla node_err("udp4_lookup", "Failed to add key for sock %u, rc=%d",
72*51a3c7a1SRakesh Kudurumalla socket, rc);
73*51a3c7a1SRakesh Kudurumalla return rc;
74*51a3c7a1SRakesh Kudurumalla }
75*51a3c7a1SRakesh Kudurumalla }
76*51a3c7a1SRakesh Kudurumalla return 0;
77*51a3c7a1SRakesh Kudurumalla }
78*51a3c7a1SRakesh Kudurumalla
79*51a3c7a1SRakesh Kudurumalla int
rte_node_udp4_usr_node_add(const char * usr_node)80*51a3c7a1SRakesh Kudurumalla rte_node_udp4_usr_node_add(const char *usr_node)
81*51a3c7a1SRakesh Kudurumalla {
82*51a3c7a1SRakesh Kudurumalla const char *next_nodes = usr_node;
83*51a3c7a1SRakesh Kudurumalla rte_node_t udp4_input_node_id, count;
84*51a3c7a1SRakesh Kudurumalla
85*51a3c7a1SRakesh Kudurumalla udp4_input_node_id = rte_node_from_name("udp4_input");
86*51a3c7a1SRakesh Kudurumalla count = rte_node_edge_update(udp4_input_node_id, RTE_EDGE_ID_INVALID,
87*51a3c7a1SRakesh Kudurumalla &next_nodes, 1);
88*51a3c7a1SRakesh Kudurumalla if (count == 0) {
89*51a3c7a1SRakesh Kudurumalla node_dbg("udp4_input", "Adding usr node as edge to udp4_input failed");
90*51a3c7a1SRakesh Kudurumalla return count;
91*51a3c7a1SRakesh Kudurumalla }
92*51a3c7a1SRakesh Kudurumalla count = rte_node_edge_count(udp4_input_node_id) - 1;
93*51a3c7a1SRakesh Kudurumalla return count;
94*51a3c7a1SRakesh Kudurumalla }
95*51a3c7a1SRakesh Kudurumalla
96*51a3c7a1SRakesh Kudurumalla static int
setup_udp4_dstprt_hash(struct udp4_input_node_main * nm,int socket)97*51a3c7a1SRakesh Kudurumalla setup_udp4_dstprt_hash(struct udp4_input_node_main *nm, int socket)
98*51a3c7a1SRakesh Kudurumalla {
99*51a3c7a1SRakesh Kudurumalla struct rte_hash_parameters *hash_udp4 = &udp4_params;
100*51a3c7a1SRakesh Kudurumalla char s[RTE_HASH_NAMESIZE];
101*51a3c7a1SRakesh Kudurumalla
102*51a3c7a1SRakesh Kudurumalla /* One Hash table per socket */
103*51a3c7a1SRakesh Kudurumalla if (nm->hash_tbl[socket])
104*51a3c7a1SRakesh Kudurumalla return 0;
105*51a3c7a1SRakesh Kudurumalla
106*51a3c7a1SRakesh Kudurumalla /* create Hash table */
107*51a3c7a1SRakesh Kudurumalla snprintf(s, sizeof(s), "UDP4_INPUT_HASH_%d", socket);
108*51a3c7a1SRakesh Kudurumalla hash_udp4->name = s;
109*51a3c7a1SRakesh Kudurumalla hash_udp4->socket_id = socket;
110*51a3c7a1SRakesh Kudurumalla nm->hash_tbl[socket] = rte_hash_create(hash_udp4);
111*51a3c7a1SRakesh Kudurumalla if (nm->hash_tbl[socket] == NULL)
112*51a3c7a1SRakesh Kudurumalla return -rte_errno;
113*51a3c7a1SRakesh Kudurumalla
114*51a3c7a1SRakesh Kudurumalla return 0;
115*51a3c7a1SRakesh Kudurumalla }
116*51a3c7a1SRakesh Kudurumalla
117*51a3c7a1SRakesh Kudurumalla static int
udp4_input_node_init(const struct rte_graph * graph,struct rte_node * node)118*51a3c7a1SRakesh Kudurumalla udp4_input_node_init(const struct rte_graph *graph, struct rte_node *node)
119*51a3c7a1SRakesh Kudurumalla {
120*51a3c7a1SRakesh Kudurumalla uint16_t socket, lcore_id;
121*51a3c7a1SRakesh Kudurumalla static uint8_t init_once;
122*51a3c7a1SRakesh Kudurumalla int rc;
123*51a3c7a1SRakesh Kudurumalla
124*51a3c7a1SRakesh Kudurumalla RTE_SET_USED(graph);
125*51a3c7a1SRakesh Kudurumalla RTE_BUILD_BUG_ON(sizeof(struct udp4_input_node_ctx) > RTE_NODE_CTX_SZ);
126*51a3c7a1SRakesh Kudurumalla
127*51a3c7a1SRakesh Kudurumalla if (!init_once) {
128*51a3c7a1SRakesh Kudurumalla
129*51a3c7a1SRakesh Kudurumalla /* Setup HASH tables for all sockets */
130*51a3c7a1SRakesh Kudurumalla RTE_LCORE_FOREACH(lcore_id)
131*51a3c7a1SRakesh Kudurumalla {
132*51a3c7a1SRakesh Kudurumalla socket = rte_lcore_to_socket_id(lcore_id);
133*51a3c7a1SRakesh Kudurumalla rc = setup_udp4_dstprt_hash(&udp4_input_nm, socket);
134*51a3c7a1SRakesh Kudurumalla if (rc) {
135*51a3c7a1SRakesh Kudurumalla node_err("udp4_lookup",
136*51a3c7a1SRakesh Kudurumalla "Failed to setup hash tbl for sock %u, rc=%d",
137*51a3c7a1SRakesh Kudurumalla socket, rc);
138*51a3c7a1SRakesh Kudurumalla return rc;
139*51a3c7a1SRakesh Kudurumalla }
140*51a3c7a1SRakesh Kudurumalla }
141*51a3c7a1SRakesh Kudurumalla init_once = 1;
142*51a3c7a1SRakesh Kudurumalla }
143*51a3c7a1SRakesh Kudurumalla
144*51a3c7a1SRakesh Kudurumalla UDP4_INPUT_NODE_HASH(node->ctx) = udp4_input_nm.hash_tbl[graph->socket];
145*51a3c7a1SRakesh Kudurumalla
146*51a3c7a1SRakesh Kudurumalla node_dbg("udp4_input", "Initialized udp4_input node");
147*51a3c7a1SRakesh Kudurumalla return 0;
148*51a3c7a1SRakesh Kudurumalla }
149*51a3c7a1SRakesh Kudurumalla
150*51a3c7a1SRakesh Kudurumalla static uint16_t
udp4_input_node_process_scalar(struct rte_graph * graph,struct rte_node * node,void ** objs,uint16_t nb_objs)151*51a3c7a1SRakesh Kudurumalla udp4_input_node_process_scalar(struct rte_graph *graph, struct rte_node *node,
152*51a3c7a1SRakesh Kudurumalla void **objs, uint16_t nb_objs)
153*51a3c7a1SRakesh Kudurumalla {
154*51a3c7a1SRakesh Kudurumalla struct rte_hash *hash_tbl_handle = UDP4_INPUT_NODE_HASH(node->ctx);
155*51a3c7a1SRakesh Kudurumalla rte_edge_t next_index, udplookup_node;
156*51a3c7a1SRakesh Kudurumalla struct rte_udp_hdr *pkt_udp_hdr;
157*51a3c7a1SRakesh Kudurumalla uint16_t last_spec = 0;
158*51a3c7a1SRakesh Kudurumalla void **to_next, **from;
159*51a3c7a1SRakesh Kudurumalla struct rte_mbuf *mbuf;
160*51a3c7a1SRakesh Kudurumalla uint16_t held = 0;
161*51a3c7a1SRakesh Kudurumalla uint16_t next = 0;
162*51a3c7a1SRakesh Kudurumalla int i, rc;
163*51a3c7a1SRakesh Kudurumalla
164*51a3c7a1SRakesh Kudurumalla /* Speculative next */
165*51a3c7a1SRakesh Kudurumalla next_index = UDP4_INPUT_NODE_NEXT_INDEX(node->ctx);
166*51a3c7a1SRakesh Kudurumalla
167*51a3c7a1SRakesh Kudurumalla from = objs;
168*51a3c7a1SRakesh Kudurumalla
169*51a3c7a1SRakesh Kudurumalla to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs);
170*51a3c7a1SRakesh Kudurumalla for (i = 0; i < nb_objs; i++) {
171*51a3c7a1SRakesh Kudurumalla struct flow_key key_port;
172*51a3c7a1SRakesh Kudurumalla
173*51a3c7a1SRakesh Kudurumalla mbuf = (struct rte_mbuf *)objs[i];
174*51a3c7a1SRakesh Kudurumalla pkt_udp_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_udp_hdr *,
175*51a3c7a1SRakesh Kudurumalla sizeof(struct rte_ether_hdr) +
176*51a3c7a1SRakesh Kudurumalla sizeof(struct rte_ipv4_hdr));
177*51a3c7a1SRakesh Kudurumalla
178*51a3c7a1SRakesh Kudurumalla key_port.prt_dst = rte_cpu_to_be_16(pkt_udp_hdr->dst_port);
179*51a3c7a1SRakesh Kudurumalla rc = rte_hash_lookup_data(hash_tbl_handle,
180*51a3c7a1SRakesh Kudurumalla &key_port.prt_dst,
181*51a3c7a1SRakesh Kudurumalla (void **)&udplookup_node);
182*51a3c7a1SRakesh Kudurumalla next = (rc < 0) ? RTE_NODE_UDP4_INPUT_NEXT_PKT_DROP
183*51a3c7a1SRakesh Kudurumalla : udplookup_node;
184*51a3c7a1SRakesh Kudurumalla
185*51a3c7a1SRakesh Kudurumalla if (unlikely(next_index != next)) {
186*51a3c7a1SRakesh Kudurumalla /* Copy things successfully speculated till now */
187*51a3c7a1SRakesh Kudurumalla rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
188*51a3c7a1SRakesh Kudurumalla from += last_spec;
189*51a3c7a1SRakesh Kudurumalla to_next += last_spec;
190*51a3c7a1SRakesh Kudurumalla held += last_spec;
191*51a3c7a1SRakesh Kudurumalla last_spec = 0;
192*51a3c7a1SRakesh Kudurumalla
193*51a3c7a1SRakesh Kudurumalla rte_node_enqueue_x1(graph, node, next, from[0]);
194*51a3c7a1SRakesh Kudurumalla from += 1;
195*51a3c7a1SRakesh Kudurumalla } else {
196*51a3c7a1SRakesh Kudurumalla last_spec += 1;
197*51a3c7a1SRakesh Kudurumalla }
198*51a3c7a1SRakesh Kudurumalla }
199*51a3c7a1SRakesh Kudurumalla /* !!! Home run !!! */
200*51a3c7a1SRakesh Kudurumalla if (likely(last_spec == nb_objs)) {
201*51a3c7a1SRakesh Kudurumalla rte_node_next_stream_move(graph, node, next_index);
202*51a3c7a1SRakesh Kudurumalla return nb_objs;
203*51a3c7a1SRakesh Kudurumalla }
204*51a3c7a1SRakesh Kudurumalla held += last_spec;
205*51a3c7a1SRakesh Kudurumalla rte_memcpy(to_next, from, last_spec * sizeof(from[0]));
206*51a3c7a1SRakesh Kudurumalla rte_node_next_stream_put(graph, node, next_index, held);
207*51a3c7a1SRakesh Kudurumalla /* Save the last next used */
208*51a3c7a1SRakesh Kudurumalla UDP4_INPUT_NODE_NEXT_INDEX(node->ctx) = next;
209*51a3c7a1SRakesh Kudurumalla
210*51a3c7a1SRakesh Kudurumalla return nb_objs;
211*51a3c7a1SRakesh Kudurumalla }
212*51a3c7a1SRakesh Kudurumalla
213*51a3c7a1SRakesh Kudurumalla static struct rte_node_register udp4_input_node = {
214*51a3c7a1SRakesh Kudurumalla .process = udp4_input_node_process_scalar,
215*51a3c7a1SRakesh Kudurumalla .name = "udp4_input",
216*51a3c7a1SRakesh Kudurumalla
217*51a3c7a1SRakesh Kudurumalla .init = udp4_input_node_init,
218*51a3c7a1SRakesh Kudurumalla
219*51a3c7a1SRakesh Kudurumalla .nb_edges = RTE_NODE_UDP4_INPUT_NEXT_PKT_DROP + 1,
220*51a3c7a1SRakesh Kudurumalla .next_nodes = {
221*51a3c7a1SRakesh Kudurumalla [RTE_NODE_UDP4_INPUT_NEXT_PKT_DROP] = "pkt_drop",
222*51a3c7a1SRakesh Kudurumalla },
223*51a3c7a1SRakesh Kudurumalla };
224*51a3c7a1SRakesh Kudurumalla
225*51a3c7a1SRakesh Kudurumalla RTE_NODE_REGISTER(udp4_input_node);
226