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