1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2016 Intel Corporation 3 */ 4 5 #ifndef __L3FWD_EM_SEQUENTIAL_H__ 6 #define __L3FWD_EM_SEQUENTIAL_H__ 7 8 #include <rte_common.h> 9 10 /** 11 * @file 12 * This is an optional implementation of packet classification in Exact-Match 13 * path using sequential packet classification method. 14 * While hash lookup multi seems to provide better performance, it's disabled 15 * by default and can be enabled with NO_HASH_LOOKUP_MULTI global define in 16 * compilation time. 17 */ 18 19 #if defined RTE_ARCH_X86 20 #include "l3fwd_sse.h" 21 #elif defined __ARM_NEON 22 #include "l3fwd_neon.h" 23 #endif 24 25 static __rte_always_inline uint16_t 26 em_get_dst_port(const struct lcore_conf *qconf, struct rte_mbuf *pkt, 27 uint16_t portid) 28 { 29 uint8_t next_hop; 30 struct rte_ipv4_hdr *ipv4_hdr; 31 struct rte_ipv6_hdr *ipv6_hdr; 32 uint32_t tcp_or_udp; 33 uint32_t l3_ptypes; 34 35 tcp_or_udp = pkt->packet_type & (RTE_PTYPE_L4_TCP | RTE_PTYPE_L4_UDP); 36 l3_ptypes = pkt->packet_type & RTE_PTYPE_L3_MASK; 37 38 if (tcp_or_udp && (l3_ptypes == RTE_PTYPE_L3_IPV4)) { 39 40 /* Handle IPv4 headers.*/ 41 ipv4_hdr = rte_pktmbuf_mtod_offset(pkt, struct rte_ipv4_hdr *, 42 sizeof(struct rte_ether_hdr)); 43 44 next_hop = em_get_ipv4_dst_port(ipv4_hdr, portid, 45 qconf->ipv4_lookup_struct); 46 47 if (next_hop >= RTE_MAX_ETHPORTS || 48 (enabled_port_mask & 1 << next_hop) == 0) 49 next_hop = portid; 50 51 return next_hop; 52 53 } else if (tcp_or_udp && (l3_ptypes == RTE_PTYPE_L3_IPV6)) { 54 55 /* Handle IPv6 headers.*/ 56 ipv6_hdr = rte_pktmbuf_mtod_offset(pkt, struct rte_ipv6_hdr *, 57 sizeof(struct rte_ether_hdr)); 58 59 next_hop = em_get_ipv6_dst_port(ipv6_hdr, portid, 60 qconf->ipv6_lookup_struct); 61 62 if (next_hop >= RTE_MAX_ETHPORTS || 63 (enabled_port_mask & 1 << next_hop) == 0) 64 next_hop = portid; 65 66 return next_hop; 67 68 } 69 70 return portid; 71 } 72 73 /* 74 * Buffer optimized handling of packets, invoked 75 * from main_loop. 76 */ 77 static inline void 78 l3fwd_em_send_packets(int nb_rx, struct rte_mbuf **pkts_burst, 79 uint16_t portid, struct lcore_conf *qconf) 80 { 81 int32_t i, j; 82 uint16_t dst_port[MAX_PKT_BURST]; 83 84 if (nb_rx > 0) { 85 rte_prefetch0(rte_pktmbuf_mtod(pkts_burst[0], 86 struct rte_ether_hdr *) + 1); 87 } 88 89 for (i = 1, j = 0; j < nb_rx; i++, j++) { 90 if (i < nb_rx) { 91 rte_prefetch0(rte_pktmbuf_mtod( 92 pkts_burst[i], 93 struct rte_ether_hdr *) + 1); 94 } 95 dst_port[j] = em_get_dst_port(qconf, pkts_burst[j], portid); 96 } 97 98 send_packets_multi(qconf, pkts_burst, dst_port, nb_rx); 99 } 100 101 /* 102 * Buffer optimized handling of events, invoked 103 * from main_loop. 104 */ 105 static inline void 106 l3fwd_em_process_events(int nb_rx, struct rte_event **events, 107 struct lcore_conf *qconf) 108 { 109 int32_t i, j; 110 111 rte_prefetch0(rte_pktmbuf_mtod(events[0]->mbuf, 112 struct rte_ether_hdr *) + 1); 113 114 for (i = 1, j = 0; j < nb_rx; i++, j++) { 115 struct rte_mbuf *mbuf = events[j]->mbuf; 116 117 if (i < nb_rx) { 118 rte_prefetch0(rte_pktmbuf_mtod( 119 events[i]->mbuf, 120 struct rte_ether_hdr *) + 1); 121 } 122 mbuf->port = em_get_dst_port(qconf, mbuf, mbuf->port); 123 process_packet(mbuf, &mbuf->port); 124 } 125 } 126 127 static inline void 128 l3fwd_em_process_event_vector(struct rte_event_vector *vec, 129 struct lcore_conf *qconf) 130 { 131 struct rte_mbuf **mbufs = vec->mbufs; 132 int32_t i, j; 133 134 rte_prefetch0(rte_pktmbuf_mtod(mbufs[0], struct rte_ether_hdr *) + 1); 135 136 if (vec->attr_valid) 137 vec->port = em_get_dst_port(qconf, mbufs[0], mbufs[0]->port); 138 139 for (i = 0, j = 1; i < vec->nb_elem; i++, j++) { 140 if (j < vec->nb_elem) 141 rte_prefetch0(rte_pktmbuf_mtod(mbufs[j], 142 struct rte_ether_hdr *) + 143 1); 144 mbufs[i]->port = 145 em_get_dst_port(qconf, mbufs[i], mbufs[i]->port); 146 process_packet(mbufs[i], &mbufs[i]->port); 147 event_vector_attr_validate(vec, mbufs[i]); 148 } 149 } 150 151 #endif /* __L3FWD_EM_SEQUENTIAL_H__ */ 152