]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*- |
2 | * BSD LICENSE | |
3 | * | |
4 | * Copyright(c) 2010-2014 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 | ||
54 | #include <rte_eth_ring.h> | |
55 | #include <rte_errno.h> | |
56 | #include <rte_eth_bond.h> | |
57 | #include <rte_eth_bond_8023ad.h> | |
58 | ||
59 | #include "packet_burst_generator.h" | |
60 | ||
61 | #include "test.h" | |
62 | ||
63 | #define SLAVE_COUNT (4) | |
64 | ||
65 | #define RX_RING_SIZE 128 | |
66 | #define TX_RING_SIZE 512 | |
67 | ||
68 | #define MBUF_CACHE_SIZE (250) | |
69 | #define BURST_SIZE (32) | |
70 | ||
71 | #define TEST_RX_DESC_MAX (2048) | |
72 | #define TEST_TX_DESC_MAX (2048) | |
73 | #define MAX_PKT_BURST (32) | |
74 | #define DEF_PKT_BURST (16) | |
75 | ||
76 | #define BONDED_DEV_NAME ("unit_test_mode4_bond_dev") | |
77 | ||
78 | #define SLAVE_DEV_NAME_FMT ("unit_test_mode4_slave_%d") | |
79 | #define SLAVE_RX_QUEUE_FMT ("unit_test_mode4_slave_%d_rx") | |
80 | #define SLAVE_TX_QUEUE_FMT ("unit_test_mode4_slave_%d_tx") | |
81 | ||
82 | #define INVALID_SOCKET_ID (-1) | |
83 | #define INVALID_PORT_ID (0xFF) | |
84 | #define INVALID_BONDING_MODE (-1) | |
85 | ||
86 | static const struct ether_addr slave_mac_default = { | |
87 | { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } | |
88 | }; | |
89 | ||
90 | static const struct ether_addr parnter_mac_default = { | |
91 | { 0x22, 0xBB, 0xFF, 0xBB, 0x00, 0x00 } | |
92 | }; | |
93 | ||
94 | static const struct ether_addr parnter_system = { | |
95 | { 0x33, 0xFF, 0xBB, 0xFF, 0x00, 0x00 } | |
96 | }; | |
97 | ||
98 | static const struct ether_addr slow_protocol_mac_addr = { | |
99 | { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 } | |
100 | }; | |
101 | ||
102 | struct slave_conf { | |
103 | struct rte_ring *rx_queue; | |
104 | struct rte_ring *tx_queue; | |
105 | uint8_t port_id; | |
106 | uint8_t bonded : 1; | |
107 | ||
108 | uint8_t lacp_parnter_state; | |
109 | }; | |
110 | ||
111 | struct ether_vlan_hdr { | |
112 | struct ether_hdr pkt_eth_hdr; | |
113 | struct vlan_hdr vlan_hdr; | |
114 | }; | |
115 | ||
116 | struct link_bonding_unittest_params { | |
117 | uint8_t bonded_port_id; | |
118 | struct slave_conf slave_ports[SLAVE_COUNT]; | |
119 | ||
120 | struct rte_mempool *mbuf_pool; | |
121 | }; | |
122 | ||
123 | #define TEST_DEFAULT_SLAVE_COUNT RTE_DIM(test_params.slave_ports) | |
124 | #define TEST_RX_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT | |
125 | #define TEST_TX_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT | |
126 | #define TEST_MARKER_SLAVE_COUT TEST_DEFAULT_SLAVE_COUNT | |
127 | #define TEST_EXPIRED_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT | |
128 | #define TEST_PROMISC_SLAVE_COUNT TEST_DEFAULT_SLAVE_COUNT | |
129 | ||
130 | static struct link_bonding_unittest_params test_params = { | |
131 | .bonded_port_id = INVALID_PORT_ID, | |
132 | .slave_ports = { [0 ... SLAVE_COUNT - 1] = { .port_id = INVALID_PORT_ID} }, | |
133 | ||
134 | .mbuf_pool = NULL, | |
135 | }; | |
136 | ||
137 | static struct rte_eth_conf default_pmd_conf = { | |
138 | .rxmode = { | |
139 | .mq_mode = ETH_MQ_RX_NONE, | |
140 | .max_rx_pkt_len = ETHER_MAX_LEN, | |
141 | .split_hdr_size = 0, | |
142 | .header_split = 0, /**< Header Split disabled */ | |
143 | .hw_ip_checksum = 0, /**< IP checksum offload enabled */ | |
144 | .hw_vlan_filter = 0, /**< VLAN filtering disabled */ | |
145 | .jumbo_frame = 0, /**< Jumbo Frame Support disabled */ | |
11fdf7f2 | 146 | .hw_strip_crc = 1, /**< CRC stripped by hardware */ |
7c673cae FG |
147 | }, |
148 | .txmode = { | |
149 | .mq_mode = ETH_MQ_TX_NONE, | |
150 | }, | |
151 | .lpbk_mode = 0, | |
152 | }; | |
153 | ||
154 | static uint8_t lacpdu_rx_count[RTE_MAX_ETHPORTS] = {0, }; | |
155 | ||
156 | #define FOR_EACH(_i, _item, _array, _size) \ | |
157 | for (_i = 0, _item = &_array[0]; _i < _size && (_item = &_array[_i]); _i++) | |
158 | ||
159 | /* Macro for iterating over every port that can be used as a slave | |
160 | * in this test. | |
161 | * _i variable used as an index in test_params->slave_ports | |
162 | * _slave pointer to &test_params->slave_ports[_idx] | |
163 | */ | |
164 | #define FOR_EACH_PORT(_i, _port) \ | |
165 | FOR_EACH(_i, _port, test_params.slave_ports, \ | |
166 | RTE_DIM(test_params.slave_ports)) | |
167 | ||
168 | /* Macro for iterating over every port that can be used as a slave | |
169 | * in this test and satisfy given condition. | |
170 | * | |
171 | * _i variable used as an index in test_params->slave_ports | |
172 | * _slave pointer to &test_params->slave_ports[_idx] | |
173 | * _condition condition that need to be checked | |
174 | */ | |
175 | #define FOR_EACH_PORT_IF(_i, _port, _condition) FOR_EACH_PORT((_i), (_port)) \ | |
176 | if (!!(_condition)) | |
177 | ||
178 | /* Macro for iterating over every port that is currently a slave of a bonded | |
179 | * device. | |
180 | * _i variable used as an index in test_params->slave_ports | |
181 | * _slave pointer to &test_params->slave_ports[_idx] | |
182 | * */ | |
183 | #define FOR_EACH_SLAVE(_i, _slave) \ | |
184 | FOR_EACH_PORT_IF(_i, _slave, (_slave)->bonded != 0) | |
185 | ||
186 | /* | |
187 | * Returns packets from slaves TX queue. | |
188 | * slave slave port | |
189 | * buffer for packets | |
190 | * size size of buffer | |
191 | * return number of packets or negative error number | |
192 | */ | |
193 | static int | |
194 | slave_get_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size) | |
195 | { | |
11fdf7f2 TL |
196 | return rte_ring_dequeue_burst(slave->tx_queue, (void **)buf, |
197 | size, NULL); | |
7c673cae FG |
198 | } |
199 | ||
200 | /* | |
201 | * Injects given packets into slaves RX queue. | |
202 | * slave slave port | |
203 | * buffer for packets | |
204 | * size number of packets to be injected | |
205 | * return number of queued packets or negative error number | |
206 | */ | |
207 | static int | |
208 | slave_put_pkts(struct slave_conf *slave, struct rte_mbuf **buf, uint16_t size) | |
209 | { | |
11fdf7f2 TL |
210 | return rte_ring_enqueue_burst(slave->rx_queue, (void **)buf, |
211 | size, NULL); | |
7c673cae FG |
212 | } |
213 | ||
214 | static uint16_t | |
215 | bond_rx(struct rte_mbuf **buf, uint16_t size) | |
216 | { | |
217 | return rte_eth_rx_burst(test_params.bonded_port_id, 0, buf, size); | |
218 | } | |
219 | ||
220 | static uint16_t | |
221 | bond_tx(struct rte_mbuf **buf, uint16_t size) | |
222 | { | |
223 | return rte_eth_tx_burst(test_params.bonded_port_id, 0, buf, size); | |
224 | } | |
225 | ||
226 | static void | |
227 | free_pkts(struct rte_mbuf **pkts, uint16_t count) | |
228 | { | |
229 | uint16_t i; | |
230 | ||
231 | for (i = 0; i < count; i++) { | |
232 | if (pkts[i] != NULL) | |
233 | rte_pktmbuf_free(pkts[i]); | |
234 | } | |
235 | } | |
236 | ||
237 | static int | |
238 | configure_ethdev(uint8_t port_id, uint8_t start) | |
239 | { | |
240 | TEST_ASSERT(rte_eth_dev_configure(port_id, 1, 1, &default_pmd_conf) == 0, | |
241 | "Failed to configure device %u", port_id); | |
242 | ||
243 | TEST_ASSERT(rte_eth_rx_queue_setup(port_id, 0, RX_RING_SIZE, | |
244 | rte_eth_dev_socket_id(port_id), NULL, test_params.mbuf_pool) == 0, | |
245 | "Failed to setup rx queue."); | |
246 | ||
247 | TEST_ASSERT(rte_eth_tx_queue_setup(port_id, 0, TX_RING_SIZE, | |
248 | rte_eth_dev_socket_id(port_id), NULL) == 0, | |
249 | "Failed to setup tx queue."); | |
250 | ||
251 | if (start) { | |
252 | TEST_ASSERT(rte_eth_dev_start(port_id) == 0, | |
253 | "Failed to start device (%d).", port_id); | |
254 | } | |
255 | return 0; | |
256 | } | |
257 | ||
258 | static int | |
259 | add_slave(struct slave_conf *slave, uint8_t start) | |
260 | { | |
261 | struct ether_addr addr, addr_check; | |
262 | ||
263 | /* Some sanity check */ | |
264 | RTE_VERIFY(test_params.slave_ports <= slave && | |
265 | slave - test_params.slave_ports < (int)RTE_DIM(test_params.slave_ports)); | |
266 | RTE_VERIFY(slave->bonded == 0); | |
267 | RTE_VERIFY(slave->port_id != INVALID_PORT_ID); | |
268 | ||
269 | ether_addr_copy(&slave_mac_default, &addr); | |
270 | addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id; | |
271 | ||
272 | rte_eth_dev_mac_addr_remove(slave->port_id, &addr); | |
273 | ||
274 | TEST_ASSERT_SUCCESS(rte_eth_dev_mac_addr_add(slave->port_id, &addr, 0), | |
275 | "Failed to set slave MAC address"); | |
276 | ||
277 | TEST_ASSERT_SUCCESS(rte_eth_bond_slave_add(test_params.bonded_port_id, | |
278 | slave->port_id), | |
279 | "Failed to add slave (idx=%u, id=%u) to bonding (id=%u)", | |
280 | (uint8_t)(slave - test_params.slave_ports), slave->port_id, | |
281 | test_params.bonded_port_id); | |
282 | ||
283 | slave->bonded = 1; | |
284 | if (start) { | |
285 | TEST_ASSERT_SUCCESS(rte_eth_dev_start(slave->port_id), | |
286 | "Failed to start slave %u", slave->port_id); | |
287 | } | |
288 | ||
289 | rte_eth_macaddr_get(slave->port_id, &addr_check); | |
290 | TEST_ASSERT_EQUAL(is_same_ether_addr(&addr, &addr_check), 1, | |
291 | "Slave MAC address is not as expected"); | |
292 | ||
293 | RTE_VERIFY(slave->lacp_parnter_state == 0); | |
294 | return 0; | |
295 | } | |
296 | ||
297 | static int | |
298 | remove_slave(struct slave_conf *slave) | |
299 | { | |
300 | ptrdiff_t slave_idx = slave - test_params.slave_ports; | |
301 | ||
302 | RTE_VERIFY(test_params.slave_ports <= slave && | |
303 | slave_idx < (ptrdiff_t)RTE_DIM(test_params.slave_ports)); | |
304 | ||
305 | RTE_VERIFY(slave->bonded == 1); | |
306 | RTE_VERIFY(slave->port_id != INVALID_PORT_ID); | |
307 | ||
308 | TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0, | |
309 | "Slave %u tx queue not empty while removing from bonding.", | |
310 | slave->port_id); | |
311 | ||
312 | TEST_ASSERT_EQUAL(rte_ring_count(slave->rx_queue), 0, | |
313 | "Slave %u tx queue not empty while removing from bonding.", | |
314 | slave->port_id); | |
315 | ||
316 | TEST_ASSERT_EQUAL(rte_eth_bond_slave_remove(test_params.bonded_port_id, | |
317 | slave->port_id), 0, | |
318 | "Failed to remove slave (idx=%u, id=%u) from bonding (id=%u)", | |
319 | (uint8_t)slave_idx, slave->port_id, | |
320 | test_params.bonded_port_id); | |
321 | ||
322 | slave->bonded = 0; | |
323 | slave->lacp_parnter_state = 0; | |
324 | return 0; | |
325 | } | |
326 | ||
327 | static void | |
328 | lacp_recv_cb(uint8_t slave_id, struct rte_mbuf *lacp_pkt) | |
329 | { | |
330 | struct ether_hdr *hdr; | |
331 | struct slow_protocol_frame *slow_hdr; | |
332 | ||
333 | RTE_VERIFY(lacp_pkt != NULL); | |
334 | ||
335 | hdr = rte_pktmbuf_mtod(lacp_pkt, struct ether_hdr *); | |
336 | RTE_VERIFY(hdr->ether_type == rte_cpu_to_be_16(ETHER_TYPE_SLOW)); | |
337 | ||
338 | slow_hdr = rte_pktmbuf_mtod(lacp_pkt, struct slow_protocol_frame *); | |
339 | RTE_VERIFY(slow_hdr->slow_protocol.subtype == SLOW_SUBTYPE_LACP); | |
340 | ||
341 | lacpdu_rx_count[slave_id]++; | |
342 | rte_pktmbuf_free(lacp_pkt); | |
343 | } | |
344 | ||
345 | static int | |
346 | initialize_bonded_device_with_slaves(uint8_t slave_count, uint8_t external_sm) | |
347 | { | |
348 | uint8_t i; | |
349 | ||
350 | RTE_VERIFY(test_params.bonded_port_id != INVALID_PORT_ID); | |
351 | ||
352 | for (i = 0; i < slave_count; i++) { | |
353 | TEST_ASSERT_SUCCESS(add_slave(&test_params.slave_ports[i], 1), | |
354 | "Failed to add port %u to bonded device.\n", | |
355 | test_params.slave_ports[i].port_id); | |
356 | } | |
357 | ||
358 | /* Reset mode 4 configuration */ | |
359 | rte_eth_bond_8023ad_setup(test_params.bonded_port_id, NULL); | |
360 | rte_eth_promiscuous_disable(test_params.bonded_port_id); | |
361 | ||
362 | if (external_sm) { | |
363 | struct rte_eth_bond_8023ad_conf conf; | |
364 | ||
365 | rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf); | |
366 | conf.slowrx_cb = lacp_recv_cb; | |
367 | rte_eth_bond_8023ad_setup(test_params.bonded_port_id, &conf); | |
368 | ||
369 | } | |
370 | ||
371 | TEST_ASSERT_SUCCESS(rte_eth_dev_start(test_params.bonded_port_id), | |
372 | "Failed to start bonded device"); | |
373 | ||
374 | return TEST_SUCCESS; | |
375 | } | |
376 | ||
377 | static int | |
378 | remove_slaves_and_stop_bonded_device(void) | |
379 | { | |
380 | struct slave_conf *slave; | |
381 | int retval; | |
382 | uint8_t slaves[RTE_MAX_ETHPORTS]; | |
383 | uint8_t i; | |
384 | ||
385 | rte_eth_dev_stop(test_params.bonded_port_id); | |
386 | ||
387 | FOR_EACH_SLAVE(i, slave) | |
388 | remove_slave(slave); | |
389 | ||
390 | retval = rte_eth_bond_slaves_get(test_params.bonded_port_id, slaves, | |
391 | RTE_DIM(slaves)); | |
392 | ||
393 | TEST_ASSERT_EQUAL(retval, 0, | |
394 | "Expected bonded device %u have 0 slaves but returned %d.", | |
395 | test_params.bonded_port_id, retval); | |
396 | ||
397 | FOR_EACH_PORT(i, slave) { | |
398 | rte_eth_dev_stop(slave->port_id); | |
399 | ||
400 | TEST_ASSERT(slave->bonded == 0, | |
401 | "Port id=%u is still marked as enslaved.", slave->port_id); | |
402 | } | |
403 | ||
404 | return TEST_SUCCESS; | |
405 | } | |
406 | ||
407 | static int | |
408 | test_setup(void) | |
409 | { | |
410 | int retval, nb_mbuf_per_pool; | |
411 | char name[RTE_ETH_NAME_MAX_LEN]; | |
412 | struct slave_conf *port; | |
413 | const uint8_t socket_id = rte_socket_id(); | |
414 | uint8_t i; | |
415 | ||
416 | if (test_params.mbuf_pool == NULL) { | |
417 | nb_mbuf_per_pool = TEST_RX_DESC_MAX + DEF_PKT_BURST + | |
418 | TEST_TX_DESC_MAX + MAX_PKT_BURST; | |
419 | test_params.mbuf_pool = rte_pktmbuf_pool_create("TEST_MODE4", | |
420 | nb_mbuf_per_pool, MBUF_CACHE_SIZE, 0, | |
421 | RTE_MBUF_DEFAULT_BUF_SIZE, socket_id); | |
422 | ||
423 | TEST_ASSERT(test_params.mbuf_pool != NULL, | |
424 | "rte_mempool_create failed\n"); | |
425 | } | |
426 | ||
427 | /* Create / initialize ring eth devs. */ | |
428 | FOR_EACH_PORT(i, port) { | |
429 | port = &test_params.slave_ports[i]; | |
430 | ||
431 | if (port->rx_queue == NULL) { | |
432 | retval = snprintf(name, RTE_DIM(name), SLAVE_RX_QUEUE_FMT, i); | |
433 | TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long"); | |
434 | port->rx_queue = rte_ring_create(name, RX_RING_SIZE, socket_id, 0); | |
435 | TEST_ASSERT(port->rx_queue != NULL, | |
436 | "Failed to allocate rx ring '%s': %s", name, | |
437 | rte_strerror(rte_errno)); | |
438 | } | |
439 | ||
440 | if (port->tx_queue == NULL) { | |
441 | retval = snprintf(name, RTE_DIM(name), SLAVE_TX_QUEUE_FMT, i); | |
442 | TEST_ASSERT(retval <= (int)RTE_DIM(name) - 1, "Name too long"); | |
443 | port->tx_queue = rte_ring_create(name, TX_RING_SIZE, socket_id, 0); | |
444 | TEST_ASSERT_NOT_NULL(port->tx_queue, | |
445 | "Failed to allocate tx ring '%s': %s", name, | |
446 | rte_strerror(rte_errno)); | |
447 | } | |
448 | ||
449 | if (port->port_id == INVALID_PORT_ID) { | |
450 | retval = snprintf(name, RTE_DIM(name), SLAVE_DEV_NAME_FMT, i); | |
451 | TEST_ASSERT(retval < (int)RTE_DIM(name) - 1, "Name too long"); | |
452 | retval = rte_eth_from_rings(name, &port->rx_queue, 1, | |
453 | &port->tx_queue, 1, socket_id); | |
454 | TEST_ASSERT(retval >= 0, | |
455 | "Failed to create ring ethdev '%s'\n", name); | |
456 | ||
457 | port->port_id = rte_eth_dev_count() - 1; | |
458 | } | |
459 | ||
460 | retval = configure_ethdev(port->port_id, 1); | |
461 | TEST_ASSERT_SUCCESS(retval, "Failed to configure virtual ethdev %s\n", | |
462 | name); | |
463 | } | |
464 | ||
465 | if (test_params.bonded_port_id == INVALID_PORT_ID) { | |
466 | retval = rte_eth_bond_create(BONDED_DEV_NAME, BONDING_MODE_8023AD, | |
467 | socket_id); | |
468 | ||
469 | TEST_ASSERT(retval >= 0, "Failed to create bonded ethdev %s", | |
470 | BONDED_DEV_NAME); | |
471 | ||
472 | test_params.bonded_port_id = retval; | |
473 | TEST_ASSERT_SUCCESS(configure_ethdev(test_params.bonded_port_id, 0), | |
474 | "Failed to configure bonded ethdev %s", BONDED_DEV_NAME); | |
475 | } else if (rte_eth_bond_mode_get(test_params.bonded_port_id) != | |
476 | BONDING_MODE_8023AD) { | |
477 | TEST_ASSERT(rte_eth_bond_mode_set(test_params.bonded_port_id, | |
478 | BONDING_MODE_8023AD) == 0, | |
479 | "Failed to set ethdev %d to mode %d", | |
480 | test_params.bonded_port_id, BONDING_MODE_8023AD); | |
481 | } | |
482 | ||
483 | return 0; | |
484 | } | |
485 | ||
486 | static void | |
487 | testsuite_teardown(void) | |
488 | { | |
489 | struct slave_conf *port; | |
490 | uint8_t i; | |
491 | ||
492 | /* Only stop ports. | |
493 | * Any cleanup/reset state is done when particular test is | |
494 | * started. */ | |
495 | ||
496 | rte_eth_dev_stop(test_params.bonded_port_id); | |
497 | ||
498 | FOR_EACH_PORT(i, port) | |
499 | rte_eth_dev_stop(port->port_id); | |
500 | } | |
501 | ||
502 | /* | |
503 | * Check if given LACP packet. If it is, make make replay packet to force | |
504 | * COLLECTING state. | |
505 | * return 0 when pkt is LACP frame, 1 if it is not slow frame, 2 if it is slow | |
506 | * frame but not LACP | |
507 | */ | |
508 | static int | |
509 | make_lacp_reply(struct slave_conf *slave, struct rte_mbuf *pkt) | |
510 | { | |
511 | struct ether_hdr *hdr; | |
512 | struct slow_protocol_frame *slow_hdr; | |
513 | struct lacpdu *lacp; | |
514 | ||
515 | /* look for LACP */ | |
516 | hdr = rte_pktmbuf_mtod(pkt, struct ether_hdr *); | |
517 | if (hdr->ether_type != rte_cpu_to_be_16(ETHER_TYPE_SLOW)) | |
518 | return 1; | |
519 | ||
520 | slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *); | |
521 | /* ignore packets of other types */ | |
522 | if (slow_hdr->slow_protocol.subtype != SLOW_SUBTYPE_LACP) | |
523 | return 2; | |
524 | ||
525 | slow_hdr = rte_pktmbuf_mtod(pkt, struct slow_protocol_frame *); | |
526 | ||
527 | /* Change source address to partner address */ | |
528 | ether_addr_copy(&parnter_mac_default, &slow_hdr->eth_hdr.s_addr); | |
529 | slow_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id; | |
530 | ||
531 | lacp = (struct lacpdu *) &slow_hdr->slow_protocol; | |
532 | /* Save last received state */ | |
533 | slave->lacp_parnter_state = lacp->actor.state; | |
534 | /* Change it into LACP replay by matching parameters. */ | |
535 | memcpy(&lacp->partner.port_params, &lacp->actor.port_params, | |
536 | sizeof(struct port_params)); | |
537 | ||
538 | lacp->partner.state = lacp->actor.state; | |
539 | ||
540 | ether_addr_copy(&parnter_system, &lacp->actor.port_params.system); | |
541 | lacp->actor.state = STATE_LACP_ACTIVE | | |
542 | STATE_SYNCHRONIZATION | | |
543 | STATE_AGGREGATION | | |
544 | STATE_COLLECTING | | |
545 | STATE_DISTRIBUTING; | |
546 | ||
547 | return 0; | |
548 | } | |
549 | ||
550 | /* | |
551 | * Reads packets from given slave, search for LACP packet and reply them. | |
552 | * | |
553 | * Receives burst of packets from slave. Looks for LACP packet. Drops | |
554 | * all other packets. Prepares response LACP and sends it back. | |
555 | * | |
556 | * return number of LACP received and replied, -1 on error. | |
557 | */ | |
558 | static int | |
559 | bond_handshake_reply(struct slave_conf *slave) | |
560 | { | |
561 | int retval; | |
562 | struct rte_mbuf *rx_buf[MAX_PKT_BURST]; | |
563 | struct rte_mbuf *lacp_tx_buf[MAX_PKT_BURST]; | |
564 | uint16_t lacp_tx_buf_cnt = 0, i; | |
565 | ||
566 | retval = slave_get_pkts(slave, rx_buf, RTE_DIM(rx_buf)); | |
567 | TEST_ASSERT(retval >= 0, "Getting slave %u packets failed.", | |
568 | slave->port_id); | |
569 | ||
570 | for (i = 0; i < (uint16_t)retval; i++) { | |
571 | if (make_lacp_reply(slave, rx_buf[i]) == 0) { | |
572 | /* reply with actor's LACP */ | |
573 | lacp_tx_buf[lacp_tx_buf_cnt++] = rx_buf[i]; | |
574 | } else | |
575 | rte_pktmbuf_free(rx_buf[i]); | |
576 | } | |
577 | ||
578 | if (lacp_tx_buf_cnt == 0) | |
579 | return 0; | |
580 | ||
581 | retval = slave_put_pkts(slave, lacp_tx_buf, lacp_tx_buf_cnt); | |
582 | if (retval <= lacp_tx_buf_cnt) { | |
583 | /* retval might be negative */ | |
584 | for (i = RTE_MAX(0, retval); retval < lacp_tx_buf_cnt; retval++) | |
585 | rte_pktmbuf_free(lacp_tx_buf[i]); | |
586 | } | |
587 | ||
588 | TEST_ASSERT_EQUAL(retval, lacp_tx_buf_cnt, | |
589 | "Failed to equeue lacp packets into slave %u tx queue.", | |
590 | slave->port_id); | |
591 | ||
592 | return lacp_tx_buf_cnt; | |
593 | } | |
594 | ||
595 | /* | |
596 | * Function check if given slave tx queue contains packets that make mode 4 | |
597 | * handshake complete. It will drain slave queue. | |
598 | * return 0 if handshake not completed, 1 if handshake was complete, | |
599 | */ | |
600 | static int | |
601 | bond_handshake_done(struct slave_conf *slave) | |
602 | { | |
603 | const uint8_t expected_state = STATE_LACP_ACTIVE | STATE_SYNCHRONIZATION | | |
604 | STATE_AGGREGATION | STATE_COLLECTING | STATE_DISTRIBUTING; | |
605 | ||
606 | return slave->lacp_parnter_state == expected_state; | |
607 | } | |
608 | ||
609 | static unsigned | |
610 | bond_get_update_timeout_ms(void) | |
611 | { | |
612 | struct rte_eth_bond_8023ad_conf conf; | |
613 | ||
614 | rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf); | |
615 | return conf.update_timeout_ms; | |
616 | } | |
617 | ||
618 | /* | |
619 | * Exchanges LACP packets with partner to achieve dynamic port configuration. | |
620 | * return TEST_SUCCESS if initial handshake succeed, TEST_FAILED otherwise. | |
621 | */ | |
622 | static int | |
623 | bond_handshake(void) | |
624 | { | |
625 | struct slave_conf *slave; | |
626 | struct rte_mbuf *buf[MAX_PKT_BURST]; | |
627 | uint16_t nb_pkts; | |
628 | uint8_t all_slaves_done, i, j; | |
629 | uint8_t status[RTE_DIM(test_params.slave_ports)] = { 0 }; | |
630 | const unsigned delay = bond_get_update_timeout_ms(); | |
631 | ||
632 | /* Exchange LACP frames */ | |
633 | all_slaves_done = 0; | |
634 | for (i = 0; i < 30 && all_slaves_done == 0; ++i) { | |
635 | rte_delay_ms(delay); | |
636 | ||
637 | all_slaves_done = 1; | |
638 | FOR_EACH_SLAVE(j, slave) { | |
639 | /* If response already send, skip slave */ | |
640 | if (status[j] != 0) | |
641 | continue; | |
642 | ||
643 | if (bond_handshake_reply(slave) < 0) { | |
644 | all_slaves_done = 0; | |
645 | break; | |
646 | } | |
647 | ||
648 | status[j] = bond_handshake_done(slave); | |
649 | if (status[j] == 0) | |
650 | all_slaves_done = 0; | |
651 | } | |
652 | ||
653 | nb_pkts = bond_tx(NULL, 0); | |
654 | TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets transmitted unexpectedly"); | |
655 | ||
656 | nb_pkts = bond_rx(buf, RTE_DIM(buf)); | |
657 | free_pkts(buf, nb_pkts); | |
658 | TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets received unexpectedly"); | |
659 | } | |
660 | /* If response didn't send - report failure */ | |
661 | TEST_ASSERT_EQUAL(all_slaves_done, 1, "Bond handshake failed\n"); | |
662 | ||
663 | /* If flags doesn't match - report failure */ | |
664 | return all_slaves_done = 1 ? TEST_SUCCESS : TEST_FAILED; | |
665 | } | |
666 | ||
667 | #define TEST_LACP_SLAVE_COUT RTE_DIM(test_params.slave_ports) | |
668 | static int | |
669 | test_mode4_lacp(void) | |
670 | { | |
671 | int retval; | |
672 | ||
673 | retval = initialize_bonded_device_with_slaves(TEST_LACP_SLAVE_COUT, 0); | |
674 | TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); | |
675 | ||
676 | /* Test LACP handshake function */ | |
677 | retval = bond_handshake(); | |
678 | TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); | |
679 | ||
680 | retval = remove_slaves_and_stop_bonded_device(); | |
681 | TEST_ASSERT_SUCCESS(retval, "Test cleanup failed."); | |
682 | ||
683 | return TEST_SUCCESS; | |
684 | } | |
685 | ||
686 | static int | |
687 | generate_packets(struct ether_addr *src_mac, | |
688 | struct ether_addr *dst_mac, uint16_t count, struct rte_mbuf **buf) | |
689 | { | |
690 | uint16_t pktlen = PACKET_BURST_GEN_PKT_LEN; | |
691 | uint8_t vlan_enable = 0; | |
692 | uint16_t vlan_id = 0; | |
693 | uint8_t ip4_type = 1; /* 0 - ipv6 */ | |
694 | ||
695 | uint16_t src_port = 10, dst_port = 20; | |
696 | ||
697 | uint32_t ip_src[4] = { [0 ... 2] = 0xDEADBEEF, [3] = IPv4(192, 168, 0, 1) }; | |
698 | uint32_t ip_dst[4] = { [0 ... 2] = 0xFEEDFACE, [3] = IPv4(192, 168, 0, 2) }; | |
699 | ||
700 | struct ether_hdr pkt_eth_hdr; | |
701 | struct udp_hdr pkt_udp_hdr; | |
702 | union { | |
703 | struct ipv4_hdr v4; | |
704 | struct ipv6_hdr v6; | |
705 | } pkt_ip_hdr; | |
706 | ||
707 | int retval; | |
708 | ||
709 | initialize_eth_header(&pkt_eth_hdr, src_mac, dst_mac, ip4_type, | |
710 | vlan_enable, vlan_id); | |
711 | ||
712 | if (ip4_type) | |
713 | initialize_ipv4_header(&pkt_ip_hdr.v4, ip_src[3], ip_dst[3], pktlen); | |
714 | else | |
715 | initialize_ipv6_header(&pkt_ip_hdr.v6, (uint8_t *)ip_src, | |
716 | (uint8_t *)&ip_dst, pktlen); | |
717 | ||
718 | initialize_udp_header(&pkt_udp_hdr, src_port, dst_port, 16); | |
719 | ||
720 | retval = generate_packet_burst(test_params.mbuf_pool, buf, | |
721 | &pkt_eth_hdr, vlan_enable, &pkt_ip_hdr, 1, &pkt_udp_hdr, | |
722 | count, pktlen, 1); | |
723 | ||
724 | if (retval > 0 && retval != count) | |
725 | free_pkts(&buf[count - retval], retval); | |
726 | ||
727 | TEST_ASSERT_EQUAL(retval, count, "Failed to generate %u packets", | |
728 | count); | |
729 | ||
730 | return count; | |
731 | } | |
732 | ||
733 | static int | |
734 | generate_and_put_packets(struct slave_conf *slave, struct ether_addr *src_mac, | |
735 | struct ether_addr *dst_mac, uint16_t count) | |
736 | { | |
737 | struct rte_mbuf *pkts[MAX_PKT_BURST]; | |
738 | int retval; | |
739 | ||
740 | retval = generate_packets(src_mac, dst_mac, count, pkts); | |
741 | if (retval != (int)count) | |
742 | return retval; | |
743 | ||
744 | retval = slave_put_pkts(slave, pkts, count); | |
745 | if (retval > 0 && retval != count) | |
746 | free_pkts(&pkts[retval], count - retval); | |
747 | ||
748 | TEST_ASSERT_EQUAL(retval, count, | |
749 | "Failed to enqueue packets into slave %u RX queue", slave->port_id); | |
750 | ||
751 | return TEST_SUCCESS; | |
752 | } | |
753 | ||
754 | static int | |
755 | test_mode4_rx(void) | |
756 | { | |
757 | struct slave_conf *slave; | |
758 | uint16_t i, j; | |
759 | ||
760 | uint16_t expected_pkts_cnt; | |
761 | struct rte_mbuf *pkts[MAX_PKT_BURST]; | |
762 | int retval; | |
763 | unsigned delay; | |
764 | ||
765 | struct ether_hdr *hdr; | |
766 | ||
767 | struct ether_addr src_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } }; | |
768 | struct ether_addr dst_mac; | |
769 | struct ether_addr bonded_mac; | |
770 | ||
771 | retval = initialize_bonded_device_with_slaves(TEST_PROMISC_SLAVE_COUNT, | |
772 | 0); | |
773 | TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); | |
774 | ||
775 | retval = bond_handshake(); | |
776 | TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); | |
777 | ||
778 | rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac); | |
779 | ether_addr_copy(&bonded_mac, &dst_mac); | |
780 | ||
781 | /* Assert that dst address is not bonding address. Do not set the | |
782 | * least significant bit of the zero byte as this would create a | |
783 | * multicast address. | |
784 | */ | |
785 | dst_mac.addr_bytes[0] += 2; | |
786 | ||
787 | /* First try with promiscuous mode enabled. | |
788 | * Add 2 packets to each slave. First with bonding MAC address, second with | |
789 | * different. Check if we received all of them. */ | |
790 | rte_eth_promiscuous_enable(test_params.bonded_port_id); | |
791 | ||
792 | expected_pkts_cnt = 0; | |
793 | FOR_EACH_SLAVE(i, slave) { | |
794 | retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1); | |
795 | TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u", | |
796 | slave->port_id); | |
797 | ||
798 | retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1); | |
799 | TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u", | |
800 | slave->port_id); | |
801 | ||
802 | /* Expect 2 packets per slave */ | |
803 | expected_pkts_cnt += 2; | |
804 | } | |
805 | ||
806 | retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts, | |
807 | RTE_DIM(pkts)); | |
808 | ||
809 | if (retval == expected_pkts_cnt) { | |
810 | int cnt[2] = { 0, 0 }; | |
811 | ||
812 | for (i = 0; i < expected_pkts_cnt; i++) { | |
813 | hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *); | |
814 | cnt[is_same_ether_addr(&hdr->d_addr, &bonded_mac)]++; | |
815 | } | |
816 | ||
817 | free_pkts(pkts, expected_pkts_cnt); | |
818 | ||
819 | /* For division by 2 expected_pkts_cnt must be even */ | |
820 | RTE_VERIFY((expected_pkts_cnt & 1) == 0); | |
821 | TEST_ASSERT(cnt[0] == expected_pkts_cnt / 2 && | |
822 | cnt[1] == expected_pkts_cnt / 2, | |
823 | "Expected %u packets with the same MAC and %u with different but " | |
824 | "got %u with the same and %u with diffrent MAC", | |
825 | expected_pkts_cnt / 2, expected_pkts_cnt / 2, cnt[1], cnt[0]); | |
826 | } else if (retval > 0) | |
827 | free_pkts(pkts, retval); | |
828 | ||
829 | TEST_ASSERT_EQUAL(retval, expected_pkts_cnt, | |
830 | "Expected %u packets but received only %d", expected_pkts_cnt, retval); | |
831 | ||
832 | /* Now, disable promiscuous mode. When promiscuous mode is disabled we | |
833 | * expect to receive only packets that are directed to bonding port. */ | |
834 | rte_eth_promiscuous_disable(test_params.bonded_port_id); | |
835 | ||
836 | expected_pkts_cnt = 0; | |
837 | FOR_EACH_SLAVE(i, slave) { | |
838 | retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1); | |
839 | TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u", | |
840 | slave->port_id); | |
841 | ||
842 | retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1); | |
843 | TEST_ASSERT_SUCCESS(retval, "Failed to enqueue packets to slave %u", | |
844 | slave->port_id); | |
845 | ||
846 | /* Expect only one packet per slave */ | |
847 | expected_pkts_cnt += 1; | |
848 | } | |
849 | ||
850 | retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts, | |
851 | RTE_DIM(pkts)); | |
852 | ||
853 | if (retval == expected_pkts_cnt) { | |
854 | int eq_cnt = 0; | |
855 | ||
856 | for (i = 0; i < expected_pkts_cnt; i++) { | |
857 | hdr = rte_pktmbuf_mtod(pkts[i], struct ether_hdr *); | |
858 | eq_cnt += is_same_ether_addr(&hdr->d_addr, &bonded_mac); | |
859 | } | |
860 | ||
861 | free_pkts(pkts, expected_pkts_cnt); | |
862 | TEST_ASSERT_EQUAL(eq_cnt, expected_pkts_cnt, "Packet address mismatch"); | |
863 | } else if (retval > 0) | |
864 | free_pkts(pkts, retval); | |
865 | ||
866 | TEST_ASSERT_EQUAL(retval, expected_pkts_cnt, | |
867 | "Expected %u packets but received only %d", expected_pkts_cnt, retval); | |
868 | ||
869 | /* Link down test: simulate link down for first slave. */ | |
870 | delay = bond_get_update_timeout_ms(); | |
871 | ||
872 | uint8_t slave_down_id = INVALID_PORT_ID; | |
873 | ||
874 | /* Find first slave and make link down on it*/ | |
875 | FOR_EACH_SLAVE(i, slave) { | |
876 | rte_eth_dev_set_link_down(slave->port_id); | |
877 | slave_down_id = slave->port_id; | |
878 | break; | |
879 | } | |
880 | ||
881 | RTE_VERIFY(slave_down_id != INVALID_PORT_ID); | |
882 | ||
883 | /* Give some time to rearrange bonding */ | |
884 | for (i = 0; i < 3; i++) { | |
885 | rte_delay_ms(delay); | |
886 | bond_handshake(); | |
887 | } | |
888 | ||
889 | TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed"); | |
890 | ||
891 | /* Put packet to each slave */ | |
892 | FOR_EACH_SLAVE(i, slave) { | |
893 | void *pkt = NULL; | |
894 | ||
895 | dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id; | |
896 | retval = generate_and_put_packets(slave, &src_mac, &dst_mac, 1); | |
897 | TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst."); | |
898 | ||
899 | src_mac.addr_bytes[ETHER_ADDR_LEN - 1] = slave->port_id; | |
900 | retval = generate_and_put_packets(slave, &src_mac, &bonded_mac, 1); | |
901 | TEST_ASSERT_SUCCESS(retval, "Failed to generate test packet burst."); | |
902 | ||
903 | retval = bond_rx(pkts, RTE_DIM(pkts)); | |
904 | ||
905 | /* Clean anything */ | |
906 | if (retval > 0) | |
907 | free_pkts(pkts, retval); | |
908 | ||
909 | while (rte_ring_dequeue(slave->rx_queue, (void **)&pkt) == 0) | |
910 | rte_pktmbuf_free(pkt); | |
911 | ||
912 | if (slave_down_id == slave->port_id) | |
913 | TEST_ASSERT_EQUAL(retval, 0, "Packets received unexpectedly."); | |
914 | else | |
915 | TEST_ASSERT_NOT_EQUAL(retval, 0, | |
916 | "Expected to receive some packets on slave %u.", | |
917 | slave->port_id); | |
918 | rte_eth_dev_start(slave->port_id); | |
919 | ||
920 | for (j = 0; j < 5; j++) { | |
921 | TEST_ASSERT(bond_handshake_reply(slave) >= 0, | |
922 | "Handshake after link up"); | |
923 | ||
924 | if (bond_handshake_done(slave) == 1) | |
925 | break; | |
926 | } | |
927 | ||
928 | TEST_ASSERT(j < 5, "Failed to agregate slave after link up"); | |
929 | } | |
930 | ||
931 | remove_slaves_and_stop_bonded_device(); | |
932 | return TEST_SUCCESS; | |
933 | } | |
934 | ||
935 | static int | |
936 | test_mode4_tx_burst(void) | |
937 | { | |
938 | struct slave_conf *slave; | |
939 | uint16_t i, j; | |
940 | ||
941 | uint16_t exp_pkts_cnt, pkts_cnt = 0; | |
942 | struct rte_mbuf *pkts[MAX_PKT_BURST]; | |
943 | int retval; | |
944 | unsigned delay; | |
945 | ||
946 | struct ether_addr dst_mac = { { 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00 } }; | |
947 | struct ether_addr bonded_mac; | |
948 | ||
949 | retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 0); | |
950 | TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); | |
951 | ||
952 | retval = bond_handshake(); | |
953 | TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); | |
954 | ||
955 | rte_eth_macaddr_get(test_params.bonded_port_id, &bonded_mac); | |
956 | ||
957 | /* Prepare burst */ | |
958 | for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) { | |
959 | dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt; | |
960 | retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]); | |
961 | ||
962 | if (retval != 1) | |
963 | free_pkts(pkts, pkts_cnt); | |
964 | ||
965 | TEST_ASSERT_EQUAL(retval, 1, "Failed to generate packet %u", pkts_cnt); | |
966 | } | |
967 | exp_pkts_cnt = pkts_cnt; | |
968 | ||
969 | /* Transmit packets on bonded device */ | |
970 | retval = bond_tx(pkts, pkts_cnt); | |
971 | if (retval > 0 && retval < pkts_cnt) | |
972 | free_pkts(&pkts[retval], pkts_cnt - retval); | |
973 | ||
974 | TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed"); | |
975 | ||
976 | /* Check if packets were transmitted properly. Every slave should have | |
977 | * at least one packet, and sum must match. Under normal operation | |
978 | * there should be no LACP nor MARKER frames. */ | |
979 | pkts_cnt = 0; | |
980 | FOR_EACH_SLAVE(i, slave) { | |
981 | uint16_t normal_cnt, slow_cnt; | |
982 | ||
983 | retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts)); | |
984 | normal_cnt = 0; | |
985 | slow_cnt = 0; | |
986 | ||
987 | for (j = 0; j < retval; j++) { | |
988 | if (make_lacp_reply(slave, pkts[j]) == 1) | |
989 | normal_cnt++; | |
990 | else | |
991 | slow_cnt++; | |
992 | } | |
993 | ||
994 | free_pkts(pkts, normal_cnt + slow_cnt); | |
995 | TEST_ASSERT_EQUAL(slow_cnt, 0, | |
996 | "slave %u unexpectedly transmitted %d SLOW packets", slave->port_id, | |
997 | slow_cnt); | |
998 | ||
999 | TEST_ASSERT_NOT_EQUAL(normal_cnt, 0, | |
1000 | "slave %u did not transmitted any packets", slave->port_id); | |
1001 | ||
1002 | pkts_cnt += normal_cnt; | |
1003 | } | |
1004 | ||
1005 | TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt, | |
1006 | "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt); | |
1007 | ||
1008 | /* Link down test: | |
1009 | * simulate link down for first slave. */ | |
1010 | delay = bond_get_update_timeout_ms(); | |
1011 | ||
1012 | uint8_t slave_down_id = INVALID_PORT_ID; | |
1013 | ||
1014 | FOR_EACH_SLAVE(i, slave) { | |
1015 | rte_eth_dev_set_link_down(slave->port_id); | |
1016 | slave_down_id = slave->port_id; | |
1017 | break; | |
1018 | } | |
1019 | ||
1020 | RTE_VERIFY(slave_down_id != INVALID_PORT_ID); | |
1021 | ||
1022 | /* Give some time to rearrange bonding. */ | |
1023 | for (i = 0; i < 3; i++) { | |
1024 | bond_handshake(); | |
1025 | rte_delay_ms(delay); | |
1026 | } | |
1027 | ||
1028 | TEST_ASSERT_SUCCESS(bond_handshake(), "Handshake after link down failed"); | |
1029 | ||
1030 | /* Prepare burst. */ | |
1031 | for (pkts_cnt = 0; pkts_cnt < RTE_DIM(pkts); pkts_cnt++) { | |
1032 | dst_mac.addr_bytes[ETHER_ADDR_LEN - 1] = pkts_cnt; | |
1033 | retval = generate_packets(&bonded_mac, &dst_mac, 1, &pkts[pkts_cnt]); | |
1034 | ||
1035 | if (retval != 1) | |
1036 | free_pkts(pkts, pkts_cnt); | |
1037 | ||
1038 | TEST_ASSERT_EQUAL(retval, 1, "Failed to generate test packet %u", | |
1039 | pkts_cnt); | |
1040 | } | |
1041 | exp_pkts_cnt = pkts_cnt; | |
1042 | ||
1043 | /* Transmit packets on bonded device. */ | |
1044 | retval = bond_tx(pkts, pkts_cnt); | |
1045 | if (retval > 0 && retval < pkts_cnt) | |
1046 | free_pkts(&pkts[retval], pkts_cnt - retval); | |
1047 | ||
1048 | TEST_ASSERT_EQUAL(retval, pkts_cnt, "TX on bonded device failed"); | |
1049 | ||
1050 | /* Check if packets was transmitted properly. Every slave should have | |
1051 | * at least one packet, and sum must match. Under normal operation | |
1052 | * there should be no LACP nor MARKER frames. */ | |
1053 | pkts_cnt = 0; | |
1054 | FOR_EACH_SLAVE(i, slave) { | |
1055 | uint16_t normal_cnt, slow_cnt; | |
1056 | ||
1057 | retval = slave_get_pkts(slave, pkts, RTE_DIM(pkts)); | |
1058 | normal_cnt = 0; | |
1059 | slow_cnt = 0; | |
1060 | ||
1061 | for (j = 0; j < retval; j++) { | |
1062 | if (make_lacp_reply(slave, pkts[j]) == 1) | |
1063 | normal_cnt++; | |
1064 | else | |
1065 | slow_cnt++; | |
1066 | } | |
1067 | ||
1068 | free_pkts(pkts, normal_cnt + slow_cnt); | |
1069 | ||
1070 | if (slave_down_id == slave->port_id) { | |
1071 | TEST_ASSERT_EQUAL(normal_cnt + slow_cnt, 0, | |
1072 | "slave %u enexpectedly transmitted %u packets", | |
1073 | normal_cnt + slow_cnt, slave->port_id); | |
1074 | } else { | |
1075 | TEST_ASSERT_EQUAL(slow_cnt, 0, | |
1076 | "slave %u unexpectedly transmitted %d SLOW packets", | |
1077 | slave->port_id, slow_cnt); | |
1078 | ||
1079 | TEST_ASSERT_NOT_EQUAL(normal_cnt, 0, | |
1080 | "slave %u did not transmitted any packets", slave->port_id); | |
1081 | } | |
1082 | ||
1083 | pkts_cnt += normal_cnt; | |
1084 | } | |
1085 | ||
1086 | TEST_ASSERT_EQUAL(exp_pkts_cnt, pkts_cnt, | |
1087 | "Expected %u packets but transmitted only %d", exp_pkts_cnt, pkts_cnt); | |
1088 | ||
1089 | return remove_slaves_and_stop_bonded_device(); | |
1090 | } | |
1091 | ||
1092 | static void | |
1093 | init_marker(struct rte_mbuf *pkt, struct slave_conf *slave) | |
1094 | { | |
1095 | struct marker_header *marker_hdr = rte_pktmbuf_mtod(pkt, | |
1096 | struct marker_header *); | |
1097 | ||
1098 | /* Copy multicast destination address */ | |
1099 | ether_addr_copy(&slow_protocol_mac_addr, &marker_hdr->eth_hdr.d_addr); | |
1100 | ||
1101 | /* Init source address */ | |
1102 | ether_addr_copy(&parnter_mac_default, &marker_hdr->eth_hdr.s_addr); | |
1103 | marker_hdr->eth_hdr.s_addr.addr_bytes[ETHER_ADDR_LEN-1] = slave->port_id; | |
1104 | ||
1105 | marker_hdr->eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_SLOW); | |
1106 | ||
1107 | marker_hdr->marker.subtype = SLOW_SUBTYPE_MARKER; | |
1108 | marker_hdr->marker.version_number = 1; | |
1109 | marker_hdr->marker.tlv_type_marker = MARKER_TLV_TYPE_INFO; | |
1110 | marker_hdr->marker.info_length = | |
1111 | offsetof(struct marker, reserved_90) - | |
1112 | offsetof(struct marker, requester_port); | |
1113 | RTE_VERIFY(marker_hdr->marker.info_length == 16); | |
1114 | marker_hdr->marker.requester_port = slave->port_id + 1; | |
1115 | marker_hdr->marker.tlv_type_terminator = TLV_TYPE_TERMINATOR_INFORMATION; | |
1116 | marker_hdr->marker.terminator_length = 0; | |
1117 | } | |
1118 | ||
1119 | static int | |
1120 | test_mode4_marker(void) | |
1121 | { | |
1122 | struct slave_conf *slave; | |
1123 | struct rte_mbuf *pkts[MAX_PKT_BURST]; | |
1124 | struct rte_mbuf *marker_pkt; | |
1125 | struct marker_header *marker_hdr; | |
1126 | ||
1127 | unsigned delay; | |
1128 | int retval; | |
1129 | uint16_t nb_pkts; | |
1130 | uint8_t i, j; | |
1131 | const uint16_t ethtype_slow_be = rte_be_to_cpu_16(ETHER_TYPE_SLOW); | |
1132 | ||
1133 | retval = initialize_bonded_device_with_slaves(TEST_MARKER_SLAVE_COUT, | |
1134 | 0); | |
1135 | TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); | |
1136 | ||
1137 | /* Test LACP handshake function */ | |
1138 | retval = bond_handshake(); | |
1139 | TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); | |
1140 | ||
1141 | delay = bond_get_update_timeout_ms(); | |
1142 | FOR_EACH_SLAVE(i, slave) { | |
1143 | marker_pkt = rte_pktmbuf_alloc(test_params.mbuf_pool); | |
1144 | TEST_ASSERT_NOT_NULL(marker_pkt, "Failed to allocate marker packet"); | |
1145 | init_marker(marker_pkt, slave); | |
1146 | ||
1147 | retval = slave_put_pkts(slave, &marker_pkt, 1); | |
1148 | if (retval != 1) | |
1149 | rte_pktmbuf_free(marker_pkt); | |
1150 | ||
1151 | TEST_ASSERT_EQUAL(retval, 1, | |
1152 | "Failed to send marker packet to slave %u", slave->port_id); | |
1153 | ||
1154 | for (j = 0; j < 20; ++j) { | |
1155 | rte_delay_ms(delay); | |
1156 | retval = rte_eth_rx_burst(test_params.bonded_port_id, 0, pkts, | |
1157 | RTE_DIM(pkts)); | |
1158 | ||
1159 | if (retval > 0) | |
1160 | free_pkts(pkts, retval); | |
1161 | ||
1162 | TEST_ASSERT_EQUAL(retval, 0, "Received packets unexpectedly"); | |
1163 | ||
1164 | retval = rte_eth_tx_burst(test_params.bonded_port_id, 0, NULL, 0); | |
1165 | TEST_ASSERT_EQUAL(retval, 0, | |
1166 | "Requested TX of 0 packets but %d transmitted", retval); | |
1167 | ||
1168 | /* Check if LACP packet was send by state machines | |
1169 | First and only packet must be a maker response */ | |
1170 | retval = slave_get_pkts(slave, pkts, MAX_PKT_BURST); | |
1171 | if (retval == 0) | |
1172 | continue; | |
1173 | if (retval > 1) | |
1174 | free_pkts(pkts, retval); | |
1175 | ||
1176 | TEST_ASSERT_EQUAL(retval, 1, "failed to get slave packets"); | |
1177 | nb_pkts = retval; | |
1178 | ||
1179 | marker_hdr = rte_pktmbuf_mtod(pkts[0], struct marker_header *); | |
1180 | /* Check if it's slow packet*/ | |
1181 | if (marker_hdr->eth_hdr.ether_type != ethtype_slow_be) | |
1182 | retval = -1; | |
1183 | /* Check if it's marker packet */ | |
1184 | else if (marker_hdr->marker.subtype != SLOW_SUBTYPE_MARKER) | |
1185 | retval = -2; | |
1186 | else if (marker_hdr->marker.tlv_type_marker != MARKER_TLV_TYPE_RESP) | |
1187 | retval = -3; | |
1188 | ||
1189 | free_pkts(pkts, nb_pkts); | |
1190 | ||
1191 | TEST_ASSERT_NOT_EQUAL(retval, -1, "Unexpected protocol type"); | |
1192 | TEST_ASSERT_NOT_EQUAL(retval, -2, "Unexpected sub protocol type"); | |
1193 | TEST_ASSERT_NOT_EQUAL(retval, -3, "Unexpected marker type"); | |
1194 | break; | |
1195 | } | |
1196 | ||
1197 | TEST_ASSERT(j < 20, "Marker response not found"); | |
1198 | } | |
1199 | ||
1200 | retval = remove_slaves_and_stop_bonded_device(); | |
1201 | TEST_ASSERT_SUCCESS(retval, "Test cleanup failed."); | |
1202 | ||
1203 | return TEST_SUCCESS; | |
1204 | } | |
1205 | ||
1206 | static int | |
1207 | test_mode4_expired(void) | |
1208 | { | |
1209 | struct slave_conf *slave, *exp_slave = NULL; | |
1210 | struct rte_mbuf *pkts[MAX_PKT_BURST]; | |
1211 | int retval; | |
1212 | uint32_t old_delay; | |
1213 | ||
1214 | uint8_t i; | |
1215 | uint16_t j; | |
1216 | ||
1217 | struct rte_eth_bond_8023ad_conf conf; | |
1218 | ||
1219 | retval = initialize_bonded_device_with_slaves(TEST_EXPIRED_SLAVE_COUNT, | |
1220 | 0); | |
1221 | /* Set custom timeouts to make test last shorter. */ | |
1222 | rte_eth_bond_8023ad_conf_get(test_params.bonded_port_id, &conf); | |
1223 | conf.fast_periodic_ms = 100; | |
1224 | conf.slow_periodic_ms = 600; | |
1225 | conf.short_timeout_ms = 300; | |
1226 | conf.long_timeout_ms = 900; | |
1227 | conf.aggregate_wait_timeout_ms = 200; | |
1228 | conf.tx_period_ms = 100; | |
1229 | old_delay = conf.update_timeout_ms; | |
1230 | conf.update_timeout_ms = 10; | |
1231 | rte_eth_bond_8023ad_setup(test_params.bonded_port_id, &conf); | |
1232 | ||
1233 | /* Wait for new settings to be applied. */ | |
1234 | for (i = 0; i < old_delay/conf.update_timeout_ms * 2; i++) { | |
1235 | FOR_EACH_SLAVE(j, slave) | |
1236 | bond_handshake_reply(slave); | |
1237 | ||
1238 | rte_delay_ms(conf.update_timeout_ms); | |
1239 | } | |
1240 | ||
1241 | retval = bond_handshake(); | |
1242 | TEST_ASSERT_SUCCESS(retval, "Initial handshake failed"); | |
1243 | ||
1244 | /* Find first slave */ | |
1245 | FOR_EACH_SLAVE(i, slave) { | |
1246 | exp_slave = slave; | |
1247 | break; | |
1248 | } | |
1249 | ||
1250 | RTE_VERIFY(exp_slave != NULL); | |
1251 | ||
1252 | /* When one of partners do not send or respond to LACP frame in | |
1253 | * conf.long_timeout_ms time, internal state machines should detect this | |
1254 | * and transit to expired state. */ | |
1255 | for (j = 0; j < conf.long_timeout_ms/conf.update_timeout_ms + 2; j++) { | |
1256 | rte_delay_ms(conf.update_timeout_ms); | |
1257 | ||
1258 | retval = bond_tx(NULL, 0); | |
1259 | TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets", | |
1260 | retval); | |
1261 | ||
1262 | FOR_EACH_SLAVE(i, slave) { | |
1263 | retval = bond_handshake_reply(slave); | |
1264 | TEST_ASSERT(retval >= 0, "Handshake failed"); | |
1265 | ||
1266 | /* Remove replay for slave that supose to be expired. */ | |
1267 | if (slave == exp_slave) { | |
1268 | while (rte_ring_count(slave->rx_queue) > 0) { | |
1269 | void *pkt = NULL; | |
1270 | ||
1271 | rte_ring_dequeue(slave->rx_queue, &pkt); | |
1272 | rte_pktmbuf_free(pkt); | |
1273 | } | |
1274 | } | |
1275 | } | |
1276 | ||
1277 | retval = bond_rx(pkts, RTE_DIM(pkts)); | |
1278 | if (retval > 0) | |
1279 | free_pkts(pkts, retval); | |
1280 | ||
1281 | TEST_ASSERT_EQUAL(retval, 0, "Unexpectedly received %d packets", | |
1282 | retval); | |
1283 | } | |
1284 | ||
1285 | /* After test only expected slave should be in EXPIRED state */ | |
1286 | FOR_EACH_SLAVE(i, slave) { | |
1287 | if (slave == exp_slave) | |
1288 | TEST_ASSERT(slave->lacp_parnter_state & STATE_EXPIRED, | |
1289 | "Slave %u should be in expired.", slave->port_id); | |
1290 | else | |
1291 | TEST_ASSERT_EQUAL(bond_handshake_done(slave), 1, | |
1292 | "Slave %u should be operational.", slave->port_id); | |
1293 | } | |
1294 | ||
1295 | retval = remove_slaves_and_stop_bonded_device(); | |
1296 | TEST_ASSERT_SUCCESS(retval, "Test cleanup failed."); | |
1297 | ||
1298 | return TEST_SUCCESS; | |
1299 | } | |
1300 | ||
1301 | static int | |
1302 | test_mode4_ext_ctrl(void) | |
1303 | { | |
1304 | /* | |
1305 | * configure bonded interface without the external sm enabled | |
1306 | * . try to transmit lacpdu (should fail) | |
1307 | * . try to set collecting and distributing flags (should fail) | |
1308 | * reconfigure w/external sm | |
1309 | * . transmit one lacpdu on each slave using new api | |
1310 | * . make sure each slave receives one lacpdu using the callback api | |
1311 | * . transmit one data pdu on each slave (should fail) | |
1312 | * . enable distribution and collection, send one data pdu each again | |
1313 | */ | |
1314 | ||
1315 | int retval; | |
1316 | struct slave_conf *slave = NULL; | |
1317 | uint8_t i; | |
1318 | ||
1319 | struct rte_mbuf *lacp_tx_buf[SLAVE_COUNT]; | |
1320 | struct ether_addr src_mac, dst_mac; | |
1321 | struct lacpdu_header lacpdu = { | |
1322 | .lacpdu = { | |
1323 | .subtype = SLOW_SUBTYPE_LACP, | |
1324 | }, | |
1325 | }; | |
1326 | ||
1327 | ether_addr_copy(&parnter_system, &src_mac); | |
1328 | ether_addr_copy(&slow_protocol_mac_addr, &dst_mac); | |
1329 | ||
1330 | initialize_eth_header(&lacpdu.eth_hdr, &src_mac, &dst_mac, | |
1331 | ETHER_TYPE_SLOW, 0, 0); | |
1332 | ||
1333 | for (i = 0; i < SLAVE_COUNT; i++) { | |
1334 | lacp_tx_buf[i] = rte_pktmbuf_alloc(test_params.mbuf_pool); | |
1335 | rte_memcpy(rte_pktmbuf_mtod(lacp_tx_buf[i], char *), | |
1336 | &lacpdu, sizeof(lacpdu)); | |
1337 | rte_pktmbuf_pkt_len(lacp_tx_buf[i]) = sizeof(lacpdu); | |
1338 | } | |
1339 | ||
1340 | retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 0); | |
1341 | TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); | |
1342 | ||
1343 | FOR_EACH_SLAVE(i, slave) { | |
1344 | TEST_ASSERT_FAIL(rte_eth_bond_8023ad_ext_slowtx( | |
1345 | test_params.bonded_port_id, | |
1346 | slave->port_id, lacp_tx_buf[i]), | |
1347 | "Slave should not allow manual LACP xmit"); | |
1348 | TEST_ASSERT_FAIL(rte_eth_bond_8023ad_ext_collect( | |
1349 | test_params.bonded_port_id, | |
1350 | slave->port_id, 1), | |
1351 | "Slave should not allow external state controls"); | |
1352 | } | |
1353 | ||
1354 | free_pkts(lacp_tx_buf, RTE_DIM(lacp_tx_buf)); | |
1355 | ||
1356 | retval = remove_slaves_and_stop_bonded_device(); | |
1357 | TEST_ASSERT_SUCCESS(retval, "Bonded device cleanup failed."); | |
1358 | ||
1359 | return TEST_SUCCESS; | |
1360 | } | |
1361 | ||
1362 | ||
1363 | static int | |
1364 | test_mode4_ext_lacp(void) | |
1365 | { | |
1366 | int retval; | |
1367 | struct slave_conf *slave = NULL; | |
1368 | uint8_t all_slaves_done = 0, i; | |
1369 | uint16_t nb_pkts; | |
1370 | const unsigned int delay = bond_get_update_timeout_ms(); | |
1371 | ||
1372 | struct rte_mbuf *lacp_tx_buf[SLAVE_COUNT]; | |
1373 | struct rte_mbuf *buf[SLAVE_COUNT]; | |
1374 | struct ether_addr src_mac, dst_mac; | |
1375 | struct lacpdu_header lacpdu = { | |
1376 | .lacpdu = { | |
1377 | .subtype = SLOW_SUBTYPE_LACP, | |
1378 | }, | |
1379 | }; | |
1380 | ||
1381 | ether_addr_copy(&parnter_system, &src_mac); | |
1382 | ether_addr_copy(&slow_protocol_mac_addr, &dst_mac); | |
1383 | ||
1384 | initialize_eth_header(&lacpdu.eth_hdr, &src_mac, &dst_mac, | |
1385 | ETHER_TYPE_SLOW, 0, 0); | |
1386 | ||
1387 | for (i = 0; i < SLAVE_COUNT; i++) { | |
1388 | lacp_tx_buf[i] = rte_pktmbuf_alloc(test_params.mbuf_pool); | |
1389 | rte_memcpy(rte_pktmbuf_mtod(lacp_tx_buf[i], char *), | |
1390 | &lacpdu, sizeof(lacpdu)); | |
1391 | rte_pktmbuf_pkt_len(lacp_tx_buf[i]) = sizeof(lacpdu); | |
1392 | } | |
1393 | ||
1394 | retval = initialize_bonded_device_with_slaves(TEST_TX_SLAVE_COUNT, 1); | |
1395 | TEST_ASSERT_SUCCESS(retval, "Failed to initialize bonded device"); | |
1396 | ||
1397 | memset(lacpdu_rx_count, 0, sizeof(lacpdu_rx_count)); | |
1398 | ||
1399 | /* Wait for new settings to be applied. */ | |
1400 | for (i = 0; i < 30; ++i) | |
1401 | rte_delay_ms(delay); | |
1402 | ||
1403 | FOR_EACH_SLAVE(i, slave) { | |
1404 | retval = rte_eth_bond_8023ad_ext_slowtx( | |
1405 | test_params.bonded_port_id, | |
1406 | slave->port_id, lacp_tx_buf[i]); | |
1407 | TEST_ASSERT_SUCCESS(retval, | |
1408 | "Slave should allow manual LACP xmit"); | |
1409 | } | |
1410 | ||
1411 | nb_pkts = bond_tx(NULL, 0); | |
1412 | TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets transmitted unexpectedly"); | |
1413 | ||
1414 | FOR_EACH_SLAVE(i, slave) { | |
1415 | nb_pkts = slave_get_pkts(slave, buf, RTE_DIM(buf)); | |
1416 | TEST_ASSERT_EQUAL(nb_pkts, 1, "found %u packets on slave %d\n", | |
1417 | nb_pkts, i); | |
1418 | slave_put_pkts(slave, buf, nb_pkts); | |
1419 | } | |
1420 | ||
1421 | nb_pkts = bond_rx(buf, RTE_DIM(buf)); | |
1422 | free_pkts(buf, nb_pkts); | |
1423 | TEST_ASSERT_EQUAL(nb_pkts, 0, "Packets received unexpectedly"); | |
1424 | ||
1425 | /* wait for the periodic callback to run */ | |
1426 | for (i = 0; i < 30 && all_slaves_done == 0; ++i) { | |
1427 | uint8_t s, total = 0; | |
1428 | ||
1429 | rte_delay_ms(delay); | |
1430 | FOR_EACH_SLAVE(s, slave) { | |
1431 | total += lacpdu_rx_count[slave->port_id]; | |
1432 | } | |
1433 | ||
1434 | if (total >= SLAVE_COUNT) | |
1435 | all_slaves_done = 1; | |
1436 | } | |
1437 | ||
1438 | FOR_EACH_SLAVE(i, slave) { | |
1439 | TEST_ASSERT_EQUAL(lacpdu_rx_count[slave->port_id], 1, | |
1440 | "Slave port %u should have received 1 lacpdu (count=%u)", | |
1441 | slave->port_id, | |
1442 | lacpdu_rx_count[slave->port_id]); | |
1443 | } | |
1444 | ||
1445 | retval = remove_slaves_and_stop_bonded_device(); | |
1446 | TEST_ASSERT_SUCCESS(retval, "Test cleanup failed."); | |
1447 | ||
1448 | return TEST_SUCCESS; | |
1449 | } | |
1450 | ||
1451 | static int | |
1452 | check_environment(void) | |
1453 | { | |
1454 | struct slave_conf *port; | |
1455 | uint8_t i, env_state; | |
1456 | uint8_t slaves[RTE_DIM(test_params.slave_ports)]; | |
1457 | int slaves_count; | |
1458 | ||
1459 | env_state = 0; | |
1460 | FOR_EACH_PORT(i, port) { | |
1461 | if (rte_ring_count(port->rx_queue) != 0) | |
1462 | env_state |= 0x01; | |
1463 | ||
1464 | if (rte_ring_count(port->tx_queue) != 0) | |
1465 | env_state |= 0x02; | |
1466 | ||
1467 | if (port->bonded != 0) | |
1468 | env_state |= 0x04; | |
1469 | ||
1470 | if (port->lacp_parnter_state != 0) | |
1471 | env_state |= 0x08; | |
1472 | ||
1473 | if (env_state != 0) | |
1474 | break; | |
1475 | } | |
1476 | ||
1477 | slaves_count = rte_eth_bond_slaves_get(test_params.bonded_port_id, | |
1478 | slaves, RTE_DIM(slaves)); | |
1479 | ||
1480 | if (slaves_count != 0) | |
1481 | env_state |= 0x10; | |
1482 | ||
1483 | TEST_ASSERT_EQUAL(env_state, 0, | |
1484 | "Environment not clean (port %u):%s%s%s%s%s", | |
1485 | port->port_id, | |
1486 | env_state & 0x01 ? " slave rx queue not clean" : "", | |
1487 | env_state & 0x02 ? " slave tx queue not clean" : "", | |
1488 | env_state & 0x04 ? " port marked as enslaved" : "", | |
1489 | env_state & 0x80 ? " slave state is not reset" : "", | |
1490 | env_state & 0x10 ? " slave count not equal 0" : "."); | |
1491 | ||
1492 | ||
1493 | return TEST_SUCCESS; | |
1494 | } | |
1495 | ||
1496 | static int | |
1497 | test_mode4_executor(int (*test_func)(void)) | |
1498 | { | |
1499 | struct slave_conf *port; | |
1500 | int test_result; | |
1501 | uint8_t i; | |
1502 | void *pkt; | |
1503 | ||
1504 | /* Check if environment is clean. Fail to launch a test if there was | |
1505 | * a critical error before that prevented to reset environment. */ | |
1506 | TEST_ASSERT_SUCCESS(check_environment(), | |
1507 | "Refusing to launch test in dirty environment."); | |
1508 | ||
1509 | RTE_VERIFY(test_func != NULL); | |
1510 | test_result = (*test_func)(); | |
1511 | ||
1512 | /* If test succeed check if environment wast left in good condition. */ | |
1513 | if (test_result == TEST_SUCCESS) | |
1514 | test_result = check_environment(); | |
1515 | ||
1516 | /* Reset environment in case test failed to do that. */ | |
1517 | if (test_result != TEST_SUCCESS) { | |
1518 | TEST_ASSERT_SUCCESS(remove_slaves_and_stop_bonded_device(), | |
1519 | "Failed to stop bonded device"); | |
1520 | ||
1521 | FOR_EACH_PORT(i, port) { | |
1522 | while (rte_ring_count(port->rx_queue) != 0) { | |
1523 | if (rte_ring_dequeue(port->rx_queue, &pkt) == 0) | |
1524 | rte_pktmbuf_free(pkt); | |
1525 | } | |
1526 | ||
1527 | while (rte_ring_count(port->tx_queue) != 0) { | |
1528 | if (rte_ring_dequeue(port->tx_queue, &pkt) == 0) | |
1529 | rte_pktmbuf_free(pkt); | |
1530 | } | |
1531 | } | |
1532 | } | |
1533 | ||
1534 | return test_result; | |
1535 | } | |
1536 | ||
1537 | static int | |
1538 | test_mode4_lacp_wrapper(void) | |
1539 | { | |
1540 | return test_mode4_executor(&test_mode4_lacp); | |
1541 | } | |
1542 | ||
1543 | static int | |
1544 | test_mode4_marker_wrapper(void) | |
1545 | { | |
1546 | return test_mode4_executor(&test_mode4_marker); | |
1547 | } | |
1548 | ||
1549 | static int | |
1550 | test_mode4_rx_wrapper(void) | |
1551 | { | |
1552 | return test_mode4_executor(&test_mode4_rx); | |
1553 | } | |
1554 | ||
1555 | static int | |
1556 | test_mode4_tx_burst_wrapper(void) | |
1557 | { | |
1558 | return test_mode4_executor(&test_mode4_tx_burst); | |
1559 | } | |
1560 | ||
1561 | static int | |
1562 | test_mode4_expired_wrapper(void) | |
1563 | { | |
1564 | return test_mode4_executor(&test_mode4_expired); | |
1565 | } | |
1566 | ||
1567 | static int | |
1568 | test_mode4_ext_ctrl_wrapper(void) | |
1569 | { | |
1570 | return test_mode4_executor(&test_mode4_ext_ctrl); | |
1571 | } | |
1572 | ||
1573 | static int | |
1574 | test_mode4_ext_lacp_wrapper(void) | |
1575 | { | |
1576 | return test_mode4_executor(&test_mode4_ext_lacp); | |
1577 | } | |
1578 | ||
1579 | static struct unit_test_suite link_bonding_mode4_test_suite = { | |
1580 | .suite_name = "Link Bonding mode 4 Unit Test Suite", | |
1581 | .setup = test_setup, | |
1582 | .teardown = testsuite_teardown, | |
1583 | .unit_test_cases = { | |
1584 | TEST_CASE_NAMED("test_mode4_lacp", test_mode4_lacp_wrapper), | |
1585 | TEST_CASE_NAMED("test_mode4_rx", test_mode4_rx_wrapper), | |
1586 | TEST_CASE_NAMED("test_mode4_tx_burst", test_mode4_tx_burst_wrapper), | |
1587 | TEST_CASE_NAMED("test_mode4_marker", test_mode4_marker_wrapper), | |
1588 | TEST_CASE_NAMED("test_mode4_expired", test_mode4_expired_wrapper), | |
1589 | TEST_CASE_NAMED("test_mode4_ext_ctrl", | |
1590 | test_mode4_ext_ctrl_wrapper), | |
1591 | TEST_CASE_NAMED("test_mode4_ext_lacp", | |
1592 | test_mode4_ext_lacp_wrapper), | |
1593 | ||
1594 | TEST_CASES_END() /**< NULL terminate unit test array */ | |
1595 | } | |
1596 | }; | |
1597 | ||
1598 | static int | |
1599 | test_link_bonding_mode4(void) | |
1600 | { | |
1601 | return unit_test_suite_runner(&link_bonding_mode4_test_suite); | |
1602 | } | |
1603 | ||
1604 | REGISTER_TEST_COMMAND(link_bonding_mode4_autotest, test_link_bonding_mode4); |