10124e18fSPavan Nikhilesh /* SPDX-License-Identifier: BSD-3-Clause 20124e18fSPavan Nikhilesh * Copyright(C) 2023 Marvell. 30124e18fSPavan Nikhilesh */ 40124e18fSPavan Nikhilesh 50124e18fSPavan Nikhilesh #include <arpa/inet.h> 60124e18fSPavan Nikhilesh #include <stdlib.h> 70124e18fSPavan Nikhilesh #include <sys/socket.h> 80124e18fSPavan Nikhilesh 90124e18fSPavan Nikhilesh #include <rte_cycles.h> 100124e18fSPavan Nikhilesh #include <rte_debug.h> 110124e18fSPavan Nikhilesh #include <rte_ethdev.h> 120124e18fSPavan Nikhilesh #include <rte_ether.h> 130124e18fSPavan Nikhilesh #include <rte_graph.h> 140124e18fSPavan Nikhilesh #include <rte_graph_worker.h> 150124e18fSPavan Nikhilesh #include <rte_ip.h> 160124e18fSPavan Nikhilesh #include <rte_ip_frag.h> 170124e18fSPavan Nikhilesh #include <rte_mbuf.h> 180124e18fSPavan Nikhilesh #include <rte_tcp.h> 190124e18fSPavan Nikhilesh #include <rte_udp.h> 200124e18fSPavan Nikhilesh 210124e18fSPavan Nikhilesh #include "rte_node_ip4_api.h" 220124e18fSPavan Nikhilesh 230124e18fSPavan Nikhilesh #include "ip4_reassembly_priv.h" 240124e18fSPavan Nikhilesh #include "node_private.h" 250124e18fSPavan Nikhilesh 260124e18fSPavan Nikhilesh struct ip4_reassembly_elem { 270124e18fSPavan Nikhilesh struct ip4_reassembly_elem *next; 280124e18fSPavan Nikhilesh struct ip4_reassembly_ctx ctx; 290124e18fSPavan Nikhilesh rte_node_t node_id; 300124e18fSPavan Nikhilesh }; 310124e18fSPavan Nikhilesh 320124e18fSPavan Nikhilesh /* IP4 reassembly global data struct */ 330124e18fSPavan Nikhilesh struct ip4_reassembly_node_main { 340124e18fSPavan Nikhilesh struct ip4_reassembly_elem *head; 350124e18fSPavan Nikhilesh }; 360124e18fSPavan Nikhilesh 370124e18fSPavan Nikhilesh typedef struct ip4_reassembly_ctx ip4_reassembly_ctx_t; 380124e18fSPavan Nikhilesh typedef struct ip4_reassembly_elem ip4_reassembly_elem_t; 390124e18fSPavan Nikhilesh 400124e18fSPavan Nikhilesh static struct ip4_reassembly_node_main ip4_reassembly_main; 410124e18fSPavan Nikhilesh 420124e18fSPavan Nikhilesh static uint16_t 430124e18fSPavan Nikhilesh ip4_reassembly_node_process(struct rte_graph *graph, struct rte_node *node, void **objs, 440124e18fSPavan Nikhilesh uint16_t nb_objs) 450124e18fSPavan Nikhilesh { 460124e18fSPavan Nikhilesh #define PREFETCH_OFFSET 4 470124e18fSPavan Nikhilesh struct rte_mbuf *mbuf, *mbuf_out; 480124e18fSPavan Nikhilesh struct rte_ip_frag_death_row *dr; 490124e18fSPavan Nikhilesh struct ip4_reassembly_ctx *ctx; 500124e18fSPavan Nikhilesh struct rte_ipv4_hdr *ipv4_hdr; 510124e18fSPavan Nikhilesh struct rte_ip_frag_tbl *tbl; 520124e18fSPavan Nikhilesh void **to_next, **to_free; 530124e18fSPavan Nikhilesh uint16_t idx = 0; 540124e18fSPavan Nikhilesh int i; 550124e18fSPavan Nikhilesh 560124e18fSPavan Nikhilesh ctx = (struct ip4_reassembly_ctx *)node->ctx; 570124e18fSPavan Nikhilesh 580124e18fSPavan Nikhilesh /* Get core specific reassembly tbl */ 590124e18fSPavan Nikhilesh tbl = ctx->tbl; 600124e18fSPavan Nikhilesh dr = ctx->dr; 610124e18fSPavan Nikhilesh 620124e18fSPavan Nikhilesh for (i = 0; i < PREFETCH_OFFSET && i < nb_objs; i++) { 630124e18fSPavan Nikhilesh rte_prefetch0(rte_pktmbuf_mtod_offset((struct rte_mbuf *)objs[i], void *, 640124e18fSPavan Nikhilesh sizeof(struct rte_ether_hdr))); 650124e18fSPavan Nikhilesh } 660124e18fSPavan Nikhilesh 670124e18fSPavan Nikhilesh to_next = node->objs; 680124e18fSPavan Nikhilesh for (i = 0; i < nb_objs - PREFETCH_OFFSET; i++) { 690124e18fSPavan Nikhilesh #if RTE_GRAPH_BURST_SIZE > 64 700124e18fSPavan Nikhilesh /* Prefetch next-next mbufs */ 710124e18fSPavan Nikhilesh if (likely(i + 8 < nb_objs)) 720124e18fSPavan Nikhilesh rte_prefetch0(objs[i + 8]); 730124e18fSPavan Nikhilesh #endif 740124e18fSPavan Nikhilesh rte_prefetch0(rte_pktmbuf_mtod_offset((struct rte_mbuf *)objs[i + PREFETCH_OFFSET], 750124e18fSPavan Nikhilesh void *, sizeof(struct rte_ether_hdr))); 760124e18fSPavan Nikhilesh mbuf = (struct rte_mbuf *)objs[i]; 770124e18fSPavan Nikhilesh 780124e18fSPavan Nikhilesh ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, 790124e18fSPavan Nikhilesh sizeof(struct rte_ether_hdr)); 800124e18fSPavan Nikhilesh if (rte_ipv4_frag_pkt_is_fragmented(ipv4_hdr)) { 810124e18fSPavan Nikhilesh /* prepare mbuf: setup l2_len/l3_len. */ 820124e18fSPavan Nikhilesh mbuf->l2_len = sizeof(struct rte_ether_hdr); 830124e18fSPavan Nikhilesh mbuf->l3_len = sizeof(struct rte_ipv4_hdr); 840124e18fSPavan Nikhilesh 850124e18fSPavan Nikhilesh mbuf_out = rte_ipv4_frag_reassemble_packet(tbl, dr, mbuf, rte_rdtsc(), 860124e18fSPavan Nikhilesh ipv4_hdr); 870124e18fSPavan Nikhilesh } else { 880124e18fSPavan Nikhilesh mbuf_out = mbuf; 890124e18fSPavan Nikhilesh } 900124e18fSPavan Nikhilesh 910124e18fSPavan Nikhilesh if (mbuf_out) 920124e18fSPavan Nikhilesh to_next[idx++] = (void *)mbuf_out; 930124e18fSPavan Nikhilesh } 940124e18fSPavan Nikhilesh 950124e18fSPavan Nikhilesh for (; i < nb_objs; i++) { 960124e18fSPavan Nikhilesh mbuf = (struct rte_mbuf *)objs[i]; 970124e18fSPavan Nikhilesh 980124e18fSPavan Nikhilesh ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, 990124e18fSPavan Nikhilesh sizeof(struct rte_ether_hdr)); 1000124e18fSPavan Nikhilesh if (rte_ipv4_frag_pkt_is_fragmented(ipv4_hdr)) { 1010124e18fSPavan Nikhilesh /* prepare mbuf: setup l2_len/l3_len. */ 1020124e18fSPavan Nikhilesh mbuf->l2_len = sizeof(struct rte_ether_hdr); 1030124e18fSPavan Nikhilesh mbuf->l3_len = sizeof(struct rte_ipv4_hdr); 1040124e18fSPavan Nikhilesh 1050124e18fSPavan Nikhilesh mbuf_out = rte_ipv4_frag_reassemble_packet(tbl, dr, mbuf, rte_rdtsc(), 1060124e18fSPavan Nikhilesh ipv4_hdr); 1070124e18fSPavan Nikhilesh } else { 1080124e18fSPavan Nikhilesh mbuf_out = mbuf; 1090124e18fSPavan Nikhilesh } 1100124e18fSPavan Nikhilesh 1110124e18fSPavan Nikhilesh if (mbuf_out) 1120124e18fSPavan Nikhilesh to_next[idx++] = (void *)mbuf_out; 1130124e18fSPavan Nikhilesh } 1140124e18fSPavan Nikhilesh node->idx = idx; 1150124e18fSPavan Nikhilesh rte_node_next_stream_move(graph, node, 1); 1160124e18fSPavan Nikhilesh if (dr->cnt) { 1170124e18fSPavan Nikhilesh to_free = rte_node_next_stream_get(graph, node, 1180124e18fSPavan Nikhilesh RTE_NODE_IP4_REASSEMBLY_NEXT_PKT_DROP, dr->cnt); 1190124e18fSPavan Nikhilesh rte_memcpy(to_free, dr->row, dr->cnt * sizeof(to_free[0])); 1200124e18fSPavan Nikhilesh rte_node_next_stream_put(graph, node, RTE_NODE_IP4_REASSEMBLY_NEXT_PKT_DROP, 1210124e18fSPavan Nikhilesh dr->cnt); 1220124e18fSPavan Nikhilesh idx += dr->cnt; 123*be4c0cb4SPavan Nikhilesh NODE_INCREMENT_XSTAT_ID(node, 0, dr->cnt, dr->cnt); 1240124e18fSPavan Nikhilesh dr->cnt = 0; 1250124e18fSPavan Nikhilesh } 1260124e18fSPavan Nikhilesh 1270124e18fSPavan Nikhilesh return idx; 1280124e18fSPavan Nikhilesh } 1290124e18fSPavan Nikhilesh 1300124e18fSPavan Nikhilesh int 1310124e18fSPavan Nikhilesh rte_node_ip4_reassembly_configure(struct rte_node_ip4_reassembly_cfg *cfg, uint16_t cnt) 1320124e18fSPavan Nikhilesh { 1330124e18fSPavan Nikhilesh ip4_reassembly_elem_t *elem; 1340124e18fSPavan Nikhilesh int i; 1350124e18fSPavan Nikhilesh 1360124e18fSPavan Nikhilesh for (i = 0; i < cnt; i++) { 1370124e18fSPavan Nikhilesh elem = malloc(sizeof(ip4_reassembly_elem_t)); 1380124e18fSPavan Nikhilesh if (elem == NULL) 1390124e18fSPavan Nikhilesh return -ENOMEM; 1400124e18fSPavan Nikhilesh elem->ctx.dr = cfg[i].dr; 1410124e18fSPavan Nikhilesh elem->ctx.tbl = cfg[i].tbl; 1420124e18fSPavan Nikhilesh elem->node_id = cfg[i].node_id; 1430124e18fSPavan Nikhilesh elem->next = ip4_reassembly_main.head; 1440124e18fSPavan Nikhilesh ip4_reassembly_main.head = elem; 1450124e18fSPavan Nikhilesh } 1460124e18fSPavan Nikhilesh 1470124e18fSPavan Nikhilesh return 0; 1480124e18fSPavan Nikhilesh } 1490124e18fSPavan Nikhilesh 1500124e18fSPavan Nikhilesh static int 1510124e18fSPavan Nikhilesh ip4_reassembly_node_init(const struct rte_graph *graph, struct rte_node *node) 1520124e18fSPavan Nikhilesh { 1530124e18fSPavan Nikhilesh ip4_reassembly_ctx_t *ctx = (ip4_reassembly_ctx_t *)node->ctx; 1540124e18fSPavan Nikhilesh ip4_reassembly_elem_t *elem = ip4_reassembly_main.head; 1550124e18fSPavan Nikhilesh 1560124e18fSPavan Nikhilesh RTE_SET_USED(graph); 1570124e18fSPavan Nikhilesh while (elem) { 1580124e18fSPavan Nikhilesh if (elem->node_id == node->id) { 1590124e18fSPavan Nikhilesh /* Update node specific context */ 1600124e18fSPavan Nikhilesh memcpy(ctx, &elem->ctx, sizeof(ip4_reassembly_ctx_t)); 1610124e18fSPavan Nikhilesh break; 1620124e18fSPavan Nikhilesh } 1630124e18fSPavan Nikhilesh elem = elem->next; 1640124e18fSPavan Nikhilesh } 1650124e18fSPavan Nikhilesh 1660124e18fSPavan Nikhilesh return 0; 1670124e18fSPavan Nikhilesh } 1680124e18fSPavan Nikhilesh 169*be4c0cb4SPavan Nikhilesh static struct rte_node_xstats ip4_reassembly_xstats = { 170*be4c0cb4SPavan Nikhilesh .nb_xstats = 1, 171*be4c0cb4SPavan Nikhilesh .xstat_desc = { 172*be4c0cb4SPavan Nikhilesh [0] = "ip4_reassembly_error", 173*be4c0cb4SPavan Nikhilesh }, 174*be4c0cb4SPavan Nikhilesh }; 175*be4c0cb4SPavan Nikhilesh 1760124e18fSPavan Nikhilesh static struct rte_node_register ip4_reassembly_node = { 1770124e18fSPavan Nikhilesh .process = ip4_reassembly_node_process, 1780124e18fSPavan Nikhilesh .name = "ip4_reassembly", 1790124e18fSPavan Nikhilesh 1800124e18fSPavan Nikhilesh .init = ip4_reassembly_node_init, 181*be4c0cb4SPavan Nikhilesh .xstats = &ip4_reassembly_xstats, 1820124e18fSPavan Nikhilesh 1830124e18fSPavan Nikhilesh .nb_edges = RTE_NODE_IP4_REASSEMBLY_NEXT_PKT_DROP + 1, 1840124e18fSPavan Nikhilesh .next_nodes = { 1850124e18fSPavan Nikhilesh [RTE_NODE_IP4_REASSEMBLY_NEXT_PKT_DROP] = "pkt_drop", 1860124e18fSPavan Nikhilesh }, 1870124e18fSPavan Nikhilesh }; 1880124e18fSPavan Nikhilesh 1890124e18fSPavan Nikhilesh struct rte_node_register * 1900124e18fSPavan Nikhilesh ip4_reassembly_node_get(void) 1910124e18fSPavan Nikhilesh { 1920124e18fSPavan Nikhilesh return &ip4_reassembly_node; 1930124e18fSPavan Nikhilesh } 1940124e18fSPavan Nikhilesh 1950124e18fSPavan Nikhilesh RTE_NODE_REGISTER(ip4_reassembly_node); 196