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