net/hns3: fix mailbox wait time
[dpdk.git] / examples / l3fwd / l3fwd_em.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2016 Intel Corporation
3  */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <stdint.h>
8 #include <inttypes.h>
9 #include <sys/types.h>
10 #include <string.h>
11 #include <sys/queue.h>
12 #include <stdarg.h>
13 #include <errno.h>
14 #include <getopt.h>
15 #include <stdbool.h>
16 #include <netinet/in.h>
17
18 #include <rte_debug.h>
19 #include <rte_ether.h>
20 #include <rte_ethdev.h>
21 #include <rte_cycles.h>
22 #include <rte_mbuf.h>
23 #include <rte_ip.h>
24 #include <rte_tcp.h>
25 #include <rte_udp.h>
26 #include <rte_hash.h>
27
28 #include "l3fwd.h"
29 #include "l3fwd_event.h"
30
31 #if defined(RTE_ARCH_X86) || defined(__ARM_FEATURE_CRC32)
32 #define EM_HASH_CRC 1
33 #endif
34
35 #ifdef EM_HASH_CRC
36 #include <rte_hash_crc.h>
37 #define DEFAULT_HASH_FUNC       rte_hash_crc
38 #else
39 #include <rte_jhash.h>
40 #define DEFAULT_HASH_FUNC       rte_jhash
41 #endif
42
43 #define IPV6_ADDR_LEN 16
44
45 struct ipv4_5tuple {
46         uint32_t ip_dst;
47         uint32_t ip_src;
48         uint16_t port_dst;
49         uint16_t port_src;
50         uint8_t  proto;
51 } __rte_packed;
52
53 union ipv4_5tuple_host {
54         struct {
55                 uint8_t  pad0;
56                 uint8_t  proto;
57                 uint16_t pad1;
58                 uint32_t ip_src;
59                 uint32_t ip_dst;
60                 uint16_t port_src;
61                 uint16_t port_dst;
62         };
63         xmm_t xmm;
64 };
65
66 #define XMM_NUM_IN_IPV6_5TUPLE 3
67
68 struct ipv6_5tuple {
69         uint8_t  ip_dst[IPV6_ADDR_LEN];
70         uint8_t  ip_src[IPV6_ADDR_LEN];
71         uint16_t port_dst;
72         uint16_t port_src;
73         uint8_t  proto;
74 } __rte_packed;
75
76 union ipv6_5tuple_host {
77         struct {
78                 uint16_t pad0;
79                 uint8_t  proto;
80                 uint8_t  pad1;
81                 uint8_t  ip_src[IPV6_ADDR_LEN];
82                 uint8_t  ip_dst[IPV6_ADDR_LEN];
83                 uint16_t port_src;
84                 uint16_t port_dst;
85                 uint64_t reserve;
86         };
87         xmm_t xmm[XMM_NUM_IN_IPV6_5TUPLE];
88 };
89
90
91
92 struct ipv4_l3fwd_em_route {
93         struct ipv4_5tuple key;
94         uint8_t if_out;
95 };
96
97 struct ipv6_l3fwd_em_route {
98         struct ipv6_5tuple key;
99         uint8_t if_out;
100 };
101
102 /* 198.18.0.0/16 are set aside for RFC2544 benchmarking (RFC5735).
103  * Use RFC863 Discard Protocol.
104  */
105 static const struct ipv4_l3fwd_em_route ipv4_l3fwd_em_route_array[] = {
106         {{RTE_IPV4(198, 18, 0, 0), RTE_IPV4(198, 18, 0, 1),  9, 9, IPPROTO_UDP}, 0},
107         {{RTE_IPV4(198, 18, 1, 0), RTE_IPV4(198, 18, 1, 1),  9, 9, IPPROTO_UDP}, 1},
108         {{RTE_IPV4(198, 18, 2, 0), RTE_IPV4(198, 18, 2, 1),  9, 9, IPPROTO_UDP}, 2},
109         {{RTE_IPV4(198, 18, 3, 0), RTE_IPV4(198, 18, 3, 1),  9, 9, IPPROTO_UDP}, 3},
110         {{RTE_IPV4(198, 18, 4, 0), RTE_IPV4(198, 18, 4, 1),  9, 9, IPPROTO_UDP}, 4},
111         {{RTE_IPV4(198, 18, 5, 0), RTE_IPV4(198, 18, 5, 1),  9, 9, IPPROTO_UDP}, 5},
112         {{RTE_IPV4(198, 18, 6, 0), RTE_IPV4(198, 18, 6, 1),  9, 9, IPPROTO_UDP}, 6},
113         {{RTE_IPV4(198, 18, 7, 0), RTE_IPV4(198, 18, 7, 1),  9, 9, IPPROTO_UDP}, 7},
114         {{RTE_IPV4(198, 18, 8, 0), RTE_IPV4(198, 18, 8, 1),  9, 9, IPPROTO_UDP}, 8},
115         {{RTE_IPV4(198, 18, 9, 0), RTE_IPV4(198, 18, 9, 1),  9, 9, IPPROTO_UDP}, 9},
116         {{RTE_IPV4(198, 18, 10, 0), RTE_IPV4(198, 18, 10, 1),  9, 9, IPPROTO_UDP}, 10},
117         {{RTE_IPV4(198, 18, 11, 0), RTE_IPV4(198, 18, 11, 1),  9, 9, IPPROTO_UDP}, 11},
118         {{RTE_IPV4(198, 18, 12, 0), RTE_IPV4(198, 18, 12, 1),  9, 9, IPPROTO_UDP}, 12},
119         {{RTE_IPV4(198, 18, 13, 0), RTE_IPV4(198, 18, 13, 1),  9, 9, IPPROTO_UDP}, 13},
120         {{RTE_IPV4(198, 18, 14, 0), RTE_IPV4(198, 18, 14, 1),  9, 9, IPPROTO_UDP}, 14},
121         {{RTE_IPV4(198, 18, 15, 0), RTE_IPV4(198, 18, 15, 1),  9, 9, IPPROTO_UDP}, 15},
122 };
123
124 /* 2001:0200::/48 is IANA reserved range for IPv6 benchmarking (RFC5180).
125  * Use RFC863 Discard Protocol.
126  */
127 static const struct ipv6_l3fwd_em_route ipv6_l3fwd_em_route_array[] = {
128         {{{32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
129           {32, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 0},
130         {{{32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0},
131           {32, 1, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 1},
132         {{{32, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0},
133           {32, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 2},
134         {{{32, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0},
135           {32, 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 3},
136         {{{32, 1, 2, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0},
137           {32, 1, 2, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 4},
138         {{{32, 1, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0},
139           {32, 1, 2, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 5},
140         {{{32, 1, 2, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0},
141           {32, 1, 2, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 6},
142         {{{32, 1, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0},
143           {32, 1, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 7},
144         {{{32, 1, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0},
145           {32, 1, 2, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 8},
146         {{{32, 1, 2, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0},
147           {32, 1, 2, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 9},
148         {{{32, 1, 2, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0},
149           {32, 1, 2, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 10},
150         {{{32, 1, 2, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0},
151           {32, 1, 2, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 11},
152         {{{32, 1, 2, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0},
153           {32, 1, 2, 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 12},
154         {{{32, 1, 2, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0},
155           {32, 1, 2, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 13},
156         {{{32, 1, 2, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0},
157           {32, 1, 2, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 14},
158         {{{32, 1, 2, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0},
159           {32, 1, 2, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 1}, 9, 9, IPPROTO_UDP}, 15},
160 };
161
162 struct rte_hash *ipv4_l3fwd_em_lookup_struct[NB_SOCKETS];
163 struct rte_hash *ipv6_l3fwd_em_lookup_struct[NB_SOCKETS];
164
165 static inline uint32_t
166 ipv4_hash_crc(const void *data, __rte_unused uint32_t data_len,
167                 uint32_t init_val)
168 {
169         const union ipv4_5tuple_host *k;
170         uint32_t t;
171         const uint32_t *p;
172
173         k = data;
174         t = k->proto;
175         p = (const uint32_t *)&k->port_src;
176
177 #ifdef EM_HASH_CRC
178         init_val = rte_hash_crc_4byte(t, init_val);
179         init_val = rte_hash_crc_4byte(k->ip_src, init_val);
180         init_val = rte_hash_crc_4byte(k->ip_dst, init_val);
181         init_val = rte_hash_crc_4byte(*p, init_val);
182 #else
183         init_val = rte_jhash_1word(t, init_val);
184         init_val = rte_jhash_1word(k->ip_src, init_val);
185         init_val = rte_jhash_1word(k->ip_dst, init_val);
186         init_val = rte_jhash_1word(*p, init_val);
187 #endif
188
189         return init_val;
190 }
191
192 static inline uint32_t
193 ipv6_hash_crc(const void *data, __rte_unused uint32_t data_len,
194                 uint32_t init_val)
195 {
196         const union ipv6_5tuple_host *k;
197         uint32_t t;
198         const uint32_t *p;
199 #ifdef EM_HASH_CRC
200         const uint32_t  *ip_src0, *ip_src1, *ip_src2, *ip_src3;
201         const uint32_t  *ip_dst0, *ip_dst1, *ip_dst2, *ip_dst3;
202 #endif
203
204         k = data;
205         t = k->proto;
206         p = (const uint32_t *)&k->port_src;
207
208 #ifdef EM_HASH_CRC
209         ip_src0 = (const uint32_t *) k->ip_src;
210         ip_src1 = (const uint32_t *)(k->ip_src+4);
211         ip_src2 = (const uint32_t *)(k->ip_src+8);
212         ip_src3 = (const uint32_t *)(k->ip_src+12);
213         ip_dst0 = (const uint32_t *) k->ip_dst;
214         ip_dst1 = (const uint32_t *)(k->ip_dst+4);
215         ip_dst2 = (const uint32_t *)(k->ip_dst+8);
216         ip_dst3 = (const uint32_t *)(k->ip_dst+12);
217         init_val = rte_hash_crc_4byte(t, init_val);
218         init_val = rte_hash_crc_4byte(*ip_src0, init_val);
219         init_val = rte_hash_crc_4byte(*ip_src1, init_val);
220         init_val = rte_hash_crc_4byte(*ip_src2, init_val);
221         init_val = rte_hash_crc_4byte(*ip_src3, init_val);
222         init_val = rte_hash_crc_4byte(*ip_dst0, init_val);
223         init_val = rte_hash_crc_4byte(*ip_dst1, init_val);
224         init_val = rte_hash_crc_4byte(*ip_dst2, init_val);
225         init_val = rte_hash_crc_4byte(*ip_dst3, init_val);
226         init_val = rte_hash_crc_4byte(*p, init_val);
227 #else
228         init_val = rte_jhash_1word(t, init_val);
229         init_val = rte_jhash(k->ip_src,
230                         sizeof(uint8_t) * IPV6_ADDR_LEN, init_val);
231         init_val = rte_jhash(k->ip_dst,
232                         sizeof(uint8_t) * IPV6_ADDR_LEN, init_val);
233         init_val = rte_jhash_1word(*p, init_val);
234 #endif
235         return init_val;
236 }
237
238 #define IPV4_L3FWD_EM_NUM_ROUTES RTE_DIM(ipv4_l3fwd_em_route_array)
239
240 #define IPV6_L3FWD_EM_NUM_ROUTES RTE_DIM(ipv6_l3fwd_em_route_array)
241
242 static uint8_t ipv4_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
243 static uint8_t ipv6_l3fwd_out_if[L3FWD_HASH_ENTRIES] __rte_cache_aligned;
244
245 static rte_xmm_t mask0;
246 static rte_xmm_t mask1;
247 static rte_xmm_t mask2;
248
249 #if defined(__SSE2__)
250 static inline xmm_t
251 em_mask_key(void *key, xmm_t mask)
252 {
253         __m128i data = _mm_loadu_si128((__m128i *)(key));
254
255         return _mm_and_si128(data, mask);
256 }
257 #elif defined(__ARM_NEON)
258 static inline xmm_t
259 em_mask_key(void *key, xmm_t mask)
260 {
261         int32x4_t data = vld1q_s32((int32_t *)key);
262
263         return vandq_s32(data, mask);
264 }
265 #elif defined(__ALTIVEC__)
266 static inline xmm_t
267 em_mask_key(void *key, xmm_t mask)
268 {
269         xmm_t data = vec_ld(0, (xmm_t *)(key));
270
271         return vec_and(data, mask);
272 }
273 #else
274 #error No vector engine (SSE, NEON, ALTIVEC) available, check your toolchain
275 #endif
276
277 /* Performing hash-based lookups. 8< */
278 static inline uint16_t
279 em_get_ipv4_dst_port(void *ipv4_hdr, uint16_t portid, void *lookup_struct)
280 {
281         int ret = 0;
282         union ipv4_5tuple_host key;
283         struct rte_hash *ipv4_l3fwd_lookup_struct =
284                 (struct rte_hash *)lookup_struct;
285
286         ipv4_hdr = (uint8_t *)ipv4_hdr +
287                 offsetof(struct rte_ipv4_hdr, time_to_live);
288
289         /*
290          * Get 5 tuple: dst port, src port, dst IP address,
291          * src IP address and protocol.
292          */
293         key.xmm = em_mask_key(ipv4_hdr, mask0.x);
294
295         /* Find destination port */
296         ret = rte_hash_lookup(ipv4_l3fwd_lookup_struct, (const void *)&key);
297         return (ret < 0) ? portid : ipv4_l3fwd_out_if[ret];
298 }
299 /* >8 End of performing hash-based lookups. */
300
301 static inline uint16_t
302 em_get_ipv6_dst_port(void *ipv6_hdr, uint16_t portid, void *lookup_struct)
303 {
304         int ret = 0;
305         union ipv6_5tuple_host key;
306         struct rte_hash *ipv6_l3fwd_lookup_struct =
307                 (struct rte_hash *)lookup_struct;
308
309         ipv6_hdr = (uint8_t *)ipv6_hdr +
310                 offsetof(struct rte_ipv6_hdr, payload_len);
311         void *data0 = ipv6_hdr;
312         void *data1 = ((uint8_t *)ipv6_hdr) + sizeof(xmm_t);
313         void *data2 = ((uint8_t *)ipv6_hdr) + sizeof(xmm_t) + sizeof(xmm_t);
314
315         /* Get part of 5 tuple: src IP address lower 96 bits and protocol */
316         key.xmm[0] = em_mask_key(data0, mask1.x);
317
318         /*
319          * Get part of 5 tuple: dst IP address lower 96 bits
320          * and src IP address higher 32 bits.
321          */
322 #if defined RTE_ARCH_X86
323         key.xmm[1] = _mm_loadu_si128(data1);
324 #else
325         key.xmm[1] = *(xmm_t *)data1;
326 #endif
327
328         /*
329          * Get part of 5 tuple: dst port and src port
330          * and dst IP address higher 32 bits.
331          */
332         key.xmm[2] = em_mask_key(data2, mask2.x);
333
334         /* Find destination port */
335         ret = rte_hash_lookup(ipv6_l3fwd_lookup_struct, (const void *)&key);
336         return (ret < 0) ? portid : ipv6_l3fwd_out_if[ret];
337 }
338
339 #if defined RTE_ARCH_X86 || defined __ARM_NEON
340 #if defined(NO_HASH_MULTI_LOOKUP)
341 #include "l3fwd_em_sequential.h"
342 #else
343 #include "l3fwd_em_hlm.h"
344 #endif
345 #else
346 #include "l3fwd_em.h"
347 #endif
348
349 static void
350 convert_ipv4_5tuple(struct ipv4_5tuple *key1,
351                 union ipv4_5tuple_host *key2)
352 {
353         key2->ip_dst = rte_cpu_to_be_32(key1->ip_dst);
354         key2->ip_src = rte_cpu_to_be_32(key1->ip_src);
355         key2->port_dst = rte_cpu_to_be_16(key1->port_dst);
356         key2->port_src = rte_cpu_to_be_16(key1->port_src);
357         key2->proto = key1->proto;
358         key2->pad0 = 0;
359         key2->pad1 = 0;
360 }
361
362 static void
363 convert_ipv6_5tuple(struct ipv6_5tuple *key1,
364                 union ipv6_5tuple_host *key2)
365 {
366         uint32_t i;
367
368         for (i = 0; i < 16; i++) {
369                 key2->ip_dst[i] = key1->ip_dst[i];
370                 key2->ip_src[i] = key1->ip_src[i];
371         }
372         key2->port_dst = rte_cpu_to_be_16(key1->port_dst);
373         key2->port_src = rte_cpu_to_be_16(key1->port_src);
374         key2->proto = key1->proto;
375         key2->pad0 = 0;
376         key2->pad1 = 0;
377         key2->reserve = 0;
378 }
379
380 #define BYTE_VALUE_MAX 256
381 #define ALL_32_BITS 0xffffffff
382 #define BIT_8_TO_15 0x0000ff00
383
384 static inline void
385 populate_ipv4_few_flow_into_table(const struct rte_hash *h)
386 {
387         uint32_t i;
388         int32_t ret;
389
390         mask0 = (rte_xmm_t){.u32 = {BIT_8_TO_15, ALL_32_BITS,
391                                 ALL_32_BITS, ALL_32_BITS} };
392
393         for (i = 0; i < IPV4_L3FWD_EM_NUM_ROUTES; i++) {
394                 struct ipv4_l3fwd_em_route  entry;
395                 union ipv4_5tuple_host newkey;
396
397                 entry = ipv4_l3fwd_em_route_array[i];
398                 convert_ipv4_5tuple(&entry.key, &newkey);
399                 ret = rte_hash_add_key(h, (void *) &newkey);
400                 if (ret < 0) {
401                         rte_exit(EXIT_FAILURE, "Unable to add entry %" PRIu32
402                                 " to the l3fwd hash.\n", i);
403                 }
404                 ipv4_l3fwd_out_if[ret] = entry.if_out;
405         }
406         printf("Hash: Adding 0x%" PRIx64 " keys\n",
407                 (uint64_t)IPV4_L3FWD_EM_NUM_ROUTES);
408 }
409
410 #define BIT_16_TO_23 0x00ff0000
411 static inline void
412 populate_ipv6_few_flow_into_table(const struct rte_hash *h)
413 {
414         uint32_t i;
415         int32_t ret;
416
417         mask1 = (rte_xmm_t){.u32 = {BIT_16_TO_23, ALL_32_BITS,
418                                 ALL_32_BITS, ALL_32_BITS} };
419
420         mask2 = (rte_xmm_t){.u32 = {ALL_32_BITS, ALL_32_BITS, 0, 0} };
421
422         for (i = 0; i < IPV6_L3FWD_EM_NUM_ROUTES; i++) {
423                 struct ipv6_l3fwd_em_route entry;
424                 union ipv6_5tuple_host newkey;
425
426                 entry = ipv6_l3fwd_em_route_array[i];
427                 convert_ipv6_5tuple(&entry.key, &newkey);
428                 ret = rte_hash_add_key(h, (void *) &newkey);
429                 if (ret < 0) {
430                         rte_exit(EXIT_FAILURE, "Unable to add entry %" PRIu32
431                                 " to the l3fwd hash.\n", i);
432                 }
433                 ipv6_l3fwd_out_if[ret] = entry.if_out;
434         }
435         printf("Hash: Adding 0x%" PRIx64 "keys\n",
436                 (uint64_t)IPV6_L3FWD_EM_NUM_ROUTES);
437 }
438
439 #define NUMBER_PORT_USED 16
440 static inline void
441 populate_ipv4_many_flow_into_table(const struct rte_hash *h,
442                 unsigned int nr_flow)
443 {
444         unsigned i;
445
446         mask0 = (rte_xmm_t){.u32 = {BIT_8_TO_15, ALL_32_BITS,
447                                 ALL_32_BITS, ALL_32_BITS} };
448
449         for (i = 0; i < nr_flow; i++) {
450                 uint8_t port = i % NUMBER_PORT_USED;
451                 struct ipv4_l3fwd_em_route entry;
452                 union ipv4_5tuple_host newkey;
453
454                 uint8_t a = (uint8_t)((port + 1) % BYTE_VALUE_MAX);
455
456                 /* Create the ipv4 exact match flow */
457                 memset(&entry, 0, sizeof(entry));
458                 entry = ipv4_l3fwd_em_route_array[port];
459                 entry.key.ip_dst = RTE_IPV4(198, 18, port, a);
460                 convert_ipv4_5tuple(&entry.key, &newkey);
461                 int32_t ret = rte_hash_add_key(h, (void *) &newkey);
462
463                 if (ret < 0)
464                         rte_exit(EXIT_FAILURE, "Unable to add entry %u\n", i);
465
466                 ipv4_l3fwd_out_if[ret] = (uint8_t) entry.if_out;
467
468         }
469         printf("Hash: Adding 0x%x keys\n", nr_flow);
470 }
471
472 static inline void
473 populate_ipv6_many_flow_into_table(const struct rte_hash *h,
474                 unsigned int nr_flow)
475 {
476         unsigned i;
477
478         mask1 = (rte_xmm_t){.u32 = {BIT_16_TO_23, ALL_32_BITS,
479                                 ALL_32_BITS, ALL_32_BITS} };
480         mask2 = (rte_xmm_t){.u32 = {ALL_32_BITS, ALL_32_BITS, 0, 0} };
481
482         for (i = 0; i < nr_flow; i++) {
483                 uint8_t port = i % NUMBER_PORT_USED;
484                 struct ipv6_l3fwd_em_route entry;
485                 union ipv6_5tuple_host newkey;
486
487                 /* Create the ipv6 exact match flow */
488                 memset(&entry, 0, sizeof(entry));
489                 entry = ipv6_l3fwd_em_route_array[port];
490                 entry.key.ip_dst[15] = (port + 1) % BYTE_VALUE_MAX;
491                 convert_ipv6_5tuple(&entry.key, &newkey);
492                 int32_t ret = rte_hash_add_key(h, (void *) &newkey);
493
494                 if (ret < 0)
495                         rte_exit(EXIT_FAILURE, "Unable to add entry %u\n", i);
496
497                 ipv6_l3fwd_out_if[ret] = (uint8_t) entry.if_out;
498
499         }
500         printf("Hash: Adding 0x%x keys\n", nr_flow);
501 }
502
503 /* Requirements:
504  * 1. IP packets without extension;
505  * 2. L4 payload should be either TCP or UDP.
506  */
507 int
508 em_check_ptype(int portid)
509 {
510         int i, ret;
511         int ptype_l3_ipv4_ext = 0;
512         int ptype_l3_ipv6_ext = 0;
513         int ptype_l4_tcp = 0;
514         int ptype_l4_udp = 0;
515         uint32_t ptype_mask = RTE_PTYPE_L3_MASK | RTE_PTYPE_L4_MASK;
516
517         ret = rte_eth_dev_get_supported_ptypes(portid, ptype_mask, NULL, 0);
518         if (ret <= 0)
519                 return 0;
520
521         uint32_t ptypes[ret];
522
523         ret = rte_eth_dev_get_supported_ptypes(portid, ptype_mask, ptypes, ret);
524         for (i = 0; i < ret; ++i) {
525                 switch (ptypes[i]) {
526                 case RTE_PTYPE_L3_IPV4_EXT:
527                         ptype_l3_ipv4_ext = 1;
528                         break;
529                 case RTE_PTYPE_L3_IPV6_EXT:
530                         ptype_l3_ipv6_ext = 1;
531                         break;
532                 case RTE_PTYPE_L4_TCP:
533                         ptype_l4_tcp = 1;
534                         break;
535                 case RTE_PTYPE_L4_UDP:
536                         ptype_l4_udp = 1;
537                         break;
538                 }
539         }
540
541         if (ptype_l3_ipv4_ext == 0)
542                 printf("port %d cannot parse RTE_PTYPE_L3_IPV4_EXT\n", portid);
543         if (ptype_l3_ipv6_ext == 0)
544                 printf("port %d cannot parse RTE_PTYPE_L3_IPV6_EXT\n", portid);
545         if (!ptype_l3_ipv4_ext || !ptype_l3_ipv6_ext)
546                 return 0;
547
548         if (ptype_l4_tcp == 0)
549                 printf("port %d cannot parse RTE_PTYPE_L4_TCP\n", portid);
550         if (ptype_l4_udp == 0)
551                 printf("port %d cannot parse RTE_PTYPE_L4_UDP\n", portid);
552         if (ptype_l4_tcp && ptype_l4_udp)
553                 return 1;
554
555         return 0;
556 }
557
558 static inline void
559 em_parse_ptype(struct rte_mbuf *m)
560 {
561         struct rte_ether_hdr *eth_hdr;
562         uint32_t packet_type = RTE_PTYPE_UNKNOWN;
563         uint16_t ether_type;
564         void *l3;
565         int hdr_len;
566         struct rte_ipv4_hdr *ipv4_hdr;
567         struct rte_ipv6_hdr *ipv6_hdr;
568
569         eth_hdr = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
570         ether_type = eth_hdr->ether_type;
571         l3 = (uint8_t *)eth_hdr + sizeof(struct rte_ether_hdr);
572         if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
573                 ipv4_hdr = (struct rte_ipv4_hdr *)l3;
574                 hdr_len = rte_ipv4_hdr_len(ipv4_hdr);
575                 if (hdr_len == sizeof(struct rte_ipv4_hdr)) {
576                         packet_type |= RTE_PTYPE_L3_IPV4;
577                         if (ipv4_hdr->next_proto_id == IPPROTO_TCP)
578                                 packet_type |= RTE_PTYPE_L4_TCP;
579                         else if (ipv4_hdr->next_proto_id == IPPROTO_UDP)
580                                 packet_type |= RTE_PTYPE_L4_UDP;
581                 } else
582                         packet_type |= RTE_PTYPE_L3_IPV4_EXT;
583         } else if (ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV6)) {
584                 ipv6_hdr = (struct rte_ipv6_hdr *)l3;
585                 if (ipv6_hdr->proto == IPPROTO_TCP)
586                         packet_type |= RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_TCP;
587                 else if (ipv6_hdr->proto == IPPROTO_UDP)
588                         packet_type |= RTE_PTYPE_L3_IPV6 | RTE_PTYPE_L4_UDP;
589                 else
590                         packet_type |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
591         }
592
593         m->packet_type = packet_type;
594 }
595
596 uint16_t
597 em_cb_parse_ptype(uint16_t port __rte_unused, uint16_t queue __rte_unused,
598                   struct rte_mbuf *pkts[], uint16_t nb_pkts,
599                   uint16_t max_pkts __rte_unused,
600                   void *user_param __rte_unused)
601 {
602         unsigned i;
603
604         for (i = 0; i < nb_pkts; ++i)
605                 em_parse_ptype(pkts[i]);
606
607         return nb_pkts;
608 }
609
610 /* main processing loop */
611 int
612 em_main_loop(__rte_unused void *dummy)
613 {
614         struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
615         unsigned lcore_id;
616         uint64_t prev_tsc, diff_tsc, cur_tsc;
617         int i, nb_rx;
618         uint8_t queueid;
619         uint16_t portid;
620         struct lcore_conf *qconf;
621         const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) /
622                 US_PER_S * BURST_TX_DRAIN_US;
623
624         lcore_id = rte_lcore_id();
625         qconf = &lcore_conf[lcore_id];
626
627         const uint16_t n_rx_q = qconf->n_rx_queue;
628         const uint16_t n_tx_p = qconf->n_tx_port;
629         if (n_rx_q == 0) {
630                 RTE_LOG(INFO, L3FWD, "lcore %u has nothing to do\n", lcore_id);
631                 return 0;
632         }
633
634         RTE_LOG(INFO, L3FWD, "entering main loop on lcore %u\n", lcore_id);
635
636         for (i = 0; i < n_rx_q; i++) {
637
638                 portid = qconf->rx_queue_list[i].port_id;
639                 queueid = qconf->rx_queue_list[i].queue_id;
640                 RTE_LOG(INFO, L3FWD,
641                         " -- lcoreid=%u portid=%u rxqueueid=%hhu\n",
642                         lcore_id, portid, queueid);
643         }
644
645         cur_tsc = rte_rdtsc();
646         prev_tsc = cur_tsc;
647
648         while (!force_quit) {
649
650                 /*
651                  * TX burst queue drain
652                  */
653                 diff_tsc = cur_tsc - prev_tsc;
654                 if (unlikely(diff_tsc > drain_tsc)) {
655
656                         for (i = 0; i < n_tx_p; ++i) {
657                                 portid = qconf->tx_port_id[i];
658                                 if (qconf->tx_mbufs[portid].len == 0)
659                                         continue;
660                                 send_burst(qconf,
661                                         qconf->tx_mbufs[portid].len,
662                                         portid);
663                                 qconf->tx_mbufs[portid].len = 0;
664                         }
665
666                         prev_tsc = cur_tsc;
667                 }
668
669                 /*
670                  * Read packet from RX queues
671                  */
672                 for (i = 0; i < n_rx_q; ++i) {
673                         portid = qconf->rx_queue_list[i].port_id;
674                         queueid = qconf->rx_queue_list[i].queue_id;
675                         nb_rx = rte_eth_rx_burst(portid, queueid, pkts_burst,
676                                 MAX_PKT_BURST);
677                         if (nb_rx == 0)
678                                 continue;
679
680 #if defined RTE_ARCH_X86 || defined __ARM_NEON
681                         l3fwd_em_send_packets(nb_rx, pkts_burst,
682                                                         portid, qconf);
683 #else
684                         l3fwd_em_no_opt_send_packets(nb_rx, pkts_burst,
685                                                         portid, qconf);
686 #endif
687                 }
688
689                 cur_tsc = rte_rdtsc();
690         }
691
692         return 0;
693 }
694
695 static __rte_always_inline void
696 em_event_loop_single(struct l3fwd_event_resources *evt_rsrc,
697                 const uint8_t flags)
698 {
699         const int event_p_id = l3fwd_get_free_event_port(evt_rsrc);
700         const uint8_t tx_q_id = evt_rsrc->evq.event_q_id[
701                 evt_rsrc->evq.nb_queues - 1];
702         const uint8_t event_d_id = evt_rsrc->event_d_id;
703         struct lcore_conf *lconf;
704         unsigned int lcore_id;
705         struct rte_event ev;
706
707         if (event_p_id < 0)
708                 return;
709
710         lcore_id = rte_lcore_id();
711         lconf = &lcore_conf[lcore_id];
712
713         RTE_LOG(INFO, L3FWD, "entering %s on lcore %u\n", __func__, lcore_id);
714         while (!force_quit) {
715                 if (!rte_event_dequeue_burst(event_d_id, event_p_id, &ev, 1, 0))
716                         continue;
717
718                 struct rte_mbuf *mbuf = ev.mbuf;
719
720 #if defined RTE_ARCH_X86 || defined __ARM_NEON
721                 mbuf->port = em_get_dst_port(lconf, mbuf, mbuf->port);
722                 process_packet(mbuf, &mbuf->port);
723 #else
724                 l3fwd_em_simple_process(mbuf, lconf);
725 #endif
726                 if (mbuf->port == BAD_PORT) {
727                         rte_pktmbuf_free(mbuf);
728                         continue;
729                 }
730
731                 if (flags & L3FWD_EVENT_TX_ENQ) {
732                         ev.queue_id = tx_q_id;
733                         ev.op = RTE_EVENT_OP_FORWARD;
734                         while (rte_event_enqueue_burst(event_d_id, event_p_id,
735                                                 &ev, 1) && !force_quit)
736                                 ;
737                 }
738
739                 if (flags & L3FWD_EVENT_TX_DIRECT) {
740                         rte_event_eth_tx_adapter_txq_set(mbuf, 0);
741                         while (!rte_event_eth_tx_adapter_enqueue(event_d_id,
742                                                 event_p_id, &ev, 1, 0) &&
743                                         !force_quit)
744                                 ;
745                 }
746         }
747 }
748
749 static __rte_always_inline void
750 em_event_loop_burst(struct l3fwd_event_resources *evt_rsrc,
751                 const uint8_t flags)
752 {
753         const int event_p_id = l3fwd_get_free_event_port(evt_rsrc);
754         const uint8_t tx_q_id = evt_rsrc->evq.event_q_id[
755                 evt_rsrc->evq.nb_queues - 1];
756         const uint8_t event_d_id = evt_rsrc->event_d_id;
757         const uint16_t deq_len = evt_rsrc->deq_depth;
758         struct rte_event events[MAX_PKT_BURST];
759         struct lcore_conf *lconf;
760         unsigned int lcore_id;
761         int i, nb_enq, nb_deq;
762
763         if (event_p_id < 0)
764                 return;
765
766         lcore_id = rte_lcore_id();
767
768         lconf = &lcore_conf[lcore_id];
769
770         RTE_LOG(INFO, L3FWD, "entering %s on lcore %u\n", __func__, lcore_id);
771
772         while (!force_quit) {
773                 /* Read events from RX queues */
774                 nb_deq = rte_event_dequeue_burst(event_d_id, event_p_id,
775                                 events, deq_len, 0);
776                 if (nb_deq == 0) {
777                         rte_pause();
778                         continue;
779                 }
780
781 #if defined RTE_ARCH_X86 || defined __ARM_NEON
782                 l3fwd_em_process_events(nb_deq, (struct rte_event **)&events,
783                                         lconf);
784 #else
785                 l3fwd_em_no_opt_process_events(nb_deq,
786                                                (struct rte_event **)&events,
787                                                lconf);
788 #endif
789                 for (i = 0; i < nb_deq; i++) {
790                         if (flags & L3FWD_EVENT_TX_ENQ) {
791                                 events[i].queue_id = tx_q_id;
792                                 events[i].op = RTE_EVENT_OP_FORWARD;
793                         }
794
795                         if (flags & L3FWD_EVENT_TX_DIRECT)
796                                 rte_event_eth_tx_adapter_txq_set(events[i].mbuf,
797                                                                  0);
798                 }
799
800                 if (flags & L3FWD_EVENT_TX_ENQ) {
801                         nb_enq = rte_event_enqueue_burst(event_d_id, event_p_id,
802                                         events, nb_deq);
803                         while (nb_enq < nb_deq && !force_quit)
804                                 nb_enq += rte_event_enqueue_burst(event_d_id,
805                                                 event_p_id, events + nb_enq,
806                                                 nb_deq - nb_enq);
807                 }
808
809                 if (flags & L3FWD_EVENT_TX_DIRECT) {
810                         nb_enq = rte_event_eth_tx_adapter_enqueue(event_d_id,
811                                         event_p_id, events, nb_deq, 0);
812                         while (nb_enq < nb_deq && !force_quit)
813                                 nb_enq += rte_event_eth_tx_adapter_enqueue(
814                                                 event_d_id, event_p_id,
815                                                 events + nb_enq,
816                                                 nb_deq - nb_enq, 0);
817                 }
818         }
819 }
820
821 static __rte_always_inline void
822 em_event_loop(struct l3fwd_event_resources *evt_rsrc,
823                  const uint8_t flags)
824 {
825         if (flags & L3FWD_EVENT_SINGLE)
826                 em_event_loop_single(evt_rsrc, flags);
827         if (flags & L3FWD_EVENT_BURST)
828                 em_event_loop_burst(evt_rsrc, flags);
829 }
830
831 int __rte_noinline
832 em_event_main_loop_tx_d(__rte_unused void *dummy)
833 {
834         struct l3fwd_event_resources *evt_rsrc =
835                                         l3fwd_get_eventdev_rsrc();
836
837         em_event_loop(evt_rsrc, L3FWD_EVENT_TX_DIRECT | L3FWD_EVENT_SINGLE);
838         return 0;
839 }
840
841 int __rte_noinline
842 em_event_main_loop_tx_d_burst(__rte_unused void *dummy)
843 {
844         struct l3fwd_event_resources *evt_rsrc =
845                                         l3fwd_get_eventdev_rsrc();
846
847         em_event_loop(evt_rsrc, L3FWD_EVENT_TX_DIRECT | L3FWD_EVENT_BURST);
848         return 0;
849 }
850
851 int __rte_noinline
852 em_event_main_loop_tx_q(__rte_unused void *dummy)
853 {
854         struct l3fwd_event_resources *evt_rsrc =
855                                         l3fwd_get_eventdev_rsrc();
856
857         em_event_loop(evt_rsrc, L3FWD_EVENT_TX_ENQ | L3FWD_EVENT_SINGLE);
858         return 0;
859 }
860
861 int __rte_noinline
862 em_event_main_loop_tx_q_burst(__rte_unused void *dummy)
863 {
864         struct l3fwd_event_resources *evt_rsrc =
865                                         l3fwd_get_eventdev_rsrc();
866
867         em_event_loop(evt_rsrc, L3FWD_EVENT_TX_ENQ | L3FWD_EVENT_BURST);
868         return 0;
869 }
870
871 /* Same eventdev loop for single and burst of vector */
872 static __rte_always_inline void
873 em_event_loop_vector(struct l3fwd_event_resources *evt_rsrc,
874                      const uint8_t flags)
875 {
876         const int event_p_id = l3fwd_get_free_event_port(evt_rsrc);
877         const uint8_t tx_q_id =
878                 evt_rsrc->evq.event_q_id[evt_rsrc->evq.nb_queues - 1];
879         const uint8_t event_d_id = evt_rsrc->event_d_id;
880         const uint16_t deq_len = evt_rsrc->deq_depth;
881         struct rte_event events[MAX_PKT_BURST];
882         struct lcore_conf *lconf;
883         unsigned int lcore_id;
884         int i, nb_enq, nb_deq;
885
886         if (event_p_id < 0)
887                 return;
888
889         lcore_id = rte_lcore_id();
890         lconf = &lcore_conf[lcore_id];
891
892         RTE_LOG(INFO, L3FWD, "entering %s on lcore %u\n", __func__, lcore_id);
893
894         while (!force_quit) {
895                 /* Read events from RX queues */
896                 nb_deq = rte_event_dequeue_burst(event_d_id, event_p_id, events,
897                                                  deq_len, 0);
898                 if (nb_deq == 0) {
899                         rte_pause();
900                         continue;
901                 }
902
903                 for (i = 0; i < nb_deq; i++) {
904                         if (flags & L3FWD_EVENT_TX_ENQ) {
905                                 events[i].queue_id = tx_q_id;
906                                 events[i].op = RTE_EVENT_OP_FORWARD;
907                         }
908
909 #if defined RTE_ARCH_X86 || defined __ARM_NEON
910                         l3fwd_em_process_event_vector(events[i].vec, lconf);
911 #else
912                         l3fwd_em_no_opt_process_event_vector(events[i].vec,
913                                                              lconf);
914 #endif
915                         if (flags & L3FWD_EVENT_TX_DIRECT)
916                                 event_vector_txq_set(events[i].vec, 0);
917                 }
918
919                 if (flags & L3FWD_EVENT_TX_ENQ) {
920                         nb_enq = rte_event_enqueue_burst(event_d_id, event_p_id,
921                                                          events, nb_deq);
922                         while (nb_enq < nb_deq && !force_quit)
923                                 nb_enq += rte_event_enqueue_burst(
924                                         event_d_id, event_p_id, events + nb_enq,
925                                         nb_deq - nb_enq);
926                 }
927
928                 if (flags & L3FWD_EVENT_TX_DIRECT) {
929                         nb_enq = rte_event_eth_tx_adapter_enqueue(
930                                 event_d_id, event_p_id, events, nb_deq, 0);
931                         while (nb_enq < nb_deq && !force_quit)
932                                 nb_enq += rte_event_eth_tx_adapter_enqueue(
933                                         event_d_id, event_p_id, events + nb_enq,
934                                         nb_deq - nb_enq, 0);
935                 }
936         }
937 }
938
939 int __rte_noinline
940 em_event_main_loop_tx_d_vector(__rte_unused void *dummy)
941 {
942         struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
943
944         em_event_loop_vector(evt_rsrc, L3FWD_EVENT_TX_DIRECT);
945         return 0;
946 }
947
948 int __rte_noinline
949 em_event_main_loop_tx_d_burst_vector(__rte_unused void *dummy)
950 {
951         struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
952
953         em_event_loop_vector(evt_rsrc, L3FWD_EVENT_TX_DIRECT);
954         return 0;
955 }
956
957 int __rte_noinline
958 em_event_main_loop_tx_q_vector(__rte_unused void *dummy)
959 {
960         struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
961
962         em_event_loop_vector(evt_rsrc, L3FWD_EVENT_TX_ENQ);
963         return 0;
964 }
965
966 int __rte_noinline
967 em_event_main_loop_tx_q_burst_vector(__rte_unused void *dummy)
968 {
969         struct l3fwd_event_resources *evt_rsrc = l3fwd_get_eventdev_rsrc();
970
971         em_event_loop_vector(evt_rsrc, L3FWD_EVENT_TX_ENQ);
972         return 0;
973 }
974
975 /* Initialize exact match (hash) parameters. 8< */
976 void
977 setup_hash(const int socketid)
978 {
979         struct rte_hash_parameters ipv4_l3fwd_hash_params = {
980                 .name = NULL,
981                 .entries = L3FWD_HASH_ENTRIES,
982                 .key_len = sizeof(union ipv4_5tuple_host),
983                 .hash_func = ipv4_hash_crc,
984                 .hash_func_init_val = 0,
985         };
986
987         struct rte_hash_parameters ipv6_l3fwd_hash_params = {
988                 .name = NULL,
989                 .entries = L3FWD_HASH_ENTRIES,
990                 .key_len = sizeof(union ipv6_5tuple_host),
991                 .hash_func = ipv6_hash_crc,
992                 .hash_func_init_val = 0,
993         };
994
995         char s[64];
996
997         /* create ipv4 hash */
998         snprintf(s, sizeof(s), "ipv4_l3fwd_hash_%d", socketid);
999         ipv4_l3fwd_hash_params.name = s;
1000         ipv4_l3fwd_hash_params.socket_id = socketid;
1001         ipv4_l3fwd_em_lookup_struct[socketid] =
1002                 rte_hash_create(&ipv4_l3fwd_hash_params);
1003         if (ipv4_l3fwd_em_lookup_struct[socketid] == NULL)
1004                 rte_exit(EXIT_FAILURE,
1005                         "Unable to create the l3fwd hash on socket %d\n",
1006                         socketid);
1007
1008         /* create ipv6 hash */
1009         snprintf(s, sizeof(s), "ipv6_l3fwd_hash_%d", socketid);
1010         ipv6_l3fwd_hash_params.name = s;
1011         ipv6_l3fwd_hash_params.socket_id = socketid;
1012         ipv6_l3fwd_em_lookup_struct[socketid] =
1013                 rte_hash_create(&ipv6_l3fwd_hash_params);
1014         if (ipv6_l3fwd_em_lookup_struct[socketid] == NULL)
1015                 rte_exit(EXIT_FAILURE,
1016                         "Unable to create the l3fwd hash on socket %d\n",
1017                         socketid);
1018
1019         if (hash_entry_number != HASH_ENTRY_NUMBER_DEFAULT) {
1020                 /* For testing hash matching with a large number of flows we
1021                  * generate millions of IP 5-tuples with an incremented dst
1022                  * address to initialize the hash table. */
1023                 if (ipv6 == 0) {
1024                         /* populate the ipv4 hash */
1025                         populate_ipv4_many_flow_into_table(
1026                                 ipv4_l3fwd_em_lookup_struct[socketid],
1027                                 hash_entry_number);
1028                 } else {
1029                         /* populate the ipv6 hash */
1030                         populate_ipv6_many_flow_into_table(
1031                                 ipv6_l3fwd_em_lookup_struct[socketid],
1032                                 hash_entry_number);
1033                 }
1034         } else {
1035                 /*
1036                  * Use data in ipv4/ipv6 l3fwd lookup table
1037                  * directly to initialize the hash table.
1038                  */
1039                 if (ipv6 == 0) {
1040                         /* populate the ipv4 hash */
1041                         populate_ipv4_few_flow_into_table(
1042                                 ipv4_l3fwd_em_lookup_struct[socketid]);
1043                 } else {
1044                         /* populate the ipv6 hash */
1045                         populate_ipv6_few_flow_into_table(
1046                                 ipv6_l3fwd_em_lookup_struct[socketid]);
1047                 }
1048         }
1049 }
1050 /* >8 End of initialization of hash parameters. */
1051
1052 /* Return ipv4/ipv6 em fwd lookup struct. */
1053 void *
1054 em_get_ipv4_l3fwd_lookup_struct(const int socketid)
1055 {
1056         return ipv4_l3fwd_em_lookup_struct[socketid];
1057 }
1058
1059 void *
1060 em_get_ipv6_l3fwd_lookup_struct(const int socketid)
1061 {
1062         return ipv6_l3fwd_em_lookup_struct[socketid];
1063 }