app/testpmd: add async flow create/destroy operations
[dpdk.git] / app / test / test_link_bonding_rssconf.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2015 Intel Corporation
3  */
4
5 #include <string.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include <inttypes.h>
11 #include <errno.h>
12 #include <rte_cycles.h>
13 #include <sys/queue.h>
14
15 #include <rte_byteorder.h>
16 #include <rte_common.h>
17 #include <rte_debug.h>
18 #include <rte_ethdev.h>
19 #include <rte_log.h>
20 #include <rte_lcore.h>
21 #include <rte_memory.h>
22 #include <rte_bus_vdev.h>
23
24 #include <rte_string_fns.h>
25 #include <rte_errno.h>
26 #include <rte_eth_bond.h>
27
28 #include "test.h"
29
30 #define SLAVE_COUNT (4)
31
32 #define RXTX_RING_SIZE                  1024
33 #define RXTX_QUEUE_COUNT                4
34
35 #define BONDED_DEV_NAME         ("net_bonding_rss")
36
37 #define SLAVE_DEV_NAME_FMT      ("net_null%d")
38 #define SLAVE_RXTX_QUEUE_FMT      ("rssconf_slave%d_q%d")
39
40 #define NUM_MBUFS 8191
41 #define MBUF_SIZE (1600 + RTE_PKTMBUF_HEADROOM)
42 #define MBUF_CACHE_SIZE 250
43 #define BURST_SIZE 32
44
45 #define INVALID_SOCKET_ID       (-1)
46 #define INVALID_PORT_ID         (0xFF)
47 #define INVALID_BONDING_MODE    (-1)
48
49 struct slave_conf {
50         uint16_t port_id;
51         struct rte_eth_dev_info dev_info;
52
53         struct rte_eth_rss_conf rss_conf;
54         uint8_t rss_key[40];
55         struct rte_eth_rss_reta_entry64 reta_conf[512 / RTE_ETH_RETA_GROUP_SIZE];
56
57         uint8_t is_slave;
58         struct rte_ring *rxtx_queue[RXTX_QUEUE_COUNT];
59 };
60
61 struct link_bonding_rssconf_unittest_params {
62         uint8_t bond_port_id;
63         struct rte_eth_dev_info bond_dev_info;
64         struct rte_eth_rss_reta_entry64 bond_reta_conf[512 / RTE_ETH_RETA_GROUP_SIZE];
65         struct slave_conf slave_ports[SLAVE_COUNT];
66
67         struct rte_mempool *mbuf_pool;
68 };
69
70 static struct link_bonding_rssconf_unittest_params test_params  = {
71         .bond_port_id = INVALID_PORT_ID,
72         .slave_ports = {
73                 [0 ... SLAVE_COUNT - 1] = { .port_id = INVALID_PORT_ID, .is_slave = 0}
74         },
75         .mbuf_pool = NULL,
76 };
77
78 /**
79  * Default port configuration with RSS turned off
80  */
81 static struct rte_eth_conf default_pmd_conf = {
82         .rxmode = {
83                 .mq_mode = RTE_ETH_MQ_RX_NONE,
84                 .split_hdr_size = 0,
85         },
86         .txmode = {
87                 .mq_mode = RTE_ETH_MQ_TX_NONE,
88         },
89         .lpbk_mode = 0,
90 };
91
92 static struct rte_eth_conf rss_pmd_conf = {
93         .rxmode = {
94                 .mq_mode = RTE_ETH_MQ_RX_RSS,
95                 .split_hdr_size = 0,
96         },
97         .txmode = {
98                 .mq_mode = RTE_ETH_MQ_TX_NONE,
99         },
100         .rx_adv_conf = {
101                 .rss_conf = {
102                         .rss_key = NULL,
103                         .rss_hf = RTE_ETH_RSS_IPV6,
104                 },
105         },
106         .lpbk_mode = 0,
107 };
108
109 #define FOR_EACH(_i, _item, _array, _size) \
110         for (_i = 0, _item = &_array[0]; _i < _size && (_item = &_array[_i]); _i++)
111
112 /* Macro for iterating over every port that can be used as a slave
113  * in this test.
114  * _i variable used as an index in test_params->slave_ports
115  * _slave pointer to &test_params->slave_ports[_idx]
116  */
117 #define FOR_EACH_PORT(_i, _port) \
118         FOR_EACH(_i, _port, test_params.slave_ports, \
119                 RTE_DIM(test_params.slave_ports))
120
121 static int
122 configure_ethdev(uint16_t port_id, struct rte_eth_conf *eth_conf,
123                  uint8_t start)
124 {
125         int rxq, txq;
126
127         TEST_ASSERT(rte_eth_dev_configure(port_id, RXTX_QUEUE_COUNT,
128                         RXTX_QUEUE_COUNT, eth_conf) == 0, "Failed to configure device %u",
129                         port_id);
130
131         int ret = rte_eth_dev_set_mtu(port_id, 1550);
132         RTE_TEST_ASSERT(ret == 0 || ret == -ENOTSUP,
133                         "rte_eth_dev_set_mtu for port %d failed", port_id);
134
135         for (rxq = 0; rxq < RXTX_QUEUE_COUNT; rxq++) {
136                 TEST_ASSERT(rte_eth_rx_queue_setup(port_id, rxq, RXTX_RING_SIZE,
137                                 rte_eth_dev_socket_id(port_id), NULL,
138                                 test_params.mbuf_pool) == 0, "Failed to setup rx queue.");
139         }
140
141         for (txq = 0; txq < RXTX_QUEUE_COUNT; txq++) {
142                 TEST_ASSERT(rte_eth_tx_queue_setup(port_id, txq, RXTX_RING_SIZE,
143                                 rte_eth_dev_socket_id(port_id), NULL) == 0,
144                                 "Failed to setup tx queue.");
145         }
146
147         if (start) {
148                 TEST_ASSERT(rte_eth_dev_start(port_id) == 0,
149                 "Failed to start device (%d).", port_id);
150         }
151
152         return 0;
153 }
154
155 /**
156  * Remove all slaves from bonding
157  */
158 static int
159 remove_slaves(void)
160 {
161         unsigned n;
162         struct slave_conf *port;
163
164         FOR_EACH_PORT(n, port) {
165                 port = &test_params.slave_ports[n];
166                 if (port->is_slave) {
167                         TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(
168                                         test_params.bond_port_id, port->port_id),
169                                         "Cannot remove slave %d from bonding", port->port_id);
170                         port->is_slave = 0;
171                 }
172         }
173
174         return 0;
175 }
176
177 static int
178 remove_slaves_and_stop_bonded_device(void)
179 {
180         TEST_ASSERT_SUCCESS(remove_slaves(), "Removing slaves");
181         TEST_ASSERT_SUCCESS(rte_eth_dev_stop(test_params.bond_port_id),
182                         "Failed to stop port %u", test_params.bond_port_id);
183         return TEST_SUCCESS;
184 }
185
186 /**
187  * Add all slaves to bonding
188  */
189 static int
190 bond_slaves(void)
191 {
192         unsigned n;
193         struct slave_conf *port;
194
195         FOR_EACH_PORT(n, port) {
196                 port = &test_params.slave_ports[n];
197                 if (!port->is_slave) {
198                         TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bond_port_id,
199                                         port->port_id), "Cannot attach slave %d to the bonding",
200                                         port->port_id);
201                         port->is_slave = 1;
202                 }
203         }
204
205         return 0;
206 }
207
208 /**
209  * Set all RETA values in port_id to value
210  */
211 static int
212 reta_set(uint16_t port_id, uint8_t value, int reta_size)
213 {
214         struct rte_eth_rss_reta_entry64 reta_conf[512/RTE_ETH_RETA_GROUP_SIZE];
215         int i, j;
216
217         for (i = 0; i < reta_size / RTE_ETH_RETA_GROUP_SIZE; i++) {
218                 /* select all fields to set */
219                 reta_conf[i].mask = ~0LL;
220                 for (j = 0; j < RTE_ETH_RETA_GROUP_SIZE; j++)
221                         reta_conf[i].reta[j] = value;
222         }
223
224         return rte_eth_dev_rss_reta_update(port_id, reta_conf, reta_size);
225 }
226
227 /**
228  * Check if slaves RETA is synchronized with bonding port. Returns 1 if slave
229  * port is synced with bonding port.
230  */
231 static int
232 reta_check_synced(struct slave_conf *port)
233 {
234         unsigned i;
235
236         for (i = 0; i < test_params.bond_dev_info.reta_size;
237                         i++) {
238
239                 int index = i / RTE_ETH_RETA_GROUP_SIZE;
240                 int shift = i % RTE_ETH_RETA_GROUP_SIZE;
241
242                 if (port->reta_conf[index].reta[shift] !=
243                                 test_params.bond_reta_conf[index].reta[shift])
244                         return 0;
245
246         }
247
248         return 1;
249 }
250
251 /**
252  * Fetch bonding ports RETA
253  */
254 static int
255 bond_reta_fetch(void) {
256         unsigned j;
257
258         for (j = 0; j < test_params.bond_dev_info.reta_size / RTE_ETH_RETA_GROUP_SIZE;
259                         j++)
260                 test_params.bond_reta_conf[j].mask = ~0LL;
261
262         TEST_ASSERT_SUCCESS(rte_eth_dev_rss_reta_query(test_params.bond_port_id,
263                         test_params.bond_reta_conf, test_params.bond_dev_info.reta_size),
264                         "Cannot take bonding ports RSS configuration");
265         return 0;
266 }
267
268 /**
269  * Fetch slaves RETA
270  */
271 static int
272 slave_reta_fetch(struct slave_conf *port) {
273         unsigned j;
274
275         for (j = 0; j < port->dev_info.reta_size / RTE_ETH_RETA_GROUP_SIZE; j++)
276                 port->reta_conf[j].mask = ~0LL;
277
278         TEST_ASSERT_SUCCESS(rte_eth_dev_rss_reta_query(port->port_id,
279                         port->reta_conf, port->dev_info.reta_size),
280                         "Cannot take bonding ports RSS configuration");
281         return 0;
282 }
283
284 /**
285  * Remove and add slave to check if slaves configuration is synced with
286  * the bonding ports values after adding new slave.
287  */
288 static int
289 slave_remove_and_add(void)
290 {
291         struct slave_conf *port = &(test_params.slave_ports[0]);
292
293         /* 1. Remove first slave from bonding */
294         TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(test_params.bond_port_id,
295                         port->port_id), "Cannot remove slave #d from bonding");
296
297         /* 2. Change removed (ex-)slave and bonding configuration to different
298          *    values
299          */
300         reta_set(test_params.bond_port_id, 1, test_params.bond_dev_info.reta_size);
301         bond_reta_fetch();
302
303         reta_set(port->port_id, 2, port->dev_info.reta_size);
304         slave_reta_fetch(port);
305
306         TEST_ASSERT(reta_check_synced(port) == 0,
307                         "Removed slave didn't should be synchronized with bonding port");
308
309         /* 3. Add (ex-)slave and check if configuration changed*/
310         TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bond_port_id,
311                         port->port_id), "Cannot add slave");
312
313         bond_reta_fetch();
314         slave_reta_fetch(port);
315
316         return reta_check_synced(port);
317 }
318
319 /**
320  * Test configuration propagation over slaves.
321  */
322 static int
323 test_propagate(void)
324 {
325         unsigned i;
326         uint8_t n;
327         struct slave_conf *port;
328         uint8_t bond_rss_key[40];
329         struct rte_eth_rss_conf bond_rss_conf;
330
331         int retval = 0;
332         uint64_t rss_hf = 0;
333         uint64_t default_rss_hf = 0;
334
335         retval = rte_eth_dev_info_get(test_params.bond_port_id,
336                                                 &test_params.bond_dev_info);
337         TEST_ASSERT((retval == 0),
338                         "Error during getting device (port %u) info: %s\n",
339                         test_params.bond_port_id, strerror(-retval));
340
341         /*
342          *  Test hash function propagation
343          */
344         for (i = 0; i < sizeof(test_params.bond_dev_info.flow_type_rss_offloads)*8;
345                         i++) {
346
347                 rss_hf = test_params.bond_dev_info.flow_type_rss_offloads & (1<<i);
348                 if (rss_hf) {
349                         bond_rss_conf.rss_key = NULL;
350                         bond_rss_conf.rss_hf = rss_hf;
351
352                         retval = rte_eth_dev_rss_hash_update(test_params.bond_port_id,
353                                         &bond_rss_conf);
354                         TEST_ASSERT_SUCCESS(retval, "Cannot set slaves hash function");
355
356                         FOR_EACH_PORT(n, port) {
357                                 port = &test_params.slave_ports[n];
358
359                                 retval = rte_eth_dev_rss_hash_conf_get(port->port_id,
360                                                 &port->rss_conf);
361                                 TEST_ASSERT_SUCCESS(retval,
362                                                 "Cannot take slaves RSS configuration");
363
364                                 TEST_ASSERT(port->rss_conf.rss_hf == rss_hf,
365                                                 "Hash function not propagated for slave %d",
366                                                 port->port_id);
367                         }
368
369                         default_rss_hf = rss_hf;
370                 }
371
372         }
373
374         /*
375          *  Test key propagation
376          */
377         for (i = 1; i < 10; i++) {
378
379                 /* Set all keys to zero */
380                 FOR_EACH_PORT(n, port) {
381                         port = &test_params.slave_ports[n];
382                         memset(port->rss_conf.rss_key, 0, 40);
383                         retval = rte_eth_dev_rss_hash_update(port->port_id,
384                                         &port->rss_conf);
385                         TEST_ASSERT_SUCCESS(retval, "Cannot set slaves RSS keys");
386                 }
387
388                 memset(bond_rss_key, i, sizeof(bond_rss_key));
389                 bond_rss_conf.rss_hf = default_rss_hf,
390                 bond_rss_conf.rss_key = bond_rss_key;
391                 bond_rss_conf.rss_key_len = 40;
392
393                 retval = rte_eth_dev_rss_hash_update(test_params.bond_port_id,
394                                 &bond_rss_conf);
395                 TEST_ASSERT_SUCCESS(retval, "Cannot set bonded port RSS keys");
396
397                 FOR_EACH_PORT(n, port) {
398                         port = &test_params.slave_ports[n];
399
400                         retval = rte_eth_dev_rss_hash_conf_get(port->port_id,
401                                         &(port->rss_conf));
402
403                         TEST_ASSERT_SUCCESS(retval,
404                                         "Cannot take slaves RSS configuration");
405
406                         /* compare keys */
407                         retval = memcmp(port->rss_conf.rss_key, bond_rss_key,
408                                         sizeof(bond_rss_key));
409                         TEST_ASSERT(retval == 0, "Key value not propagated for slave %d",
410                                         port->port_id);
411                 }
412         }
413
414         /*
415          *  Test RETA propagation
416          */
417         for (i = 0; i < RXTX_QUEUE_COUNT; i++) {
418
419                 /* Set all keys to zero */
420                 FOR_EACH_PORT(n, port) {
421                         port = &test_params.slave_ports[n];
422                         retval = reta_set(port->port_id, (i + 1) % RXTX_QUEUE_COUNT,
423                                         port->dev_info.reta_size);
424                         TEST_ASSERT_SUCCESS(retval, "Cannot set slaves RETA");
425                 }
426
427                 TEST_ASSERT_SUCCESS(reta_set(test_params.bond_port_id,
428                                 i % RXTX_QUEUE_COUNT, test_params.bond_dev_info.reta_size),
429                                 "Cannot set bonded port RETA");
430
431                 bond_reta_fetch();
432
433                 FOR_EACH_PORT(n, port) {
434                         port = &test_params.slave_ports[n];
435
436                         slave_reta_fetch(port);
437                         TEST_ASSERT(reta_check_synced(port) == 1, "RETAs inconsistent");
438                 }
439         }
440
441         return TEST_SUCCESS;
442 }
443
444 /**
445  * Test propagation logic, when RX_RSS mq_mode is turned on for bonding port
446  */
447 static int
448 test_rss(void)
449 {
450         /**
451          * Configure bonding port in RSS mq mode
452          */
453         int ret;
454
455         TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bond_port_id,
456                         &rss_pmd_conf, 0), "Failed to configure bonding device\n");
457
458         ret = rte_eth_dev_info_get(test_params.bond_port_id,
459                                         &test_params.bond_dev_info);
460         TEST_ASSERT((ret == 0),
461                         "Error during getting device (port %u) info: %s\n",
462                         test_params.bond_port_id, strerror(-ret));
463
464         TEST_ASSERT_SUCCESS(bond_slaves(), "Bonding slaves failed");
465
466         TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bond_port_id),
467                         "Failed to start bonding port (%d).", test_params.bond_port_id);
468
469         TEST_ASSERT_SUCCESS(test_propagate(), "Propagation test failed");
470
471         TEST_ASSERT(slave_remove_and_add() == 1, "New slave should be synced");
472
473         remove_slaves_and_stop_bonded_device();
474
475         return TEST_SUCCESS;
476 }
477
478 /**
479  * Test propagation logic, when RX_RSS mq_mode is turned off for bonding port
480  */
481 static int
482 test_rss_lazy(void)
483 {
484         int ret;
485
486         TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bond_port_id,
487                         &default_pmd_conf, 0), "Failed to configure bonding device\n");
488
489         ret = rte_eth_dev_info_get(test_params.bond_port_id,
490                                                 &test_params.bond_dev_info);
491         TEST_ASSERT((ret == 0),
492                         "Error during getting device (port %u) info: %s\n",
493                         test_params.bond_port_id, strerror(-ret));
494
495         TEST_ASSERT_SUCCESS(bond_slaves(), "Bonding slaves failed");
496
497         TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bond_port_id),
498                         "Failed to start bonding port (%d).", test_params.bond_port_id);
499
500         TEST_ASSERT_SUCCESS(test_propagate(), "Propagation test failed");
501
502         TEST_ASSERT(slave_remove_and_add() == 0, "New slave shouldn't be synced");
503
504         remove_slaves_and_stop_bonded_device();
505
506         return TEST_SUCCESS;
507 }
508
509 static int
510 test_setup(void)
511 {
512         unsigned n;
513         int retval;
514         int port_id;
515         char name[256];
516         struct slave_conf *port;
517         struct rte_ether_addr mac_addr = { .addr_bytes = {0} };
518
519         if (test_params.mbuf_pool == NULL) {
520
521                 test_params.mbuf_pool = rte_pktmbuf_pool_create(
522                         "RSS_MBUF_POOL", NUM_MBUFS * SLAVE_COUNT,
523                         MBUF_CACHE_SIZE, 0, MBUF_SIZE, rte_socket_id());
524
525                 TEST_ASSERT(test_params.mbuf_pool != NULL,
526                                 "rte_pktmbuf_pool_create failed\n");
527         }
528
529         /* Create / initialize ring eth devs. */
530         FOR_EACH_PORT(n, port) {
531                 port = &test_params.slave_ports[n];
532
533                 port_id = rte_eth_dev_count_avail();
534                 snprintf(name, sizeof(name), SLAVE_DEV_NAME_FMT, port_id);
535
536                 retval = rte_vdev_init(name, "size=64,copy=0");
537                 TEST_ASSERT_SUCCESS(retval, "Failed to create null device '%s'\n",
538                                 name);
539
540                 port->port_id = port_id;
541
542                 port->rss_conf.rss_key = port->rss_key;
543                 port->rss_conf.rss_key_len = 40;
544
545                 retval = configure_ethdev(port->port_id, &default_pmd_conf, 0);
546                 TEST_ASSERT_SUCCESS(retval, "Failed to configure virtual ethdev %s\n",
547                                 name);
548
549                 /* assign a non-zero MAC */
550                 mac_addr.addr_bytes[5] = 0x10 + port->port_id;
551                 rte_eth_dev_default_mac_addr_set(port->port_id, &mac_addr);
552
553                 rte_eth_dev_info_get(port->port_id, &port->dev_info);
554                 retval = rte_eth_dev_info_get(port->port_id, &port->dev_info);
555                 TEST_ASSERT((retval == 0),
556                                 "Error during getting device (port %u) info: %s\n",
557                                 test_params.bond_port_id, strerror(-retval));
558         }
559
560         if (test_params.bond_port_id == INVALID_PORT_ID) {
561                 retval = rte_eth_bond_create(BONDED_DEV_NAME, 0, rte_socket_id());
562
563                 TEST_ASSERT(retval >= 0, "Failed to create bonded ethdev %s",
564                                 BONDED_DEV_NAME);
565
566                 test_params.bond_port_id = retval;
567
568                 TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bond_port_id,
569                                 &default_pmd_conf, 0), "Failed to configure bonding device\n");
570
571                 retval = rte_eth_dev_info_get(test_params.bond_port_id,
572                                                 &test_params.bond_dev_info);
573                 TEST_ASSERT((retval == 0),
574                                 "Error during getting device (port %u) info: %s\n",
575                                 test_params.bond_port_id, strerror(-retval));
576         }
577
578         return TEST_SUCCESS;
579 }
580
581 static void
582 testsuite_teardown(void)
583 {
584         struct slave_conf *port;
585         uint8_t i;
586
587         /* Only stop ports.
588          * Any cleanup/reset state is done when particular test is
589          * started. */
590
591         rte_eth_dev_stop(test_params.bond_port_id);
592
593         FOR_EACH_PORT(i, port)
594                 rte_eth_dev_stop(port->port_id);
595 }
596
597 static int
598 check_environment(void)
599 {
600         return TEST_SUCCESS;
601 }
602
603 static int
604 test_rssconf_executor(int (*test_func)(void))
605 {
606         int test_result;
607
608         /* Check if environment is clean. Fail to launch a test if there was
609          * a critical error before that prevented to reset environment. */
610         TEST_ASSERT_SUCCESS(check_environment(),
611                 "Refusing to launch test in dirty environment.");
612
613         RTE_VERIFY(test_func != NULL);
614         test_result = (*test_func)();
615
616         /* If test succeed check if environment wast left in good condition. */
617         if (test_result == TEST_SUCCESS)
618                 test_result = check_environment();
619
620         /* Reset environment in case test failed to do that. */
621         if (test_result != TEST_SUCCESS) {
622                 TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(),
623                         "Failed to stop bonded device");
624         }
625
626         return test_result;
627 }
628
629 static int
630 test_setup_wrapper(void)
631 {
632         return test_rssconf_executor(&test_setup);
633 }
634
635 static int
636 test_rss_wrapper(void)
637 {
638         return test_rssconf_executor(&test_rss);
639 }
640
641 static int
642 test_rss_lazy_wrapper(void)
643 {
644         return test_rssconf_executor(&test_rss_lazy);
645 }
646
647 static struct unit_test_suite link_bonding_rssconf_test_suite  = {
648         .suite_name = "RSS Dynamic Configuration for Bonding Unit Test Suite",
649         .teardown = testsuite_teardown,
650         .unit_test_cases = {
651                 TEST_CASE_NAMED("test_setup", test_setup_wrapper),
652                 TEST_CASE_NAMED("test_rss", test_rss_wrapper),
653                 TEST_CASE_NAMED("test_rss_lazy", test_rss_lazy_wrapper),
654
655                 TEST_CASES_END()
656         }
657 };
658
659 static int
660 test_link_bonding_rssconf(void)
661 {
662         return unit_test_suite_runner(&link_bonding_rssconf_test_suite);
663 }
664
665 REGISTER_TEST_COMMAND(link_bonding_rssconf_autotest, test_link_bonding_rssconf);