199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(C) 2020 Marvell International Ltd. 399a2dd95SBruce Richardson */ 499a2dd95SBruce Richardson 599a2dd95SBruce Richardson #include <arpa/inet.h> 699a2dd95SBruce Richardson #include <sys/socket.h> 799a2dd95SBruce Richardson 899a2dd95SBruce Richardson #include <rte_ethdev.h> 999a2dd95SBruce Richardson #include <rte_ether.h> 1099a2dd95SBruce Richardson #include <rte_graph.h> 11a2bc0584SZhirun Yan #include <rte_graph_worker.h> 1299a2dd95SBruce Richardson #include <rte_ip.h> 1399a2dd95SBruce Richardson #include <rte_lpm.h> 1499a2dd95SBruce Richardson 1599a2dd95SBruce Richardson #include "rte_node_ip4_api.h" 1699a2dd95SBruce Richardson 1799a2dd95SBruce Richardson #include "node_private.h" 1899a2dd95SBruce Richardson 1999a2dd95SBruce Richardson #define IPV4_L3FWD_LPM_MAX_RULES 1024 2099a2dd95SBruce Richardson #define IPV4_L3FWD_LPM_NUMBER_TBL8S (1 << 8) 2199a2dd95SBruce Richardson 2299a2dd95SBruce Richardson /* IP4 Lookup global data struct */ 2399a2dd95SBruce Richardson struct ip4_lookup_node_main { 2499a2dd95SBruce Richardson struct rte_lpm *lpm_tbl[RTE_MAX_NUMA_NODES]; 2599a2dd95SBruce Richardson }; 2699a2dd95SBruce Richardson 2799a2dd95SBruce Richardson struct ip4_lookup_node_ctx { 2899a2dd95SBruce Richardson /* Socket's LPM table */ 2999a2dd95SBruce Richardson struct rte_lpm *lpm; 3099a2dd95SBruce Richardson /* Dynamic offset to mbuf priv1 */ 3199a2dd95SBruce Richardson int mbuf_priv1_off; 3299a2dd95SBruce Richardson }; 3399a2dd95SBruce Richardson 3499a2dd95SBruce Richardson int node_mbuf_priv1_dynfield_offset = -1; 3599a2dd95SBruce Richardson 3699a2dd95SBruce Richardson static struct ip4_lookup_node_main ip4_lookup_nm; 3799a2dd95SBruce Richardson 3899a2dd95SBruce Richardson #define IP4_LOOKUP_NODE_LPM(ctx) \ 3999a2dd95SBruce Richardson (((struct ip4_lookup_node_ctx *)ctx)->lpm) 4099a2dd95SBruce Richardson 4199a2dd95SBruce Richardson #define IP4_LOOKUP_NODE_PRIV1_OFF(ctx) \ 4299a2dd95SBruce Richardson (((struct ip4_lookup_node_ctx *)ctx)->mbuf_priv1_off) 4399a2dd95SBruce Richardson 4499a2dd95SBruce Richardson #if defined(__ARM_NEON) 4599a2dd95SBruce Richardson #include "ip4_lookup_neon.h" 4699a2dd95SBruce Richardson #elif defined(RTE_ARCH_X86) 4799a2dd95SBruce Richardson #include "ip4_lookup_sse.h" 4899a2dd95SBruce Richardson #endif 4999a2dd95SBruce Richardson 5099a2dd95SBruce Richardson static uint16_t 5199a2dd95SBruce Richardson ip4_lookup_node_process_scalar(struct rte_graph *graph, struct rte_node *node, 5299a2dd95SBruce Richardson void **objs, uint16_t nb_objs) 5399a2dd95SBruce Richardson { 5499a2dd95SBruce Richardson struct rte_lpm *lpm = IP4_LOOKUP_NODE_LPM(node->ctx); 5599a2dd95SBruce Richardson const int dyn = IP4_LOOKUP_NODE_PRIV1_OFF(node->ctx); 5699a2dd95SBruce Richardson struct rte_ipv4_hdr *ipv4_hdr; 5799a2dd95SBruce Richardson void **to_next, **from; 5899a2dd95SBruce Richardson uint16_t last_spec = 0; 5999a2dd95SBruce Richardson struct rte_mbuf *mbuf; 6099a2dd95SBruce Richardson rte_edge_t next_index; 6199a2dd95SBruce Richardson uint16_t held = 0; 6299a2dd95SBruce Richardson uint32_t drop_nh; 6399a2dd95SBruce Richardson int i, rc; 6499a2dd95SBruce Richardson 6599a2dd95SBruce Richardson /* Speculative next */ 6699a2dd95SBruce Richardson next_index = RTE_NODE_IP4_LOOKUP_NEXT_REWRITE; 6799a2dd95SBruce Richardson /* Drop node */ 6899a2dd95SBruce Richardson drop_nh = ((uint32_t)RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP) << 16; 6999a2dd95SBruce Richardson from = objs; 7099a2dd95SBruce Richardson 7199a2dd95SBruce Richardson /* Get stream for the speculated next node */ 7299a2dd95SBruce Richardson to_next = rte_node_next_stream_get(graph, node, next_index, nb_objs); 7399a2dd95SBruce Richardson for (i = 0; i < nb_objs; i++) { 7499a2dd95SBruce Richardson uint32_t next_hop; 7599a2dd95SBruce Richardson uint16_t next; 7699a2dd95SBruce Richardson 7799a2dd95SBruce Richardson mbuf = (struct rte_mbuf *)objs[i]; 7899a2dd95SBruce Richardson 7999a2dd95SBruce Richardson /* Extract DIP of mbuf0 */ 8099a2dd95SBruce Richardson ipv4_hdr = rte_pktmbuf_mtod_offset(mbuf, struct rte_ipv4_hdr *, 8199a2dd95SBruce Richardson sizeof(struct rte_ether_hdr)); 8299a2dd95SBruce Richardson /* Extract cksum, ttl as ipv4 hdr is in cache */ 8399a2dd95SBruce Richardson node_mbuf_priv1(mbuf, dyn)->cksum = ipv4_hdr->hdr_checksum; 8499a2dd95SBruce Richardson node_mbuf_priv1(mbuf, dyn)->ttl = ipv4_hdr->time_to_live; 8599a2dd95SBruce Richardson 8699a2dd95SBruce Richardson rc = rte_lpm_lookup(lpm, rte_be_to_cpu_32(ipv4_hdr->dst_addr), 8799a2dd95SBruce Richardson &next_hop); 8899a2dd95SBruce Richardson next_hop = (rc == 0) ? next_hop : drop_nh; 89*be4c0cb4SPavan Nikhilesh NODE_INCREMENT_XSTAT_ID(node, 0, rc != 0, 1); 9099a2dd95SBruce Richardson 9199a2dd95SBruce Richardson node_mbuf_priv1(mbuf, dyn)->nh = (uint16_t)next_hop; 9299a2dd95SBruce Richardson next_hop = next_hop >> 16; 9399a2dd95SBruce Richardson next = (uint16_t)next_hop; 9499a2dd95SBruce Richardson 9599a2dd95SBruce Richardson if (unlikely(next_index != next)) { 9699a2dd95SBruce Richardson /* Copy things successfully speculated till now */ 9799a2dd95SBruce Richardson rte_memcpy(to_next, from, last_spec * sizeof(from[0])); 9899a2dd95SBruce Richardson from += last_spec; 9999a2dd95SBruce Richardson to_next += last_spec; 10099a2dd95SBruce Richardson held += last_spec; 10199a2dd95SBruce Richardson last_spec = 0; 10299a2dd95SBruce Richardson 10399a2dd95SBruce Richardson rte_node_enqueue_x1(graph, node, next, from[0]); 10499a2dd95SBruce Richardson from += 1; 10599a2dd95SBruce Richardson } else { 10699a2dd95SBruce Richardson last_spec += 1; 10799a2dd95SBruce Richardson } 10899a2dd95SBruce Richardson } 10999a2dd95SBruce Richardson 11099a2dd95SBruce Richardson /* !!! Home run !!! */ 11199a2dd95SBruce Richardson if (likely(last_spec == nb_objs)) { 11299a2dd95SBruce Richardson rte_node_next_stream_move(graph, node, next_index); 11399a2dd95SBruce Richardson return nb_objs; 11499a2dd95SBruce Richardson } 11599a2dd95SBruce Richardson held += last_spec; 11699a2dd95SBruce Richardson rte_memcpy(to_next, from, last_spec * sizeof(from[0])); 11799a2dd95SBruce Richardson rte_node_next_stream_put(graph, node, next_index, held); 11899a2dd95SBruce Richardson 11999a2dd95SBruce Richardson return nb_objs; 12099a2dd95SBruce Richardson } 12199a2dd95SBruce Richardson 12299a2dd95SBruce Richardson int 12399a2dd95SBruce Richardson rte_node_ip4_route_add(uint32_t ip, uint8_t depth, uint16_t next_hop, 12499a2dd95SBruce Richardson enum rte_node_ip4_lookup_next next_node) 12599a2dd95SBruce Richardson { 12699a2dd95SBruce Richardson char abuf[INET6_ADDRSTRLEN]; 12799a2dd95SBruce Richardson struct in_addr in; 12899a2dd95SBruce Richardson uint8_t socket; 12999a2dd95SBruce Richardson uint32_t val; 13099a2dd95SBruce Richardson int ret; 13199a2dd95SBruce Richardson 13299a2dd95SBruce Richardson in.s_addr = htonl(ip); 13399a2dd95SBruce Richardson inet_ntop(AF_INET, &in, abuf, sizeof(abuf)); 13499a2dd95SBruce Richardson /* Embedded next node id into 24 bit next hop */ 13599a2dd95SBruce Richardson val = ((next_node << 16) | next_hop) & ((1ull << 24) - 1); 13699a2dd95SBruce Richardson node_dbg("ip4_lookup", "LPM: Adding route %s / %d nh (0x%x)", abuf, 13799a2dd95SBruce Richardson depth, val); 13899a2dd95SBruce Richardson 13999a2dd95SBruce Richardson for (socket = 0; socket < RTE_MAX_NUMA_NODES; socket++) { 14099a2dd95SBruce Richardson if (!ip4_lookup_nm.lpm_tbl[socket]) 14199a2dd95SBruce Richardson continue; 14299a2dd95SBruce Richardson 14399a2dd95SBruce Richardson ret = rte_lpm_add(ip4_lookup_nm.lpm_tbl[socket], 14499a2dd95SBruce Richardson ip, depth, val); 14599a2dd95SBruce Richardson if (ret < 0) { 14699a2dd95SBruce Richardson node_err("ip4_lookup", 147ae282b06SDavid Marchand "Unable to add entry %s / %d nh (%x) to LPM table on sock %d, rc=%d", 14899a2dd95SBruce Richardson abuf, depth, val, socket, ret); 14999a2dd95SBruce Richardson return ret; 15099a2dd95SBruce Richardson } 15199a2dd95SBruce Richardson } 15299a2dd95SBruce Richardson 15399a2dd95SBruce Richardson return 0; 15499a2dd95SBruce Richardson } 15599a2dd95SBruce Richardson 15699a2dd95SBruce Richardson static int 15799a2dd95SBruce Richardson setup_lpm(struct ip4_lookup_node_main *nm, int socket) 15899a2dd95SBruce Richardson { 15999a2dd95SBruce Richardson struct rte_lpm_config config_ipv4; 16099a2dd95SBruce Richardson char s[RTE_LPM_NAMESIZE]; 16199a2dd95SBruce Richardson 16299a2dd95SBruce Richardson /* One LPM table per socket */ 16399a2dd95SBruce Richardson if (nm->lpm_tbl[socket]) 16499a2dd95SBruce Richardson return 0; 16599a2dd95SBruce Richardson 16699a2dd95SBruce Richardson /* create the LPM table */ 16799a2dd95SBruce Richardson config_ipv4.max_rules = IPV4_L3FWD_LPM_MAX_RULES; 16899a2dd95SBruce Richardson config_ipv4.number_tbl8s = IPV4_L3FWD_LPM_NUMBER_TBL8S; 16999a2dd95SBruce Richardson config_ipv4.flags = 0; 17099a2dd95SBruce Richardson snprintf(s, sizeof(s), "IPV4_L3FWD_LPM_%d", socket); 17199a2dd95SBruce Richardson nm->lpm_tbl[socket] = rte_lpm_create(s, socket, &config_ipv4); 17299a2dd95SBruce Richardson if (nm->lpm_tbl[socket] == NULL) 17399a2dd95SBruce Richardson return -rte_errno; 17499a2dd95SBruce Richardson 17599a2dd95SBruce Richardson return 0; 17699a2dd95SBruce Richardson } 17799a2dd95SBruce Richardson 17899a2dd95SBruce Richardson static int 17999a2dd95SBruce Richardson ip4_lookup_node_init(const struct rte_graph *graph, struct rte_node *node) 18099a2dd95SBruce Richardson { 18199a2dd95SBruce Richardson uint16_t socket, lcore_id; 18299a2dd95SBruce Richardson static uint8_t init_once; 18399a2dd95SBruce Richardson int rc; 18499a2dd95SBruce Richardson 18599a2dd95SBruce Richardson RTE_SET_USED(graph); 18699a2dd95SBruce Richardson RTE_BUILD_BUG_ON(sizeof(struct ip4_lookup_node_ctx) > RTE_NODE_CTX_SZ); 18799a2dd95SBruce Richardson 18899a2dd95SBruce Richardson if (!init_once) { 18999a2dd95SBruce Richardson node_mbuf_priv1_dynfield_offset = rte_mbuf_dynfield_register( 19099a2dd95SBruce Richardson &node_mbuf_priv1_dynfield_desc); 19199a2dd95SBruce Richardson if (node_mbuf_priv1_dynfield_offset < 0) 19299a2dd95SBruce Richardson return -rte_errno; 19399a2dd95SBruce Richardson 19499a2dd95SBruce Richardson /* Setup LPM tables for all sockets */ 19599a2dd95SBruce Richardson RTE_LCORE_FOREACH(lcore_id) 19699a2dd95SBruce Richardson { 19799a2dd95SBruce Richardson socket = rte_lcore_to_socket_id(lcore_id); 19899a2dd95SBruce Richardson rc = setup_lpm(&ip4_lookup_nm, socket); 19999a2dd95SBruce Richardson if (rc) { 20099a2dd95SBruce Richardson node_err("ip4_lookup", 20199a2dd95SBruce Richardson "Failed to setup lpm tbl for sock %u, rc=%d", 20299a2dd95SBruce Richardson socket, rc); 20399a2dd95SBruce Richardson return rc; 20499a2dd95SBruce Richardson } 20599a2dd95SBruce Richardson } 20699a2dd95SBruce Richardson init_once = 1; 20799a2dd95SBruce Richardson } 20899a2dd95SBruce Richardson 20999a2dd95SBruce Richardson /* Update socket's LPM and mbuf dyn priv1 offset in node ctx */ 21099a2dd95SBruce Richardson IP4_LOOKUP_NODE_LPM(node->ctx) = ip4_lookup_nm.lpm_tbl[graph->socket]; 21199a2dd95SBruce Richardson IP4_LOOKUP_NODE_PRIV1_OFF(node->ctx) = node_mbuf_priv1_dynfield_offset; 21299a2dd95SBruce Richardson 21399a2dd95SBruce Richardson #if defined(__ARM_NEON) || defined(RTE_ARCH_X86) 21499a2dd95SBruce Richardson if (rte_vect_get_max_simd_bitwidth() >= RTE_VECT_SIMD_128) 21599a2dd95SBruce Richardson node->process = ip4_lookup_node_process_vec; 21699a2dd95SBruce Richardson #endif 21799a2dd95SBruce Richardson 21899a2dd95SBruce Richardson node_dbg("ip4_lookup", "Initialized ip4_lookup node"); 21999a2dd95SBruce Richardson 22099a2dd95SBruce Richardson return 0; 22199a2dd95SBruce Richardson } 22299a2dd95SBruce Richardson 223*be4c0cb4SPavan Nikhilesh static struct rte_node_xstats ip4_lookup_xstats = { 224*be4c0cb4SPavan Nikhilesh .nb_xstats = 1, 225*be4c0cb4SPavan Nikhilesh .xstat_desc = { 226*be4c0cb4SPavan Nikhilesh [0] = "ip4_lookup_error", 227*be4c0cb4SPavan Nikhilesh }, 228*be4c0cb4SPavan Nikhilesh }; 229*be4c0cb4SPavan Nikhilesh 23099a2dd95SBruce Richardson static struct rte_node_register ip4_lookup_node = { 23199a2dd95SBruce Richardson .process = ip4_lookup_node_process_scalar, 23299a2dd95SBruce Richardson .name = "ip4_lookup", 23399a2dd95SBruce Richardson 23499a2dd95SBruce Richardson .init = ip4_lookup_node_init, 235*be4c0cb4SPavan Nikhilesh .xstats = &ip4_lookup_xstats, 23699a2dd95SBruce Richardson 237d529aa72SRakesh Kudurumalla .nb_edges = RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP + 1, 23899a2dd95SBruce Richardson .next_nodes = { 23958fbbccaSRakesh Kudurumalla [RTE_NODE_IP4_LOOKUP_NEXT_IP4_LOCAL] = "ip4_local", 24099a2dd95SBruce Richardson [RTE_NODE_IP4_LOOKUP_NEXT_REWRITE] = "ip4_rewrite", 24199a2dd95SBruce Richardson [RTE_NODE_IP4_LOOKUP_NEXT_PKT_DROP] = "pkt_drop", 24299a2dd95SBruce Richardson }, 24399a2dd95SBruce Richardson }; 24499a2dd95SBruce Richardson 24599a2dd95SBruce Richardson RTE_NODE_REGISTER(ip4_lookup_node); 246