12d0cf6a7SVamsi Attunuru /* SPDX-License-Identifier: BSD-3-Clause
22d0cf6a7SVamsi Attunuru * Copyright(C) 2023 Marvell International Ltd.
32d0cf6a7SVamsi Attunuru */
42d0cf6a7SVamsi Attunuru
52d0cf6a7SVamsi Attunuru #include <fcntl.h>
62d0cf6a7SVamsi Attunuru #include <poll.h>
72d0cf6a7SVamsi Attunuru #include <stdlib.h>
82d0cf6a7SVamsi Attunuru #include <sys/ioctl.h>
92d0cf6a7SVamsi Attunuru #include <sys/socket.h>
102d0cf6a7SVamsi Attunuru #include <unistd.h>
112d0cf6a7SVamsi Attunuru
122d0cf6a7SVamsi Attunuru #include <rte_debug.h>
132d0cf6a7SVamsi Attunuru #include <rte_ethdev.h>
142d0cf6a7SVamsi Attunuru #include <rte_graph.h>
15a2bc0584SZhirun Yan #include <rte_graph_worker.h>
162d0cf6a7SVamsi Attunuru #include <rte_ip.h>
172d0cf6a7SVamsi Attunuru #include <rte_malloc.h>
182d0cf6a7SVamsi Attunuru #include <rte_mbuf.h>
192d0cf6a7SVamsi Attunuru #include <rte_mempool.h>
202d0cf6a7SVamsi Attunuru #include <rte_net.h>
212d0cf6a7SVamsi Attunuru
222d0cf6a7SVamsi Attunuru #include "ethdev_rx_priv.h"
232d0cf6a7SVamsi Attunuru #include "kernel_rx_priv.h"
242d0cf6a7SVamsi Attunuru #include "node_private.h"
252d0cf6a7SVamsi Attunuru
262d0cf6a7SVamsi Attunuru static inline struct rte_mbuf *
alloc_rx_mbuf(kernel_rx_node_ctx_t * ctx)272d0cf6a7SVamsi Attunuru alloc_rx_mbuf(kernel_rx_node_ctx_t *ctx)
282d0cf6a7SVamsi Attunuru {
292d0cf6a7SVamsi Attunuru kernel_rx_info_t *rx = ctx->recv_info;
302d0cf6a7SVamsi Attunuru
312d0cf6a7SVamsi Attunuru if (rx->idx >= rx->cnt) {
322d0cf6a7SVamsi Attunuru uint16_t cnt;
332d0cf6a7SVamsi Attunuru
342d0cf6a7SVamsi Attunuru rx->idx = 0;
352d0cf6a7SVamsi Attunuru rx->cnt = 0;
362d0cf6a7SVamsi Attunuru
372d0cf6a7SVamsi Attunuru cnt = rte_pktmbuf_alloc_bulk(ctx->pktmbuf_pool, rx->rx_bufs, KERN_RX_CACHE_COUNT);
382d0cf6a7SVamsi Attunuru if (cnt <= 0)
392d0cf6a7SVamsi Attunuru return NULL;
402d0cf6a7SVamsi Attunuru
412d0cf6a7SVamsi Attunuru rx->cnt = cnt;
422d0cf6a7SVamsi Attunuru }
432d0cf6a7SVamsi Attunuru
442d0cf6a7SVamsi Attunuru return rx->rx_bufs[rx->idx++];
452d0cf6a7SVamsi Attunuru }
462d0cf6a7SVamsi Attunuru
472d0cf6a7SVamsi Attunuru static inline void
mbuf_update(struct rte_mbuf ** mbufs,uint16_t nb_pkts)482d0cf6a7SVamsi Attunuru mbuf_update(struct rte_mbuf **mbufs, uint16_t nb_pkts)
492d0cf6a7SVamsi Attunuru {
502d0cf6a7SVamsi Attunuru struct rte_net_hdr_lens hdr_lens;
512d0cf6a7SVamsi Attunuru struct rte_mbuf *m;
522d0cf6a7SVamsi Attunuru int i;
532d0cf6a7SVamsi Attunuru
542d0cf6a7SVamsi Attunuru for (i = 0; i < nb_pkts; i++) {
552d0cf6a7SVamsi Attunuru m = mbufs[i];
562d0cf6a7SVamsi Attunuru
572d0cf6a7SVamsi Attunuru m->packet_type = rte_net_get_ptype(m, &hdr_lens, RTE_PTYPE_ALL_MASK);
582d0cf6a7SVamsi Attunuru
592d0cf6a7SVamsi Attunuru m->ol_flags = 0;
602d0cf6a7SVamsi Attunuru m->tx_offload = 0;
612d0cf6a7SVamsi Attunuru
622d0cf6a7SVamsi Attunuru m->l2_len = hdr_lens.l2_len;
632d0cf6a7SVamsi Attunuru m->l3_len = hdr_lens.l3_len;
642d0cf6a7SVamsi Attunuru m->l4_len = hdr_lens.l4_len;
652d0cf6a7SVamsi Attunuru }
662d0cf6a7SVamsi Attunuru }
672d0cf6a7SVamsi Attunuru
682d0cf6a7SVamsi Attunuru static uint16_t
recv_pkt_parse(void ** objs,uint16_t nb_pkts)692d0cf6a7SVamsi Attunuru recv_pkt_parse(void **objs, uint16_t nb_pkts)
702d0cf6a7SVamsi Attunuru {
712d0cf6a7SVamsi Attunuru uint16_t pkts_left = nb_pkts;
722d0cf6a7SVamsi Attunuru struct rte_mbuf **pkts;
732d0cf6a7SVamsi Attunuru int i;
742d0cf6a7SVamsi Attunuru
752d0cf6a7SVamsi Attunuru pkts = (struct rte_mbuf **)objs;
762d0cf6a7SVamsi Attunuru
772d0cf6a7SVamsi Attunuru if (pkts_left >= 4) {
782d0cf6a7SVamsi Attunuru for (i = 0; i < 4; i++)
792d0cf6a7SVamsi Attunuru rte_prefetch0(rte_pktmbuf_mtod(pkts[i], void *));
802d0cf6a7SVamsi Attunuru }
812d0cf6a7SVamsi Attunuru
822d0cf6a7SVamsi Attunuru while (pkts_left >= 12) {
832d0cf6a7SVamsi Attunuru /* Prefetch next-next mbufs */
842d0cf6a7SVamsi Attunuru rte_prefetch0(pkts[8]);
852d0cf6a7SVamsi Attunuru rte_prefetch0(pkts[9]);
862d0cf6a7SVamsi Attunuru rte_prefetch0(pkts[10]);
872d0cf6a7SVamsi Attunuru rte_prefetch0(pkts[11]);
882d0cf6a7SVamsi Attunuru
892d0cf6a7SVamsi Attunuru /* Prefetch next mbuf data */
902d0cf6a7SVamsi Attunuru rte_prefetch0(rte_pktmbuf_mtod(pkts[4], void *));
912d0cf6a7SVamsi Attunuru rte_prefetch0(rte_pktmbuf_mtod(pkts[5], void *));
922d0cf6a7SVamsi Attunuru rte_prefetch0(rte_pktmbuf_mtod(pkts[6], void *));
932d0cf6a7SVamsi Attunuru rte_prefetch0(rte_pktmbuf_mtod(pkts[7], void *));
942d0cf6a7SVamsi Attunuru
952d0cf6a7SVamsi Attunuru /* Extract ptype of mbufs */
962d0cf6a7SVamsi Attunuru mbuf_update(pkts, 4);
972d0cf6a7SVamsi Attunuru
982d0cf6a7SVamsi Attunuru pkts += 4;
992d0cf6a7SVamsi Attunuru pkts_left -= 4;
1002d0cf6a7SVamsi Attunuru }
1012d0cf6a7SVamsi Attunuru
1022d0cf6a7SVamsi Attunuru if (pkts_left > 0)
1032d0cf6a7SVamsi Attunuru mbuf_update(pkts, pkts_left);
1042d0cf6a7SVamsi Attunuru
1052d0cf6a7SVamsi Attunuru return nb_pkts;
1062d0cf6a7SVamsi Attunuru }
1072d0cf6a7SVamsi Attunuru
1082d0cf6a7SVamsi Attunuru static uint16_t
kernel_rx_node_do(struct rte_graph * graph,struct rte_node * node,kernel_rx_node_ctx_t * ctx)1092d0cf6a7SVamsi Attunuru kernel_rx_node_do(struct rte_graph *graph, struct rte_node *node, kernel_rx_node_ctx_t *ctx)
1102d0cf6a7SVamsi Attunuru {
1112d0cf6a7SVamsi Attunuru kernel_rx_info_t *rx;
1122d0cf6a7SVamsi Attunuru uint16_t next_index;
1132d0cf6a7SVamsi Attunuru int fd;
1142d0cf6a7SVamsi Attunuru
1152d0cf6a7SVamsi Attunuru rx = ctx->recv_info;
1162d0cf6a7SVamsi Attunuru next_index = rx->node_next;
1172d0cf6a7SVamsi Attunuru
1182d0cf6a7SVamsi Attunuru fd = rx->sock;
1192d0cf6a7SVamsi Attunuru if (fd > 0) {
1202d0cf6a7SVamsi Attunuru struct rte_mbuf **mbufs;
1212d0cf6a7SVamsi Attunuru uint16_t len = 0, count = 0;
1222d0cf6a7SVamsi Attunuru int nb_cnt, i;
1232d0cf6a7SVamsi Attunuru
1242d0cf6a7SVamsi Attunuru nb_cnt = (node->size >= RTE_GRAPH_BURST_SIZE) ? RTE_GRAPH_BURST_SIZE : node->size;
1252d0cf6a7SVamsi Attunuru
1262d0cf6a7SVamsi Attunuru mbufs = (struct rte_mbuf **)node->objs;
1272d0cf6a7SVamsi Attunuru for (i = 0; i < nb_cnt; i++) {
1282d0cf6a7SVamsi Attunuru struct rte_mbuf *m = alloc_rx_mbuf(ctx);
1292d0cf6a7SVamsi Attunuru
1302d0cf6a7SVamsi Attunuru if (!m)
1312d0cf6a7SVamsi Attunuru break;
1322d0cf6a7SVamsi Attunuru
1332d0cf6a7SVamsi Attunuru len = read(fd, rte_pktmbuf_mtod(m, char *), rte_pktmbuf_tailroom(m));
1342d0cf6a7SVamsi Attunuru if (len == 0 || len == 0xFFFF) {
1352d0cf6a7SVamsi Attunuru rte_pktmbuf_free(m);
1362d0cf6a7SVamsi Attunuru if (rx->idx <= 0)
137*ae282b06SDavid Marchand node_dbg("kernel_rx", "rx_mbuf array is empty");
1382d0cf6a7SVamsi Attunuru rx->idx--;
1392d0cf6a7SVamsi Attunuru break;
1402d0cf6a7SVamsi Attunuru }
1412d0cf6a7SVamsi Attunuru *mbufs++ = m;
1422d0cf6a7SVamsi Attunuru
1432d0cf6a7SVamsi Attunuru m->port = node->id;
1442d0cf6a7SVamsi Attunuru rte_pktmbuf_data_len(m) = len;
1452d0cf6a7SVamsi Attunuru
1462d0cf6a7SVamsi Attunuru count++;
1472d0cf6a7SVamsi Attunuru }
1482d0cf6a7SVamsi Attunuru
1492d0cf6a7SVamsi Attunuru if (count) {
1502d0cf6a7SVamsi Attunuru recv_pkt_parse(node->objs, count);
1512d0cf6a7SVamsi Attunuru node->idx = count;
1522d0cf6a7SVamsi Attunuru
1532d0cf6a7SVamsi Attunuru /* Enqueue to next node */
1542d0cf6a7SVamsi Attunuru rte_node_next_stream_move(graph, node, next_index);
1552d0cf6a7SVamsi Attunuru }
1562d0cf6a7SVamsi Attunuru
1572d0cf6a7SVamsi Attunuru return count;
1582d0cf6a7SVamsi Attunuru }
1592d0cf6a7SVamsi Attunuru
1602d0cf6a7SVamsi Attunuru return 0;
1612d0cf6a7SVamsi Attunuru }
1622d0cf6a7SVamsi Attunuru
1632d0cf6a7SVamsi Attunuru static uint16_t
kernel_rx_node_process(struct rte_graph * graph,struct rte_node * node,void ** objs,uint16_t nb_objs)1642d0cf6a7SVamsi Attunuru kernel_rx_node_process(struct rte_graph *graph, struct rte_node *node, void **objs,
1652d0cf6a7SVamsi Attunuru uint16_t nb_objs)
1662d0cf6a7SVamsi Attunuru {
1672d0cf6a7SVamsi Attunuru kernel_rx_node_ctx_t *ctx = (kernel_rx_node_ctx_t *)node->ctx;
1682d0cf6a7SVamsi Attunuru int fd;
1692d0cf6a7SVamsi Attunuru
1702d0cf6a7SVamsi Attunuru RTE_SET_USED(objs);
1712d0cf6a7SVamsi Attunuru RTE_SET_USED(nb_objs);
1722d0cf6a7SVamsi Attunuru
1732d0cf6a7SVamsi Attunuru if (!ctx)
1742d0cf6a7SVamsi Attunuru return 0;
1752d0cf6a7SVamsi Attunuru
1762d0cf6a7SVamsi Attunuru fd = ctx->recv_info->sock;
1772d0cf6a7SVamsi Attunuru if (fd > 0) {
1782d0cf6a7SVamsi Attunuru struct pollfd fds = {.fd = fd, .events = POLLIN};
1792d0cf6a7SVamsi Attunuru
1802d0cf6a7SVamsi Attunuru if (poll(&fds, 1, 0) > 0) {
1812d0cf6a7SVamsi Attunuru if (fds.revents & POLLIN)
1822d0cf6a7SVamsi Attunuru return kernel_rx_node_do(graph, node, ctx);
1832d0cf6a7SVamsi Attunuru }
1842d0cf6a7SVamsi Attunuru }
1852d0cf6a7SVamsi Attunuru
1862d0cf6a7SVamsi Attunuru return 0;
1872d0cf6a7SVamsi Attunuru }
1882d0cf6a7SVamsi Attunuru
1892d0cf6a7SVamsi Attunuru static int
kernel_rx_node_init(const struct rte_graph * graph,struct rte_node * node)1902d0cf6a7SVamsi Attunuru kernel_rx_node_init(const struct rte_graph *graph, struct rte_node *node)
1912d0cf6a7SVamsi Attunuru {
1922d0cf6a7SVamsi Attunuru struct kernel_rx_node_main *rx_node_main = kernel_rx_node_data_get();
1932d0cf6a7SVamsi Attunuru kernel_rx_node_ctx_t *ctx = (kernel_rx_node_ctx_t *)node->ctx;
1942d0cf6a7SVamsi Attunuru kernel_rx_node_elem_t *elem = rx_node_main->head;
1952d0cf6a7SVamsi Attunuru kernel_rx_info_t *recv_info;
1962d0cf6a7SVamsi Attunuru int sock;
1972d0cf6a7SVamsi Attunuru
1982d0cf6a7SVamsi Attunuru while (elem) {
1992d0cf6a7SVamsi Attunuru if (elem->nid == node->id) {
2002d0cf6a7SVamsi Attunuru /* Update node specific context */
2012d0cf6a7SVamsi Attunuru memcpy(ctx, &elem->ctx, sizeof(kernel_rx_node_ctx_t));
2022d0cf6a7SVamsi Attunuru break;
2032d0cf6a7SVamsi Attunuru }
2042d0cf6a7SVamsi Attunuru elem = elem->next;
2052d0cf6a7SVamsi Attunuru }
2062d0cf6a7SVamsi Attunuru
2072d0cf6a7SVamsi Attunuru RTE_VERIFY(elem != NULL);
2082d0cf6a7SVamsi Attunuru
2092d0cf6a7SVamsi Attunuru if (ctx->pktmbuf_pool == NULL) {
210*ae282b06SDavid Marchand node_err("kernel_rx", "Invalid mbuf pool on graph %s", graph->name);
2112d0cf6a7SVamsi Attunuru return -EINVAL;
2122d0cf6a7SVamsi Attunuru }
2132d0cf6a7SVamsi Attunuru
2142d0cf6a7SVamsi Attunuru recv_info = rte_zmalloc_socket("kernel_rx_info", sizeof(kernel_rx_info_t),
2152d0cf6a7SVamsi Attunuru RTE_CACHE_LINE_SIZE, graph->socket);
2162d0cf6a7SVamsi Attunuru if (!recv_info) {
217*ae282b06SDavid Marchand node_err("kernel_rx", "Kernel recv_info is NULL");
2182d0cf6a7SVamsi Attunuru return -ENOMEM;
2192d0cf6a7SVamsi Attunuru }
2202d0cf6a7SVamsi Attunuru
2212d0cf6a7SVamsi Attunuru sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2222d0cf6a7SVamsi Attunuru if (sock < 0) {
223*ae282b06SDavid Marchand node_err("kernel_rx", "Unable to open RAW socket");
2242d0cf6a7SVamsi Attunuru return sock;
2252d0cf6a7SVamsi Attunuru }
2262d0cf6a7SVamsi Attunuru
2272d0cf6a7SVamsi Attunuru recv_info->sock = sock;
2282d0cf6a7SVamsi Attunuru ctx->recv_info = recv_info;
2292d0cf6a7SVamsi Attunuru
2302d0cf6a7SVamsi Attunuru return 0;
2312d0cf6a7SVamsi Attunuru }
2322d0cf6a7SVamsi Attunuru
2332d0cf6a7SVamsi Attunuru static void
kernel_rx_node_fini(const struct rte_graph * graph __rte_unused,struct rte_node * node)2342d0cf6a7SVamsi Attunuru kernel_rx_node_fini(const struct rte_graph *graph __rte_unused, struct rte_node *node)
2352d0cf6a7SVamsi Attunuru {
2362d0cf6a7SVamsi Attunuru kernel_rx_node_ctx_t *ctx = (kernel_rx_node_ctx_t *)node->ctx;
2372d0cf6a7SVamsi Attunuru
2382d0cf6a7SVamsi Attunuru if (ctx->recv_info) {
2392d0cf6a7SVamsi Attunuru close(ctx->recv_info->sock);
2402d0cf6a7SVamsi Attunuru ctx->recv_info->sock = -1;
2412d0cf6a7SVamsi Attunuru rte_free(ctx->recv_info);
2422d0cf6a7SVamsi Attunuru }
2432d0cf6a7SVamsi Attunuru
2442d0cf6a7SVamsi Attunuru ctx->recv_info = NULL;
2452d0cf6a7SVamsi Attunuru }
2462d0cf6a7SVamsi Attunuru
2472d0cf6a7SVamsi Attunuru struct kernel_rx_node_main *
kernel_rx_node_data_get(void)2482d0cf6a7SVamsi Attunuru kernel_rx_node_data_get(void)
2492d0cf6a7SVamsi Attunuru {
2502d0cf6a7SVamsi Attunuru static struct kernel_rx_node_main kernel_rx_main;
2512d0cf6a7SVamsi Attunuru
2522d0cf6a7SVamsi Attunuru return &kernel_rx_main;
2532d0cf6a7SVamsi Attunuru }
2542d0cf6a7SVamsi Attunuru
2552d0cf6a7SVamsi Attunuru static struct rte_node_register kernel_rx_node_base = {
2562d0cf6a7SVamsi Attunuru .process = kernel_rx_node_process,
2572d0cf6a7SVamsi Attunuru .flags = RTE_NODE_SOURCE_F,
2582d0cf6a7SVamsi Attunuru .name = "kernel_rx",
2592d0cf6a7SVamsi Attunuru
2602d0cf6a7SVamsi Attunuru .init = kernel_rx_node_init,
2612d0cf6a7SVamsi Attunuru .fini = kernel_rx_node_fini,
2622d0cf6a7SVamsi Attunuru
2632d0cf6a7SVamsi Attunuru .nb_edges = KERNEL_RX_NEXT_MAX,
2642d0cf6a7SVamsi Attunuru .next_nodes = {
2652d0cf6a7SVamsi Attunuru [KERNEL_RX_NEXT_PKT_CLS] = "pkt_cls",
2662d0cf6a7SVamsi Attunuru [KERNEL_RX_NEXT_IP4_LOOKUP] = "ip4_lookup",
2672d0cf6a7SVamsi Attunuru },
2682d0cf6a7SVamsi Attunuru };
2692d0cf6a7SVamsi Attunuru
2702d0cf6a7SVamsi Attunuru struct rte_node_register *
kernel_rx_node_get(void)2712d0cf6a7SVamsi Attunuru kernel_rx_node_get(void)
2722d0cf6a7SVamsi Attunuru {
2732d0cf6a7SVamsi Attunuru return &kernel_rx_node_base;
2742d0cf6a7SVamsi Attunuru }
2752d0cf6a7SVamsi Attunuru
2762d0cf6a7SVamsi Attunuru RTE_NODE_REGISTER(kernel_rx_node_base);
277