1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2015 Intel Corporation
12 #include <rte_cycles.h>
13 #include <sys/queue.h>
15 #include <rte_byteorder.h>
16 #include <rte_common.h>
17 #include <rte_debug.h>
18 #include <rte_ethdev.h>
20 #include <rte_lcore.h>
21 #include <rte_memory.h>
22 #include <rte_bus_vdev.h>
24 #include <rte_string_fns.h>
25 #include <rte_errno.h>
26 #include <rte_eth_bond.h>
30 #define SLAVE_COUNT (4)
32 #define RXTX_RING_SIZE 1024
33 #define RXTX_QUEUE_COUNT 4
35 #define BONDED_DEV_NAME ("net_bonding_rss")
37 #define SLAVE_DEV_NAME_FMT ("net_null%d")
38 #define SLAVE_RXTX_QUEUE_FMT ("rssconf_slave%d_q%d")
40 #define NUM_MBUFS 8191
41 #define MBUF_SIZE (1600 + RTE_PKTMBUF_HEADROOM)
42 #define MBUF_CACHE_SIZE 250
45 #define INVALID_SOCKET_ID (-1)
46 #define INVALID_PORT_ID (0xFF)
47 #define INVALID_BONDING_MODE (-1)
51 struct rte_eth_dev_info dev_info
;
53 struct rte_eth_rss_conf rss_conf
;
55 struct rte_eth_rss_reta_entry64 reta_conf
[512 / RTE_RETA_GROUP_SIZE
];
58 struct rte_ring
*rxtx_queue
[RXTX_QUEUE_COUNT
];
61 struct link_bonding_rssconf_unittest_params
{
63 struct rte_eth_dev_info bond_dev_info
;
64 struct rte_eth_rss_reta_entry64 bond_reta_conf
[512 / RTE_RETA_GROUP_SIZE
];
65 struct slave_conf slave_ports
[SLAVE_COUNT
];
67 struct rte_mempool
*mbuf_pool
;
70 static struct link_bonding_rssconf_unittest_params test_params
= {
71 .bond_port_id
= INVALID_PORT_ID
,
73 [0 ... SLAVE_COUNT
- 1] = { .port_id
= INVALID_PORT_ID
, .is_slave
= 0}
79 * Default port configuration with RSS turned off
81 static struct rte_eth_conf default_pmd_conf
= {
83 .mq_mode
= ETH_MQ_RX_NONE
,
84 .max_rx_pkt_len
= ETHER_MAX_LEN
,
88 .mq_mode
= ETH_MQ_TX_NONE
,
93 static struct rte_eth_conf rss_pmd_conf
= {
95 .mq_mode
= ETH_MQ_RX_RSS
,
96 .max_rx_pkt_len
= ETHER_MAX_LEN
,
100 .mq_mode
= ETH_MQ_TX_NONE
,
105 .rss_hf
= ETH_RSS_IPV6
,
111 #define FOR_EACH(_i, _item, _array, _size) \
112 for (_i = 0, _item = &_array[0]; _i < _size && (_item = &_array[_i]); _i++)
114 /* Macro for iterating over every port that can be used as a slave
116 * _i variable used as an index in test_params->slave_ports
117 * _slave pointer to &test_params->slave_ports[_idx]
119 #define FOR_EACH_PORT(_i, _port) \
120 FOR_EACH(_i, _port, test_params.slave_ports, \
121 RTE_DIM(test_params.slave_ports))
124 configure_ethdev(uint16_t port_id
, struct rte_eth_conf
*eth_conf
,
129 TEST_ASSERT(rte_eth_dev_configure(port_id
, RXTX_QUEUE_COUNT
,
130 RXTX_QUEUE_COUNT
, eth_conf
) == 0, "Failed to configure device %u",
133 for (rxq
= 0; rxq
< RXTX_QUEUE_COUNT
; rxq
++) {
134 TEST_ASSERT(rte_eth_rx_queue_setup(port_id
, rxq
, RXTX_RING_SIZE
,
135 rte_eth_dev_socket_id(port_id
), NULL
,
136 test_params
.mbuf_pool
) == 0, "Failed to setup rx queue.");
139 for (txq
= 0; txq
< RXTX_QUEUE_COUNT
; txq
++) {
140 TEST_ASSERT(rte_eth_tx_queue_setup(port_id
, txq
, RXTX_RING_SIZE
,
141 rte_eth_dev_socket_id(port_id
), NULL
) == 0,
142 "Failed to setup tx queue.");
146 TEST_ASSERT(rte_eth_dev_start(port_id
) == 0,
147 "Failed to start device (%d).", port_id
);
154 * Remove all slaves from bonding
160 struct slave_conf
*port
;
162 FOR_EACH_PORT(n
, port
) {
163 port
= &test_params
.slave_ports
[n
];
164 if (port
->is_slave
) {
165 TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(
166 test_params
.bond_port_id
, port
->port_id
),
167 "Cannot remove slave %d from bonding", port
->port_id
);
176 remove_slaves_and_stop_bonded_device(void)
178 TEST_ASSERT_SUCCESS(remove_slaves(), "Removing slaves");
179 rte_eth_dev_stop(test_params
.bond_port_id
);
184 * Add all slaves to bonding
190 struct slave_conf
*port
;
192 FOR_EACH_PORT(n
, port
) {
193 port
= &test_params
.slave_ports
[n
];
194 if (!port
->is_slave
) {
195 TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params
.bond_port_id
,
196 port
->port_id
), "Cannot attach slave %d to the bonding",
206 * Set all RETA values in port_id to value
209 reta_set(uint16_t port_id
, uint8_t value
, int reta_size
)
211 struct rte_eth_rss_reta_entry64 reta_conf
[512/RTE_RETA_GROUP_SIZE
];
214 for (i
= 0; i
< reta_size
/ RTE_RETA_GROUP_SIZE
; i
++) {
215 /* select all fields to set */
216 reta_conf
[i
].mask
= ~0LL;
217 for (j
= 0; j
< RTE_RETA_GROUP_SIZE
; j
++)
218 reta_conf
[i
].reta
[j
] = value
;
221 return rte_eth_dev_rss_reta_update(port_id
, reta_conf
, reta_size
);
225 * Check if slaves RETA is synchronized with bonding port. Returns 1 if slave
226 * port is synced with bonding port.
229 reta_check_synced(struct slave_conf
*port
)
233 for (i
= 0; i
< test_params
.bond_dev_info
.reta_size
;
236 int index
= i
/ RTE_RETA_GROUP_SIZE
;
237 int shift
= i
% RTE_RETA_GROUP_SIZE
;
239 if (port
->reta_conf
[index
].reta
[shift
] !=
240 test_params
.bond_reta_conf
[index
].reta
[shift
])
249 * Fetch bonding ports RETA
252 bond_reta_fetch(void) {
255 for (j
= 0; j
< test_params
.bond_dev_info
.reta_size
/ RTE_RETA_GROUP_SIZE
;
257 test_params
.bond_reta_conf
[j
].mask
= ~0LL;
259 TEST_ASSERT_SUCCESS(rte_eth_dev_rss_reta_query(test_params
.bond_port_id
,
260 test_params
.bond_reta_conf
, test_params
.bond_dev_info
.reta_size
),
261 "Cannot take bonding ports RSS configuration");
269 slave_reta_fetch(struct slave_conf
*port
) {
272 for (j
= 0; j
< port
->dev_info
.reta_size
/ RTE_RETA_GROUP_SIZE
; j
++)
273 port
->reta_conf
[j
].mask
= ~0LL;
275 TEST_ASSERT_SUCCESS(rte_eth_dev_rss_reta_query(port
->port_id
,
276 port
->reta_conf
, port
->dev_info
.reta_size
),
277 "Cannot take bonding ports RSS configuration");
282 * Remove and add slave to check if slaves configuration is synced with
283 * the bonding ports values after adding new slave.
286 slave_remove_and_add(void)
288 struct slave_conf
*port
= &(test_params
.slave_ports
[0]);
290 /* 1. Remove first slave from bonding */
291 TEST_ASSERT_SUCCESS(rte_eth_bond_slave_remove(test_params
.bond_port_id
,
292 port
->port_id
), "Cannot remove slave #d from bonding");
294 /* 2. Change removed (ex-)slave and bonding configuration to different
297 reta_set(test_params
.bond_port_id
, 1, test_params
.bond_dev_info
.reta_size
);
300 reta_set(port
->port_id
, 2, port
->dev_info
.reta_size
);
301 slave_reta_fetch(port
);
303 TEST_ASSERT(reta_check_synced(port
) == 0,
304 "Removed slave didn't should be synchronized with bonding port");
306 /* 3. Add (ex-)slave and check if configuration changed*/
307 TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params
.bond_port_id
,
308 port
->port_id
), "Cannot add slave");
311 slave_reta_fetch(port
);
313 return reta_check_synced(port
);
317 * Test configuration propagation over slaves.
324 struct slave_conf
*port
;
325 uint8_t bond_rss_key
[40];
326 struct rte_eth_rss_conf bond_rss_conf
;
330 uint64_t default_rss_hf
= 0;
332 rte_eth_dev_info_get(test_params
.bond_port_id
, &test_params
.bond_dev_info
);
335 * Test hash function propagation
337 for (i
= 0; i
< sizeof(test_params
.bond_dev_info
.flow_type_rss_offloads
)*8;
340 rss_hf
= test_params
.bond_dev_info
.flow_type_rss_offloads
& (1<<i
);
342 bond_rss_conf
.rss_key
= NULL
;
343 bond_rss_conf
.rss_hf
= rss_hf
;
345 retval
= rte_eth_dev_rss_hash_update(test_params
.bond_port_id
,
347 TEST_ASSERT_SUCCESS(retval
, "Cannot set slaves hash function");
349 FOR_EACH_PORT(n
, port
) {
350 port
= &test_params
.slave_ports
[n
];
352 retval
= rte_eth_dev_rss_hash_conf_get(port
->port_id
,
354 TEST_ASSERT_SUCCESS(retval
,
355 "Cannot take slaves RSS configuration");
357 TEST_ASSERT(port
->rss_conf
.rss_hf
== rss_hf
,
358 "Hash function not propagated for slave %d",
362 default_rss_hf
= rss_hf
;
368 * Test key propagation
370 for (i
= 1; i
< 10; i
++) {
372 /* Set all keys to zero */
373 FOR_EACH_PORT(n
, port
) {
374 port
= &test_params
.slave_ports
[n
];
375 memset(port
->rss_conf
.rss_key
, 0, 40);
376 retval
= rte_eth_dev_rss_hash_update(port
->port_id
,
378 TEST_ASSERT_SUCCESS(retval
, "Cannot set slaves RSS keys");
381 memset(bond_rss_key
, i
, sizeof(bond_rss_key
));
382 bond_rss_conf
.rss_hf
= default_rss_hf
,
383 bond_rss_conf
.rss_key
= bond_rss_key
;
384 bond_rss_conf
.rss_key_len
= 40;
386 retval
= rte_eth_dev_rss_hash_update(test_params
.bond_port_id
,
388 TEST_ASSERT_SUCCESS(retval
, "Cannot set bonded port RSS keys");
390 FOR_EACH_PORT(n
, port
) {
391 port
= &test_params
.slave_ports
[n
];
393 retval
= rte_eth_dev_rss_hash_conf_get(port
->port_id
,
396 TEST_ASSERT_SUCCESS(retval
,
397 "Cannot take slaves RSS configuration");
400 retval
= memcmp(port
->rss_conf
.rss_key
, bond_rss_key
,
401 sizeof(bond_rss_key
));
402 TEST_ASSERT(retval
== 0, "Key value not propagated for slave %d",
408 * Test RETA propagation
410 for (i
= 0; i
< RXTX_QUEUE_COUNT
; i
++) {
412 /* Set all keys to zero */
413 FOR_EACH_PORT(n
, port
) {
414 port
= &test_params
.slave_ports
[n
];
415 retval
= reta_set(port
->port_id
, (i
+ 1) % RXTX_QUEUE_COUNT
,
416 port
->dev_info
.reta_size
);
417 TEST_ASSERT_SUCCESS(retval
, "Cannot set slaves RETA");
420 TEST_ASSERT_SUCCESS(reta_set(test_params
.bond_port_id
,
421 i
% RXTX_QUEUE_COUNT
, test_params
.bond_dev_info
.reta_size
),
422 "Cannot set bonded port RETA");
426 FOR_EACH_PORT(n
, port
) {
427 port
= &test_params
.slave_ports
[n
];
429 slave_reta_fetch(port
);
430 TEST_ASSERT(reta_check_synced(port
) == 1, "RETAs inconsistent");
438 * Test propagation logic, when RX_RSS mq_mode is turned on for bonding port
444 * Configure bonding port in RSS mq mode
446 TEST_ASSERT_SUCCESS(configure_ethdev(test_params
.bond_port_id
,
447 &rss_pmd_conf
, 0), "Failed to configure bonding device\n");
449 rte_eth_dev_info_get(test_params
.bond_port_id
, &test_params
.bond_dev_info
);
451 TEST_ASSERT_SUCCESS(bond_slaves(), "Bonding slaves failed");
453 TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params
.bond_port_id
),
454 "Failed to start bonding port (%d).", test_params
.bond_port_id
);
456 TEST_ASSERT_SUCCESS(test_propagate(), "Propagation test failed");
458 TEST_ASSERT(slave_remove_and_add() == 1, "New slave should be synced");
460 remove_slaves_and_stop_bonded_device();
466 * Test propagation logic, when RX_RSS mq_mode is turned off for bonding port
471 TEST_ASSERT_SUCCESS(configure_ethdev(test_params
.bond_port_id
,
472 &default_pmd_conf
, 0), "Failed to configure bonding device\n");
474 rte_eth_dev_info_get(test_params
.bond_port_id
, &test_params
.bond_dev_info
);
476 TEST_ASSERT_SUCCESS(bond_slaves(), "Bonding slaves failed");
478 TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params
.bond_port_id
),
479 "Failed to start bonding port (%d).", test_params
.bond_port_id
);
481 TEST_ASSERT_SUCCESS(test_propagate(), "Propagation test failed");
483 TEST_ASSERT(slave_remove_and_add() == 0, "New slave shouldn't be synced");
485 remove_slaves_and_stop_bonded_device();
497 struct slave_conf
*port
;
498 struct ether_addr mac_addr
= { .addr_bytes
= {0} };
500 if (test_params
.mbuf_pool
== NULL
) {
502 test_params
.mbuf_pool
= rte_pktmbuf_pool_create(
503 "RSS_MBUF_POOL", NUM_MBUFS
* SLAVE_COUNT
,
504 MBUF_CACHE_SIZE
, 0, MBUF_SIZE
, rte_socket_id());
506 TEST_ASSERT(test_params
.mbuf_pool
!= NULL
,
507 "rte_pktmbuf_pool_create failed\n");
510 /* Create / initialize ring eth devs. */
511 FOR_EACH_PORT(n
, port
) {
512 port
= &test_params
.slave_ports
[n
];
514 port_id
= rte_eth_dev_count_avail();
515 snprintf(name
, sizeof(name
), SLAVE_DEV_NAME_FMT
, port_id
);
517 retval
= rte_vdev_init(name
, "size=64,copy=0");
518 TEST_ASSERT_SUCCESS(retval
, "Failed to create null device '%s'\n",
521 port
->port_id
= port_id
;
523 port
->rss_conf
.rss_key
= port
->rss_key
;
524 port
->rss_conf
.rss_key_len
= 40;
526 retval
= configure_ethdev(port
->port_id
, &default_pmd_conf
, 0);
527 TEST_ASSERT_SUCCESS(retval
, "Failed to configure virtual ethdev %s\n",
530 /* assign a non-zero MAC */
531 mac_addr
.addr_bytes
[5] = 0x10 + port
->port_id
;
532 rte_eth_dev_default_mac_addr_set(port
->port_id
, &mac_addr
);
534 rte_eth_dev_info_get(port
->port_id
, &port
->dev_info
);
537 if (test_params
.bond_port_id
== INVALID_PORT_ID
) {
538 retval
= rte_eth_bond_create(BONDED_DEV_NAME
, 0, rte_socket_id());
540 TEST_ASSERT(retval
>= 0, "Failed to create bonded ethdev %s",
543 test_params
.bond_port_id
= retval
;
545 TEST_ASSERT_SUCCESS(configure_ethdev(test_params
.bond_port_id
,
546 &default_pmd_conf
, 0), "Failed to configure bonding device\n");
548 rte_eth_dev_info_get(test_params
.bond_port_id
,
549 &test_params
.bond_dev_info
);
556 testsuite_teardown(void)
558 struct slave_conf
*port
;
562 * Any cleanup/reset state is done when particular test is
565 rte_eth_dev_stop(test_params
.bond_port_id
);
567 FOR_EACH_PORT(i
, port
)
568 rte_eth_dev_stop(port
->port_id
);
572 check_environment(void)
578 test_rssconf_executor(int (*test_func
)(void))
582 /* Check if environment is clean. Fail to launch a test if there was
583 * a critical error before that prevented to reset environment. */
584 TEST_ASSERT_SUCCESS(check_environment(),
585 "Refusing to launch test in dirty environment.");
587 RTE_VERIFY(test_func
!= NULL
);
588 test_result
= (*test_func
)();
590 /* If test succeed check if environment wast left in good condition. */
591 if (test_result
== TEST_SUCCESS
)
592 test_result
= check_environment();
594 /* Reset environment in case test failed to do that. */
595 if (test_result
!= TEST_SUCCESS
) {
596 TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(),
597 "Failed to stop bonded device");
604 test_setup_wrapper(void)
606 return test_rssconf_executor(&test_setup
);
610 test_rss_wrapper(void)
612 return test_rssconf_executor(&test_rss
);
616 test_rss_lazy_wrapper(void)
618 return test_rssconf_executor(&test_rss_lazy
);
621 static struct unit_test_suite link_bonding_rssconf_test_suite
= {
622 .suite_name
= "RSS Dynamic Configuration for Bonding Unit Test Suite",
623 .teardown
= testsuite_teardown
,
625 TEST_CASE_NAMED("test_setup", test_setup_wrapper
),
626 TEST_CASE_NAMED("test_rss", test_rss_wrapper
),
627 TEST_CASE_NAMED("test_rss_lazy", test_rss_lazy_wrapper
),
634 test_link_bonding_rssconf(void)
636 return unit_test_suite_runner(&link_bonding_rssconf_test_suite
);
639 REGISTER_TEST_COMMAND(link_bonding_rssconf_autotest
, test_link_bonding_rssconf
);