Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #ifndef RTE_EXEC_ENV_WINDOWS
6 : :
7 : : #include <string.h>
8 : : #include <rte_pipeline.h>
9 : : #include <inttypes.h>
10 : : #include <rte_hexdump.h>
11 : : #include "test_table.h"
12 : : #include "test_table_pipeline.h"
13 : :
14 : : #if 0
15 : :
16 : : static rte_pipeline_port_out_action_handler port_action_0x00
17 : : (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg);
18 : : static rte_pipeline_port_out_action_handler port_action_0xFF
19 : : (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg);
20 : : static rte_pipeline_port_out_action_handler port_action_stub
21 : : (struct rte_mbuf **pkts, uint32_t n, uint64_t *pkts_mask, void *arg);
22 : :
23 : :
24 : : rte_pipeline_port_out_action_handler port_action_0x00(struct rte_mbuf **pkts,
25 : : uint32_t n,
26 : : uint64_t *pkts_mask,
27 : : void *arg)
28 : : {
29 : : RTE_SET_USED(pkts);
30 : : RTE_SET_USED(n);
31 : : RTE_SET_USED(arg);
32 : : printf("Port Action 0x00\n");
33 : : *pkts_mask = 0x00;
34 : : return 0;
35 : : }
36 : :
37 : : rte_pipeline_port_out_action_handler port_action_0xFF(struct rte_mbuf **pkts,
38 : : uint32_t n,
39 : : uint64_t *pkts_mask,
40 : : void *arg)
41 : : {
42 : : RTE_SET_USED(pkts);
43 : : RTE_SET_USED(n);
44 : : RTE_SET_USED(arg);
45 : : printf("Port Action 0xFF\n");
46 : : *pkts_mask = 0xFF;
47 : : return 0;
48 : : }
49 : :
50 : : rte_pipeline_port_out_action_handler port_action_stub(struct rte_mbuf **pkts,
51 : : uint32_t n,
52 : : uint64_t *pkts_mask,
53 : : void *arg)
54 : : {
55 : : RTE_SET_USED(pkts);
56 : : RTE_SET_USED(n);
57 : : RTE_SET_USED(pkts_mask);
58 : : RTE_SET_USED(arg);
59 : : printf("Port Action stub\n");
60 : : return 0;
61 : : }
62 : :
63 : : #endif
64 : :
65 : : rte_pipeline_table_action_handler_hit
66 : : table_action_0x00(struct rte_pipeline *p, struct rte_mbuf **pkts,
67 : : uint64_t pkts_mask, struct rte_pipeline_table_entry **entry, void *arg);
68 : :
69 : : rte_pipeline_table_action_handler_hit
70 : : table_action_stub_hit(struct rte_pipeline *p, struct rte_mbuf **pkts,
71 : : uint64_t pkts_mask, struct rte_pipeline_table_entry **entry, void *arg);
72 : :
73 : : static int
74 : : table_action_stub_miss(struct rte_pipeline *p, struct rte_mbuf **pkts,
75 : : uint64_t pkts_mask, struct rte_pipeline_table_entry *entry, void *arg);
76 : :
77 : : rte_pipeline_table_action_handler_hit
78 : 0 : table_action_0x00(__rte_unused struct rte_pipeline *p,
79 : : __rte_unused struct rte_mbuf **pkts,
80 : : uint64_t pkts_mask,
81 : : __rte_unused struct rte_pipeline_table_entry **entry,
82 : : __rte_unused void *arg)
83 : : {
84 : : printf("Table Action, setting pkts_mask to 0x00\n");
85 : : pkts_mask = ~0x00;
86 : 0 : rte_pipeline_ah_packet_drop(p, pkts_mask);
87 : 0 : return 0;
88 : : }
89 : :
90 : : rte_pipeline_table_action_handler_hit
91 : 0 : table_action_stub_hit(__rte_unused struct rte_pipeline *p,
92 : : __rte_unused struct rte_mbuf **pkts,
93 : : uint64_t pkts_mask,
94 : : __rte_unused struct rte_pipeline_table_entry **entry,
95 : : __rte_unused void *arg)
96 : : {
97 : : printf("STUB Table Action Hit - doing nothing\n");
98 : 0 : printf("STUB Table Action Hit - setting mask to 0x%"PRIx64"\n",
99 : : override_hit_mask);
100 : 0 : pkts_mask = (~override_hit_mask) & 0x3;
101 : 0 : rte_pipeline_ah_packet_drop(p, pkts_mask);
102 : 0 : return 0;
103 : : }
104 : :
105 : : static int
106 : 10 : table_action_stub_miss(struct rte_pipeline *p,
107 : : __rte_unused struct rte_mbuf **pkts,
108 : : uint64_t pkts_mask,
109 : : __rte_unused struct rte_pipeline_table_entry *entry,
110 : : __rte_unused void *arg)
111 : : {
112 : 20 : printf("STUB Table Action Miss - setting mask to 0x%"PRIx64"\n",
113 : : override_miss_mask);
114 : 10 : pkts_mask = (~override_miss_mask) & 0x3;
115 : 10 : rte_pipeline_ah_packet_drop(p, pkts_mask);
116 : 10 : return 0;
117 : : }
118 : :
119 : : enum e_test_type {
120 : : e_TEST_STUB = 0,
121 : : e_TEST_LPM,
122 : : e_TEST_LPM6,
123 : : e_TEST_HASH_LRU_8,
124 : : e_TEST_HASH_LRU_16,
125 : : e_TEST_HASH_LRU_32,
126 : : e_TEST_HASH_EXT_8,
127 : : e_TEST_HASH_EXT_16,
128 : : e_TEST_HASH_EXT_32
129 : : };
130 : :
131 : : char pipeline_test_names[][64] = {
132 : : "Stub",
133 : : "LPM",
134 : : "LPMv6",
135 : : "8-bit LRU Hash",
136 : : "16-bit LRU Hash",
137 : : "32-bit LRU Hash",
138 : : "16-bit Ext Hash",
139 : : "8-bit Ext Hash",
140 : : "32-bit Ext Hash",
141 : : ""
142 : : };
143 : :
144 : :
145 : : static int
146 : : cleanup_pipeline(void)
147 : : {
148 : :
149 : 7 : rte_pipeline_free(p);
150 : :
151 : : return 0;
152 : : }
153 : :
154 : :
155 : : static int check_pipeline_invalid_params(void);
156 : :
157 : : static int
158 : 1 : check_pipeline_invalid_params(void)
159 : : {
160 : 1 : struct rte_pipeline_params pipeline_params_1 = {
161 : : .name = NULL,
162 : : .socket_id = 0,
163 : : };
164 : 1 : struct rte_pipeline_params pipeline_params_2 = {
165 : : .name = "PIPELINE",
166 : : .socket_id = -1,
167 : : };
168 : 1 : struct rte_pipeline_params pipeline_params_3 = {
169 : : .name = "PIPELINE",
170 : : .socket_id = 127,
171 : : };
172 : :
173 : 1 : p = rte_pipeline_create(NULL);
174 [ - + ]: 1 : if (p != NULL) {
175 : 0 : fprintf(stderr,
176 : : "%s: configured pipeline with null params\n",
177 : : __func__);
178 : 0 : goto fail;
179 : : }
180 : 1 : p = rte_pipeline_create(&pipeline_params_1);
181 [ - + ]: 1 : if (p != NULL) {
182 : 0 : fprintf(stderr,
183 : : "%s: Configure pipeline with NULL name\n", __func__);
184 : 0 : goto fail;
185 : : }
186 : :
187 : 1 : p = rte_pipeline_create(&pipeline_params_2);
188 [ - + ]: 1 : if (p != NULL) {
189 : 0 : fprintf(stderr,
190 : : "%s: Configure pipeline with invalid socket\n", __func__);
191 : 0 : goto fail;
192 : : }
193 : :
194 [ - + ]: 1 : if (rte_eal_has_hugepages()) {
195 : 0 : p = rte_pipeline_create(&pipeline_params_3);
196 [ # # ]: 0 : if (p != NULL) {
197 : 0 : fprintf(stderr,
198 : : "%s: Configure pipeline with invalid socket\n",
199 : : __func__);
200 : 0 : goto fail;
201 : : }
202 : : }
203 : :
204 : : /* Check pipeline consistency */
205 [ - + ]: 1 : if (!rte_pipeline_check(p)) {
206 : 0 : rte_panic("Pipeline consistency reported as OK\n");
207 : : goto fail;
208 : : }
209 : :
210 : :
211 : : return 0;
212 : : fail:
213 : : return -1;
214 : : }
215 : :
216 : :
217 : : static int
218 : 7 : setup_pipeline(int test_type)
219 : : {
220 : : int ret;
221 : : int i;
222 : 7 : struct rte_pipeline_params pipeline_params = {
223 : : .name = "PIPELINE",
224 : : .socket_id = 0,
225 : : };
226 : :
227 : 7 : fprintf(stderr, "%s: **** Setting up %s test\n",
228 : 7 : __func__, pipeline_test_names[test_type]);
229 : :
230 : : /* Pipeline configuration */
231 : 7 : p = rte_pipeline_create(&pipeline_params);
232 [ - + ]: 7 : if (p == NULL) {
233 : 0 : fprintf(stderr, "%s: Failed to configure pipeline\n",
234 : : __func__);
235 : 0 : goto fail;
236 : : }
237 : :
238 : 7 : ret = rte_pipeline_free(p);
239 [ - + ]: 7 : if (ret != 0) {
240 : 0 : fprintf(stderr, "%s: Failed to free pipeline\n",
241 : : __func__);
242 : 0 : goto fail;
243 : : }
244 : :
245 : : /* Pipeline configuration */
246 : 7 : p = rte_pipeline_create(&pipeline_params);
247 [ + - ]: 7 : if (p == NULL) {
248 : 0 : fprintf(stderr, "%s: Failed to configure pipeline\n",
249 : : __func__);
250 : 0 : goto fail;
251 : : }
252 : :
253 : :
254 : : /* Input port configuration */
255 [ + + ]: 21 : for (i = 0; i < N_PORTS; i++) {
256 : 14 : struct rte_port_ring_reader_params port_ring_params = {
257 : 14 : .ring = rings_rx[i],
258 : : };
259 : :
260 : 14 : struct rte_pipeline_port_in_params port_params = {
261 : : .ops = &rte_port_ring_reader_ops,
262 : : .arg_create = (void *) &port_ring_params,
263 : : .f_action = NULL,
264 : : .burst_size = BURST_SIZE,
265 : : };
266 : :
267 : : /* Put in action for some ports */
268 : : if (i)
269 : : port_params.f_action = NULL;
270 : :
271 : 14 : ret = rte_pipeline_port_in_create(p, &port_params,
272 : : &port_in_id[i]);
273 [ - + ]: 14 : if (ret) {
274 : 0 : rte_panic("Unable to configure input port %d, ret:%d\n",
275 : : i, ret);
276 : : goto fail;
277 : : }
278 : : }
279 : :
280 : : /* output Port configuration */
281 [ + + ]: 21 : for (i = 0; i < N_PORTS; i++) {
282 : 14 : struct rte_port_ring_writer_params port_ring_params = {
283 : 14 : .ring = rings_tx[i],
284 : : .tx_burst_sz = BURST_SIZE,
285 : : };
286 : :
287 : 14 : struct rte_pipeline_port_out_params port_params = {
288 : : .ops = &rte_port_ring_writer_ops,
289 : : .arg_create = (void *) &port_ring_params,
290 : : .f_action = NULL,
291 : : .arg_ah = NULL,
292 : : };
293 : :
294 [ + + ]: 14 : if (i)
295 : 7 : port_params.f_action = port_out_action;
296 : :
297 [ - + ]: 14 : if (rte_pipeline_port_out_create(p, &port_params,
298 : : &port_out_id[i])) {
299 : 0 : rte_panic("Unable to configure output port %d\n", i);
300 : : goto fail;
301 : : }
302 : : }
303 : :
304 : : /* Table configuration */
305 [ + + ]: 21 : for (i = 0; i < N_PORTS; i++) {
306 : 14 : struct rte_pipeline_table_params table_params = {
307 : : .ops = &rte_table_stub_ops,
308 : : .arg_create = NULL,
309 : : .f_action_hit = action_handler_hit,
310 : : .f_action_miss = action_handler_miss,
311 : : .action_data_size = 0,
312 : : };
313 : :
314 [ - + ]: 14 : if (rte_pipeline_table_create(p, &table_params, &table_id[i])) {
315 : 0 : rte_panic("Unable to configure table %u\n", i);
316 : : goto fail;
317 : : }
318 : :
319 [ + + ]: 14 : if (connect_miss_action_to_table)
320 [ - + ]: 4 : if (rte_pipeline_table_create(p, &table_params,
321 : 4 : &table_id[i+2])) {
322 : 0 : rte_panic("Unable to configure table %u\n", i);
323 : : goto fail;
324 : : }
325 : : }
326 : :
327 [ + + ]: 21 : for (i = 0; i < N_PORTS; i++)
328 [ - + ]: 14 : if (rte_pipeline_port_in_connect_to_table(p, port_in_id[i],
329 : : table_id[i])) {
330 : 0 : rte_panic("Unable to connect input port %u to "
331 : : "table %u\n", port_in_id[i], table_id[i]);
332 : : goto fail;
333 : : }
334 : :
335 : : /* Add entries to tables */
336 [ + + ]: 21 : for (i = 0; i < N_PORTS; i++) {
337 : 14 : struct rte_pipeline_table_entry default_entry = {
338 : : .action = (enum rte_pipeline_action)
339 : : table_entry_default_action,
340 : 14 : {.port_id = port_out_id[i^1]},
341 : : };
342 : : struct rte_pipeline_table_entry *default_entry_ptr;
343 : :
344 [ + + ]: 14 : if (connect_miss_action_to_table) {
345 : : printf("Setting first table to output to next table\n");
346 : 4 : default_entry.action = RTE_PIPELINE_ACTION_TABLE;
347 : 4 : default_entry.table_id = table_id[i+2];
348 : : }
349 : :
350 : : /* Add the default action for the table. */
351 : 14 : ret = rte_pipeline_table_default_entry_add(p, table_id[i],
352 : : &default_entry, &default_entry_ptr);
353 [ - + ]: 14 : if (ret < 0) {
354 : 0 : rte_panic("Unable to add default entry to table %u "
355 : : "code %d\n", table_id[i], ret);
356 : : goto fail;
357 : : } else
358 : 14 : printf("Added default entry to table id %d with "
359 : : "action %x\n",
360 : 14 : table_id[i], default_entry.action);
361 : :
362 [ + + ]: 14 : if (connect_miss_action_to_table) {
363 : : /* We create a second table so the first can pass
364 : : traffic into it */
365 : 4 : struct rte_pipeline_table_entry default_entry = {
366 : : .action = RTE_PIPELINE_ACTION_PORT,
367 : 4 : {.port_id = port_out_id[i^1]},
368 : : };
369 : : printf("Setting second table to output to port\n");
370 : :
371 : : /* Add the default action for the table. */
372 : 4 : ret = rte_pipeline_table_default_entry_add(p,
373 : 4 : table_id[i+2],
374 : : &default_entry, &default_entry_ptr);
375 [ - + ]: 4 : if (ret < 0) {
376 : 0 : rte_panic("Unable to add default entry to "
377 : : "table %u code %d\n",
378 : : table_id[i], ret);
379 : : goto fail;
380 : : } else
381 : 4 : printf("Added default entry to table id %d "
382 : : "with action %x\n",
383 : 4 : table_id[i], default_entry.action);
384 : : }
385 : : }
386 : :
387 : : /* Enable input ports */
388 [ + + ]: 21 : for (i = 0; i < N_PORTS ; i++)
389 [ - + ]: 14 : if (rte_pipeline_port_in_enable(p, port_in_id[i]))
390 : 0 : rte_panic("Unable to enable input port %u\n",
391 : : port_in_id[i]);
392 : :
393 : : /* Check pipeline consistency */
394 [ - + ]: 7 : if (rte_pipeline_check(p) < 0) {
395 : 0 : rte_panic("Pipeline consistency check failed\n");
396 : : goto fail;
397 : : } else
398 : : printf("Pipeline Consistency OK!\n");
399 : :
400 : 7 : return 0;
401 : : fail:
402 : :
403 : : return -1;
404 : : }
405 : :
406 : : static int
407 : 7 : test_pipeline_single_filter(int test_type, int expected_count)
408 : : {
409 : : int i;
410 : : int j;
411 : : int ret;
412 : : int tx_count;
413 : :
414 : 7 : fprintf(stderr, "%s: **** Running %s test\n",
415 : 7 : __func__, pipeline_test_names[test_type]);
416 : : /* Run pipeline once */
417 [ + + ]: 21 : for (i = 0; i < N_PORTS; i++)
418 : 14 : rte_pipeline_run(p);
419 : :
420 : :
421 : 7 : ret = rte_pipeline_flush(NULL);
422 [ - + ]: 7 : if (ret != -EINVAL) {
423 : 0 : fprintf(stderr,
424 : : "%s: No pipeline flush error NULL pipeline (%d)\n",
425 : : __func__, ret);
426 : 0 : goto fail;
427 : : }
428 : :
429 : : /*
430 : : * Allocate a few mbufs and manually insert into the rings. */
431 [ + + ]: 21 : for (i = 0; i < N_PORTS; i++)
432 [ + + ]: 42 : for (j = 0; j < N_PORTS; j++) {
433 : : struct rte_mbuf *m;
434 : : uint8_t *key;
435 : : uint32_t *k32;
436 : :
437 : 28 : m = rte_pktmbuf_alloc(pool);
438 [ - + ]: 28 : if (m == NULL) {
439 : 0 : rte_panic("Failed to alloc mbuf from pool\n");
440 : : return -1;
441 : : }
442 : : key = RTE_MBUF_METADATA_UINT8_PTR(m,
443 : : APP_METADATA_OFFSET(32));
444 : :
445 : : k32 = (uint32_t *) key;
446 : 28 : k32[0] = 0xadadadad >> (j % 2);
447 : :
448 : 28 : fprintf(stderr, "%s: Enqueue onto ring %d\n",
449 : : __func__, i);
450 [ - + - - : 56 : rte_ring_enqueue(rings_rx[i], m);
- ]
451 : : }
452 : :
453 : : /* Run pipeline once */
454 [ + + ]: 21 : for (i = 0; i < N_PORTS; i++)
455 : 14 : rte_pipeline_run(p);
456 : :
457 : : /*
458 : : * need to flush the pipeline, as there may be less hits than the burst
459 : : size and they will not have been flushed to the tx rings. */
460 : 7 : rte_pipeline_flush(p);
461 : :
462 : : /*
463 : : * Now we'll see what we got back on the tx rings. We should see whatever
464 : : * packets we had hits on that were destined for the output ports.
465 : : */
466 : : tx_count = 0;
467 : :
468 [ + + ]: 21 : for (i = 0; i < N_PORTS; i++) {
469 : : void *objs[RING_TX_SIZE];
470 : : struct rte_mbuf *mbuf;
471 : :
472 : 14 : ret = rte_ring_sc_dequeue_burst(rings_tx[i], objs, 10, NULL);
473 [ + + ]: 14 : if (ret <= 0)
474 : : printf("Got no objects from ring %d - error code %d\n",
475 : : i, ret);
476 : : else {
477 : : printf("Got %d object(s) from ring %d!\n", ret, i);
478 [ + + ]: 30 : for (j = 0; j < ret; j++) {
479 : 18 : mbuf = objs[j];
480 : 18 : rte_hexdump(stdout, "Object:",
481 : 18 : rte_pktmbuf_mtod(mbuf, char *),
482 : 18 : mbuf->data_len);
483 : 18 : rte_pktmbuf_free(mbuf);
484 : : }
485 : 12 : tx_count += ret;
486 : : }
487 : : }
488 : :
489 [ - + ]: 7 : if (tx_count != expected_count) {
490 : 0 : fprintf(stderr,
491 : : "%s: Unexpected packets out for %s test, expected %d, got %d\n",
492 : : __func__, pipeline_test_names[test_type],
493 : : expected_count, tx_count);
494 : 0 : goto fail;
495 : : }
496 : :
497 : : cleanup_pipeline();
498 : :
499 : 7 : return 0;
500 : : fail:
501 : : return -1;
502 : :
503 : : }
504 : :
505 : : int
506 : 1 : test_table_pipeline(void)
507 : : {
508 : : /* TEST - All packets dropped */
509 : 1 : action_handler_hit = NULL;
510 : 1 : action_handler_miss = NULL;
511 : 1 : table_entry_default_action = RTE_PIPELINE_ACTION_DROP;
512 : 1 : setup_pipeline(e_TEST_STUB);
513 [ + - ]: 1 : if (test_pipeline_single_filter(e_TEST_STUB, 0) < 0)
514 : : return -1;
515 : :
516 : : /* TEST - All packets passed through */
517 : 1 : table_entry_default_action = RTE_PIPELINE_ACTION_PORT;
518 : 1 : setup_pipeline(e_TEST_STUB);
519 [ + - ]: 1 : if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0)
520 : : return -1;
521 : :
522 : : /* TEST - one packet per port */
523 : 1 : action_handler_hit = NULL;
524 : 1 : action_handler_miss = table_action_stub_miss;
525 : 1 : table_entry_default_action = RTE_PIPELINE_ACTION_PORT;
526 : 1 : override_miss_mask = 0x01; /* one packet per port */
527 : 1 : setup_pipeline(e_TEST_STUB);
528 [ + - ]: 1 : if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0)
529 : : return -1;
530 : :
531 : : /* TEST - one packet per port */
532 : 1 : override_miss_mask = 0x02; /*all per port */
533 : 1 : setup_pipeline(e_TEST_STUB);
534 [ + - ]: 1 : if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0)
535 : : return -1;
536 : :
537 : : /* TEST - all packets per port */
538 : 1 : override_miss_mask = 0x03; /*all per port */
539 : 1 : setup_pipeline(e_TEST_STUB);
540 [ + - ]: 1 : if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0)
541 : : return -1;
542 : :
543 : : /*
544 : : * This test will set up two tables in the pipeline. the first table
545 : : * will forward to another table on miss, and the second table will
546 : : * forward to port.
547 : : */
548 : 1 : connect_miss_action_to_table = 1;
549 : 1 : table_entry_default_action = RTE_PIPELINE_ACTION_TABLE;
550 : 1 : action_handler_hit = NULL; /* not for stub, hitmask always zero */
551 : 1 : action_handler_miss = NULL;
552 : 1 : setup_pipeline(e_TEST_STUB);
553 [ + - ]: 1 : if (test_pipeline_single_filter(e_TEST_STUB, 4) < 0)
554 : : return -1;
555 : 1 : connect_miss_action_to_table = 0;
556 : :
557 : : printf("TEST - two tables, hitmask override to 0x01\n");
558 : 1 : connect_miss_action_to_table = 1;
559 : 1 : action_handler_miss = table_action_stub_miss;
560 : 1 : override_miss_mask = 0x01;
561 : 1 : setup_pipeline(e_TEST_STUB);
562 [ + - ]: 1 : if (test_pipeline_single_filter(e_TEST_STUB, 2) < 0)
563 : : return -1;
564 : 1 : connect_miss_action_to_table = 0;
565 : :
566 [ - + ]: 1 : if (check_pipeline_invalid_params()) {
567 : 0 : fprintf(stderr, "%s: Check pipeline invalid params failed.\n",
568 : : __func__);
569 : 0 : return -1;
570 : : }
571 : :
572 : : return 0;
573 : : }
574 : :
575 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
|