]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2010-2015 Intel Corporation | |
7c673cae FG |
3 | */ |
4 | ||
5 | #include <stddef.h> | |
6 | #include <string.h> | |
7 | #include <stdbool.h> | |
8 | ||
9 | #include <rte_alarm.h> | |
10 | #include <rte_malloc.h> | |
11 | #include <rte_errno.h> | |
12 | #include <rte_cycles.h> | |
13 | #include <rte_compat.h> | |
14 | ||
15 | #include "rte_eth_bond_private.h" | |
16 | ||
17 | static void bond_mode_8023ad_ext_periodic_cb(void *arg); | |
7c673cae | 18 | #ifdef RTE_LIBRTE_BOND_DEBUG_8023AD |
11fdf7f2 TL |
19 | |
20 | #define MODE4_DEBUG(fmt, ...) \ | |
21 | rte_log(RTE_LOG_DEBUG, bond_logtype, \ | |
22 | "%6u [Port %u: %s] " fmt, \ | |
23 | bond_dbg_get_time_diff_ms(), slave_id, \ | |
24 | __func__, ##__VA_ARGS__) | |
7c673cae FG |
25 | |
26 | static uint64_t start_time; | |
27 | ||
28 | static unsigned | |
29 | bond_dbg_get_time_diff_ms(void) | |
30 | { | |
31 | uint64_t now; | |
32 | ||
33 | now = rte_rdtsc(); | |
34 | if (start_time == 0) | |
35 | start_time = now; | |
36 | ||
37 | return ((now - start_time) * 1000) / rte_get_tsc_hz(); | |
38 | } | |
39 | ||
40 | static void | |
41 | bond_print_lacp(struct lacpdu *l) | |
42 | { | |
43 | char a_address[18]; | |
44 | char p_address[18]; | |
45 | char a_state[256] = { 0 }; | |
46 | char p_state[256] = { 0 }; | |
47 | ||
48 | static const char * const state_labels[] = { | |
49 | "ACT", "TIMEOUT", "AGG", "SYNC", "COL", "DIST", "DEF", "EXP" | |
50 | }; | |
51 | ||
52 | int a_len = 0; | |
53 | int p_len = 0; | |
54 | uint8_t i; | |
55 | uint8_t *addr; | |
56 | ||
57 | addr = l->actor.port_params.system.addr_bytes; | |
58 | snprintf(a_address, sizeof(a_address), "%02X:%02X:%02X:%02X:%02X:%02X", | |
59 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); | |
60 | ||
61 | addr = l->partner.port_params.system.addr_bytes; | |
62 | snprintf(p_address, sizeof(p_address), "%02X:%02X:%02X:%02X:%02X:%02X", | |
63 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); | |
64 | ||
65 | for (i = 0; i < 8; i++) { | |
66 | if ((l->actor.state >> i) & 1) { | |
67 | a_len += snprintf(&a_state[a_len], RTE_DIM(a_state) - a_len, "%s ", | |
68 | state_labels[i]); | |
69 | } | |
70 | ||
71 | if ((l->partner.state >> i) & 1) { | |
72 | p_len += snprintf(&p_state[p_len], RTE_DIM(p_state) - p_len, "%s ", | |
73 | state_labels[i]); | |
74 | } | |
75 | } | |
76 | ||
77 | if (a_len && a_state[a_len-1] == ' ') | |
78 | a_state[a_len-1] = '\0'; | |
79 | ||
80 | if (p_len && p_state[p_len-1] == ' ') | |
81 | p_state[p_len-1] = '\0'; | |
82 | ||
11fdf7f2 TL |
83 | RTE_BOND_LOG(DEBUG, |
84 | "LACP: {\n" | |
85 | " subtype= %02X\n" | |
86 | " ver_num=%02X\n" | |
87 | " actor={ tlv=%02X, len=%02X\n" | |
88 | " pri=%04X, system=%s, key=%04X, p_pri=%04X p_num=%04X\n" | |
89 | " state={ %s }\n" | |
90 | " }\n" | |
91 | " partner={ tlv=%02X, len=%02X\n" | |
92 | " pri=%04X, system=%s, key=%04X, p_pri=%04X p_num=%04X\n" | |
93 | " state={ %s }\n" | |
94 | " }\n" | |
95 | " collector={info=%02X, length=%02X, max_delay=%04X\n, " | |
96 | "type_term=%02X, terminator_length = %02X }", | |
97 | l->subtype, | |
98 | l->version_number, | |
99 | l->actor.tlv_type_info, | |
100 | l->actor.info_length, | |
101 | l->actor.port_params.system_priority, | |
102 | a_address, | |
103 | l->actor.port_params.key, | |
104 | l->actor.port_params.port_priority, | |
105 | l->actor.port_params.port_number, | |
106 | a_state, | |
107 | l->partner.tlv_type_info, | |
108 | l->partner.info_length, | |
109 | l->partner.port_params.system_priority, | |
110 | p_address, | |
111 | l->partner.port_params.key, | |
112 | l->partner.port_params.port_priority, | |
113 | l->partner.port_params.port_number, | |
114 | p_state, | |
115 | l->tlv_type_collector_info, | |
116 | l->collector_info_length, | |
117 | l->collector_max_delay, | |
118 | l->tlv_type_terminator, | |
119 | l->terminator_length); | |
7c673cae FG |
120 | |
121 | } | |
11fdf7f2 | 122 | |
7c673cae FG |
123 | #define BOND_PRINT_LACP(lacpdu) bond_print_lacp(lacpdu) |
124 | #else | |
125 | #define BOND_PRINT_LACP(lacpdu) do { } while (0) | |
126 | #define MODE4_DEBUG(fmt, ...) do { } while (0) | |
127 | #endif | |
128 | ||
129 | static const struct ether_addr lacp_mac_addr = { | |
130 | .addr_bytes = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x02 } | |
131 | }; | |
132 | ||
9f95a23c | 133 | struct port bond_mode_8023ad_ports[RTE_MAX_ETHPORTS]; |
7c673cae FG |
134 | |
135 | static void | |
136 | timer_cancel(uint64_t *timer) | |
137 | { | |
138 | *timer = 0; | |
139 | } | |
140 | ||
141 | static void | |
142 | timer_set(uint64_t *timer, uint64_t timeout) | |
143 | { | |
144 | *timer = rte_rdtsc() + timeout; | |
145 | } | |
146 | ||
147 | /* Forces given timer to be in expired state. */ | |
148 | static void | |
149 | timer_force_expired(uint64_t *timer) | |
150 | { | |
151 | *timer = rte_rdtsc(); | |
152 | } | |
153 | ||
154 | static bool | |
155 | timer_is_stopped(uint64_t *timer) | |
156 | { | |
157 | return *timer == 0; | |
158 | } | |
159 | ||
160 | static bool | |
161 | timer_is_expired(uint64_t *timer) | |
162 | { | |
163 | return *timer < rte_rdtsc(); | |
164 | } | |
165 | ||
166 | /* Timer is in running state if it is not stopped nor expired */ | |
167 | static bool | |
168 | timer_is_running(uint64_t *timer) | |
169 | { | |
170 | return !timer_is_stopped(timer) && !timer_is_expired(timer); | |
171 | } | |
172 | ||
173 | static void | |
174 | set_warning_flags(struct port *port, uint16_t flags) | |
175 | { | |
176 | int retval; | |
177 | uint16_t old; | |
178 | uint16_t new_flag = 0; | |
179 | ||
180 | do { | |
181 | old = port->warnings_to_show; | |
182 | new_flag = old | flags; | |
183 | retval = rte_atomic16_cmpset(&port->warnings_to_show, old, new_flag); | |
184 | } while (unlikely(retval == 0)); | |
185 | } | |
186 | ||
187 | static void | |
11fdf7f2 | 188 | show_warnings(uint16_t slave_id) |
7c673cae | 189 | { |
9f95a23c | 190 | struct port *port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
191 | uint8_t warnings; |
192 | ||
193 | do { | |
194 | warnings = port->warnings_to_show; | |
195 | } while (rte_atomic16_cmpset(&port->warnings_to_show, warnings, 0) == 0); | |
196 | ||
197 | if (!warnings) | |
198 | return; | |
199 | ||
200 | if (!timer_is_expired(&port->warning_timer)) | |
201 | return; | |
202 | ||
203 | ||
204 | timer_set(&port->warning_timer, BOND_8023AD_WARNINGS_PERIOD_MS * | |
205 | rte_get_tsc_hz() / 1000); | |
206 | ||
207 | if (warnings & WRN_RX_QUEUE_FULL) { | |
11fdf7f2 TL |
208 | RTE_BOND_LOG(DEBUG, |
209 | "Slave %u: failed to enqueue LACP packet into RX ring.\n" | |
210 | "Receive and transmit functions must be invoked on bonded" | |
211 | "interface at least 10 times per second or LACP will notwork correctly", | |
212 | slave_id); | |
7c673cae FG |
213 | } |
214 | ||
215 | if (warnings & WRN_TX_QUEUE_FULL) { | |
11fdf7f2 TL |
216 | RTE_BOND_LOG(DEBUG, |
217 | "Slave %u: failed to enqueue LACP packet into TX ring.\n" | |
218 | "Receive and transmit functions must be invoked on bonded" | |
219 | "interface at least 10 times per second or LACP will not work correctly", | |
220 | slave_id); | |
7c673cae FG |
221 | } |
222 | ||
223 | if (warnings & WRN_RX_MARKER_TO_FAST) | |
11fdf7f2 TL |
224 | RTE_BOND_LOG(INFO, "Slave %u: marker to early - ignoring.", |
225 | slave_id); | |
7c673cae FG |
226 | |
227 | if (warnings & WRN_UNKNOWN_SLOW_TYPE) { | |
11fdf7f2 TL |
228 | RTE_BOND_LOG(INFO, |
229 | "Slave %u: ignoring unknown slow protocol frame type", | |
230 | slave_id); | |
7c673cae FG |
231 | } |
232 | ||
233 | if (warnings & WRN_UNKNOWN_MARKER_TYPE) | |
11fdf7f2 TL |
234 | RTE_BOND_LOG(INFO, "Slave %u: ignoring unknown marker type", |
235 | slave_id); | |
7c673cae FG |
236 | |
237 | if (warnings & WRN_NOT_LACP_CAPABLE) | |
238 | MODE4_DEBUG("Port %u is not LACP capable!\n", slave_id); | |
239 | } | |
240 | ||
241 | static void | |
242 | record_default(struct port *port) | |
243 | { | |
244 | /* Record default parameters for partner. Partner admin parameters | |
245 | * are not implemented so set them to arbitrary default (last known) and | |
246 | * mark actor that parner is in defaulted state. */ | |
247 | port->partner_state = STATE_LACP_ACTIVE; | |
248 | ACTOR_STATE_SET(port, DEFAULTED); | |
249 | } | |
250 | ||
251 | /** Function handles rx state machine. | |
252 | * | |
253 | * This function implements Receive State Machine from point 5.4.12 in | |
254 | * 802.1AX documentation. It should be called periodically. | |
255 | * | |
256 | * @param lacpdu LACPDU received. | |
257 | * @param port Port on which LACPDU was received. | |
258 | */ | |
259 | static void | |
11fdf7f2 | 260 | rx_machine(struct bond_dev_private *internals, uint16_t slave_id, |
7c673cae FG |
261 | struct lacpdu *lacp) |
262 | { | |
9f95a23c | 263 | struct port *agg, *port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
264 | uint64_t timeout; |
265 | ||
266 | if (SM_FLAG(port, BEGIN)) { | |
267 | /* Initialize stuff */ | |
268 | MODE4_DEBUG("-> INITIALIZE\n"); | |
269 | SM_FLAG_CLR(port, MOVED); | |
270 | port->selected = UNSELECTED; | |
271 | ||
272 | record_default(port); | |
273 | ||
274 | ACTOR_STATE_CLR(port, EXPIRED); | |
275 | timer_cancel(&port->current_while_timer); | |
276 | ||
277 | /* DISABLED: On initialization partner is out of sync */ | |
278 | PARTNER_STATE_CLR(port, SYNCHRONIZATION); | |
279 | ||
280 | /* LACP DISABLED stuff if LACP not enabled on this port */ | |
281 | if (!SM_FLAG(port, LACP_ENABLED)) | |
282 | PARTNER_STATE_CLR(port, AGGREGATION); | |
283 | else | |
284 | PARTNER_STATE_SET(port, AGGREGATION); | |
285 | } | |
286 | ||
287 | if (!SM_FLAG(port, LACP_ENABLED)) { | |
288 | /* Update parameters only if state changed */ | |
289 | if (!timer_is_stopped(&port->current_while_timer)) { | |
290 | port->selected = UNSELECTED; | |
291 | record_default(port); | |
292 | PARTNER_STATE_CLR(port, AGGREGATION); | |
293 | ACTOR_STATE_CLR(port, EXPIRED); | |
294 | timer_cancel(&port->current_while_timer); | |
295 | } | |
296 | return; | |
297 | } | |
298 | ||
299 | if (lacp) { | |
300 | MODE4_DEBUG("LACP -> CURRENT\n"); | |
301 | BOND_PRINT_LACP(lacp); | |
302 | /* Update selected flag. If partner parameters are defaulted assume they | |
303 | * are match. If not defaulted compare LACP actor with ports parner | |
304 | * params. */ | |
305 | if (!ACTOR_STATE(port, DEFAULTED) && | |
306 | (ACTOR_STATE(port, AGGREGATION) != PARTNER_STATE(port, AGGREGATION) | |
307 | || memcmp(&port->partner, &lacp->actor.port_params, | |
308 | sizeof(port->partner)) != 0)) { | |
309 | MODE4_DEBUG("selected <- UNSELECTED\n"); | |
310 | port->selected = UNSELECTED; | |
311 | } | |
312 | ||
313 | /* Record this PDU actor params as partner params */ | |
314 | memcpy(&port->partner, &lacp->actor.port_params, | |
315 | sizeof(struct port_params)); | |
316 | port->partner_state = lacp->actor.state; | |
317 | ||
318 | /* Partner parameters are not defaulted any more */ | |
319 | ACTOR_STATE_CLR(port, DEFAULTED); | |
320 | ||
321 | /* If LACP partner params match this port actor params */ | |
9f95a23c | 322 | agg = &bond_mode_8023ad_ports[port->aggregator_port_id]; |
7c673cae FG |
323 | bool match = port->actor.system_priority == |
324 | lacp->partner.port_params.system_priority && | |
325 | is_same_ether_addr(&agg->actor.system, | |
326 | &lacp->partner.port_params.system) && | |
327 | port->actor.port_priority == | |
328 | lacp->partner.port_params.port_priority && | |
329 | port->actor.port_number == | |
330 | lacp->partner.port_params.port_number; | |
331 | ||
332 | /* Update NTT if partners information are outdated (xored and masked | |
333 | * bits are set)*/ | |
334 | uint8_t state_mask = STATE_LACP_ACTIVE | STATE_LACP_SHORT_TIMEOUT | | |
335 | STATE_SYNCHRONIZATION | STATE_AGGREGATION; | |
336 | ||
337 | if (((port->actor_state ^ lacp->partner.state) & state_mask) || | |
338 | match == false) { | |
339 | SM_FLAG_SET(port, NTT); | |
340 | } | |
341 | ||
342 | /* If LACP partner params match this port actor params */ | |
343 | if (match == true && ACTOR_STATE(port, AGGREGATION) == | |
344 | PARTNER_STATE(port, AGGREGATION)) | |
345 | PARTNER_STATE_SET(port, SYNCHRONIZATION); | |
346 | else if (!PARTNER_STATE(port, AGGREGATION) && ACTOR_STATE(port, | |
347 | AGGREGATION)) | |
348 | PARTNER_STATE_SET(port, SYNCHRONIZATION); | |
349 | else | |
350 | PARTNER_STATE_CLR(port, SYNCHRONIZATION); | |
351 | ||
352 | if (ACTOR_STATE(port, LACP_SHORT_TIMEOUT)) | |
353 | timeout = internals->mode4.short_timeout; | |
354 | else | |
355 | timeout = internals->mode4.long_timeout; | |
356 | ||
357 | timer_set(&port->current_while_timer, timeout); | |
358 | ACTOR_STATE_CLR(port, EXPIRED); | |
359 | return; /* No state change */ | |
360 | } | |
361 | ||
362 | /* If CURRENT state timer is not running (stopped or expired) | |
363 | * transit to EXPIRED state from DISABLED or CURRENT */ | |
364 | if (!timer_is_running(&port->current_while_timer)) { | |
365 | ACTOR_STATE_SET(port, EXPIRED); | |
366 | PARTNER_STATE_CLR(port, SYNCHRONIZATION); | |
367 | PARTNER_STATE_SET(port, LACP_SHORT_TIMEOUT); | |
368 | timer_set(&port->current_while_timer, internals->mode4.short_timeout); | |
369 | } | |
370 | } | |
371 | ||
372 | /** | |
373 | * Function handles periodic tx state machine. | |
374 | * | |
375 | * Function implements Periodic Transmission state machine from point 5.4.13 | |
376 | * in 802.1AX documentation. It should be called periodically. | |
377 | * | |
378 | * @param port Port to handle state machine. | |
379 | */ | |
380 | static void | |
11fdf7f2 | 381 | periodic_machine(struct bond_dev_private *internals, uint16_t slave_id) |
7c673cae | 382 | { |
9f95a23c | 383 | struct port *port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
384 | /* Calculate if either site is LACP enabled */ |
385 | uint64_t timeout; | |
386 | uint8_t active = ACTOR_STATE(port, LACP_ACTIVE) || | |
387 | PARTNER_STATE(port, LACP_ACTIVE); | |
388 | ||
389 | uint8_t is_partner_fast, was_partner_fast; | |
390 | /* No periodic is on BEGIN, LACP DISABLE or when both sides are pasive */ | |
391 | if (SM_FLAG(port, BEGIN) || !SM_FLAG(port, LACP_ENABLED) || !active) { | |
392 | timer_cancel(&port->periodic_timer); | |
393 | timer_force_expired(&port->tx_machine_timer); | |
394 | SM_FLAG_CLR(port, PARTNER_SHORT_TIMEOUT); | |
395 | ||
396 | MODE4_DEBUG("-> NO_PERIODIC ( %s%s%s)\n", | |
397 | SM_FLAG(port, BEGIN) ? "begind " : "", | |
398 | SM_FLAG(port, LACP_ENABLED) ? "" : "LACP disabled ", | |
399 | active ? "LACP active " : "LACP pasive "); | |
400 | return; | |
401 | } | |
402 | ||
403 | is_partner_fast = PARTNER_STATE(port, LACP_SHORT_TIMEOUT); | |
404 | was_partner_fast = SM_FLAG(port, PARTNER_SHORT_TIMEOUT); | |
405 | ||
406 | /* If periodic timer is not started, transit from NO PERIODIC to FAST/SLOW. | |
407 | * Other case: check if timer expire or partners settings changed. */ | |
408 | if (!timer_is_stopped(&port->periodic_timer)) { | |
409 | if (timer_is_expired(&port->periodic_timer)) { | |
410 | SM_FLAG_SET(port, NTT); | |
411 | } else if (is_partner_fast != was_partner_fast) { | |
412 | /* Partners timeout was slow and now it is fast -> send LACP. | |
413 | * In other case (was fast and now it is slow) just switch | |
414 | * timeout to slow without forcing send of LACP (because standard | |
415 | * say so)*/ | |
11fdf7f2 | 416 | if (is_partner_fast) |
7c673cae FG |
417 | SM_FLAG_SET(port, NTT); |
418 | } else | |
419 | return; /* Nothing changed */ | |
420 | } | |
421 | ||
422 | /* Handle state transition to FAST/SLOW LACP timeout */ | |
423 | if (is_partner_fast) { | |
424 | timeout = internals->mode4.fast_periodic_timeout; | |
425 | SM_FLAG_SET(port, PARTNER_SHORT_TIMEOUT); | |
426 | } else { | |
427 | timeout = internals->mode4.slow_periodic_timeout; | |
428 | SM_FLAG_CLR(port, PARTNER_SHORT_TIMEOUT); | |
429 | } | |
430 | ||
431 | timer_set(&port->periodic_timer, timeout); | |
432 | } | |
433 | ||
434 | /** | |
435 | * Function handles mux state machine. | |
436 | * | |
437 | * Function implements Mux Machine from point 5.4.15 in 802.1AX documentation. | |
438 | * It should be called periodically. | |
439 | * | |
440 | * @param port Port to handle state machine. | |
441 | */ | |
442 | static void | |
11fdf7f2 | 443 | mux_machine(struct bond_dev_private *internals, uint16_t slave_id) |
7c673cae | 444 | { |
9f95a23c | 445 | struct port *port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
446 | |
447 | /* Save current state for later use */ | |
448 | const uint8_t state_mask = STATE_SYNCHRONIZATION | STATE_DISTRIBUTING | | |
449 | STATE_COLLECTING; | |
450 | ||
451 | /* Enter DETACHED state on BEGIN condition or from any other state if | |
452 | * port was unselected */ | |
453 | if (SM_FLAG(port, BEGIN) || | |
454 | port->selected == UNSELECTED || (port->selected == STANDBY && | |
455 | (port->actor_state & state_mask) != 0)) { | |
456 | /* detach mux from aggregator */ | |
457 | port->actor_state &= ~state_mask; | |
458 | /* Set ntt to true if BEGIN condition or transition from any other state | |
459 | * which is indicated that wait_while_timer was started */ | |
460 | if (SM_FLAG(port, BEGIN) || | |
461 | !timer_is_stopped(&port->wait_while_timer)) { | |
462 | SM_FLAG_SET(port, NTT); | |
463 | MODE4_DEBUG("-> DETACHED\n"); | |
464 | } | |
465 | timer_cancel(&port->wait_while_timer); | |
466 | } | |
467 | ||
468 | if (timer_is_stopped(&port->wait_while_timer)) { | |
469 | if (port->selected == SELECTED || port->selected == STANDBY) { | |
470 | timer_set(&port->wait_while_timer, | |
471 | internals->mode4.aggregate_wait_timeout); | |
472 | ||
473 | MODE4_DEBUG("DETACHED -> WAITING\n"); | |
474 | } | |
475 | /* Waiting state entered */ | |
476 | return; | |
477 | } | |
478 | ||
479 | /* Transit next state if port is ready */ | |
480 | if (!timer_is_expired(&port->wait_while_timer)) | |
481 | return; | |
482 | ||
483 | if ((ACTOR_STATE(port, DISTRIBUTING) || ACTOR_STATE(port, COLLECTING)) && | |
484 | !PARTNER_STATE(port, SYNCHRONIZATION)) { | |
485 | /* If in COLLECTING or DISTRIBUTING state and partner becomes out of | |
486 | * sync transit to ATACHED state. */ | |
487 | ACTOR_STATE_CLR(port, DISTRIBUTING); | |
488 | ACTOR_STATE_CLR(port, COLLECTING); | |
489 | /* Clear actor sync to activate transit ATACHED in condition bellow */ | |
490 | ACTOR_STATE_CLR(port, SYNCHRONIZATION); | |
491 | MODE4_DEBUG("Out of sync -> ATTACHED\n"); | |
492 | } | |
493 | ||
494 | if (!ACTOR_STATE(port, SYNCHRONIZATION)) { | |
495 | /* attach mux to aggregator */ | |
496 | RTE_ASSERT((port->actor_state & (STATE_COLLECTING | | |
497 | STATE_DISTRIBUTING)) == 0); | |
498 | ||
499 | ACTOR_STATE_SET(port, SYNCHRONIZATION); | |
500 | SM_FLAG_SET(port, NTT); | |
501 | MODE4_DEBUG("ATTACHED Entered\n"); | |
502 | } else if (!ACTOR_STATE(port, COLLECTING)) { | |
503 | /* Start collecting if in sync */ | |
504 | if (PARTNER_STATE(port, SYNCHRONIZATION)) { | |
505 | MODE4_DEBUG("ATTACHED -> COLLECTING\n"); | |
506 | ACTOR_STATE_SET(port, COLLECTING); | |
507 | SM_FLAG_SET(port, NTT); | |
508 | } | |
509 | } else if (ACTOR_STATE(port, COLLECTING)) { | |
510 | /* Check if partner is in COLLECTING state. If so this port can | |
511 | * distribute frames to it */ | |
512 | if (!ACTOR_STATE(port, DISTRIBUTING)) { | |
513 | if (PARTNER_STATE(port, COLLECTING)) { | |
514 | /* Enable DISTRIBUTING if partner is collecting */ | |
515 | ACTOR_STATE_SET(port, DISTRIBUTING); | |
516 | SM_FLAG_SET(port, NTT); | |
517 | MODE4_DEBUG("COLLECTING -> DISTRIBUTING\n"); | |
11fdf7f2 TL |
518 | RTE_BOND_LOG(INFO, |
519 | "Bond %u: slave id %u distributing started.", | |
7c673cae FG |
520 | internals->port_id, slave_id); |
521 | } | |
522 | } else { | |
523 | if (!PARTNER_STATE(port, COLLECTING)) { | |
524 | /* Disable DISTRIBUTING (enter COLLECTING state) if partner | |
525 | * is not collecting */ | |
526 | ACTOR_STATE_CLR(port, DISTRIBUTING); | |
527 | SM_FLAG_SET(port, NTT); | |
528 | MODE4_DEBUG("DISTRIBUTING -> COLLECTING\n"); | |
11fdf7f2 TL |
529 | RTE_BOND_LOG(INFO, |
530 | "Bond %u: slave id %u distributing stopped.", | |
7c673cae FG |
531 | internals->port_id, slave_id); |
532 | } | |
533 | } | |
534 | } | |
535 | } | |
536 | ||
537 | /** | |
538 | * Function handles transmit state machine. | |
539 | * | |
540 | * Function implements Transmit Machine from point 5.4.16 in 802.1AX | |
541 | * documentation. | |
542 | * | |
543 | * @param port | |
544 | */ | |
545 | static void | |
11fdf7f2 | 546 | tx_machine(struct bond_dev_private *internals, uint16_t slave_id) |
7c673cae | 547 | { |
9f95a23c | 548 | struct port *agg, *port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
549 | |
550 | struct rte_mbuf *lacp_pkt = NULL; | |
551 | struct lacpdu_header *hdr; | |
552 | struct lacpdu *lacpdu; | |
553 | ||
554 | /* If periodic timer is not running periodic machine is in NO PERIODIC and | |
555 | * according to 802.3ax standard tx machine should not transmit any frames | |
556 | * and set ntt to false. */ | |
557 | if (timer_is_stopped(&port->periodic_timer)) | |
558 | SM_FLAG_CLR(port, NTT); | |
559 | ||
560 | if (!SM_FLAG(port, NTT)) | |
561 | return; | |
562 | ||
563 | if (!timer_is_expired(&port->tx_machine_timer)) | |
564 | return; | |
565 | ||
566 | lacp_pkt = rte_pktmbuf_alloc(port->mbuf_pool); | |
567 | if (lacp_pkt == NULL) { | |
11fdf7f2 | 568 | RTE_BOND_LOG(ERR, "Failed to allocate LACP packet from pool"); |
7c673cae FG |
569 | return; |
570 | } | |
571 | ||
572 | lacp_pkt->data_len = sizeof(*hdr); | |
573 | lacp_pkt->pkt_len = sizeof(*hdr); | |
574 | ||
575 | hdr = rte_pktmbuf_mtod(lacp_pkt, struct lacpdu_header *); | |
576 | ||
577 | /* Source and destination MAC */ | |
578 | ether_addr_copy(&lacp_mac_addr, &hdr->eth_hdr.d_addr); | |
579 | rte_eth_macaddr_get(slave_id, &hdr->eth_hdr.s_addr); | |
580 | hdr->eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_SLOW); | |
581 | ||
582 | lacpdu = &hdr->lacpdu; | |
583 | memset(lacpdu, 0, sizeof(*lacpdu)); | |
584 | ||
585 | /* Initialize LACP part */ | |
586 | lacpdu->subtype = SLOW_SUBTYPE_LACP; | |
587 | lacpdu->version_number = 1; | |
588 | ||
589 | /* ACTOR */ | |
590 | lacpdu->actor.tlv_type_info = TLV_TYPE_ACTOR_INFORMATION; | |
591 | lacpdu->actor.info_length = sizeof(struct lacpdu_actor_partner_params); | |
592 | memcpy(&hdr->lacpdu.actor.port_params, &port->actor, | |
593 | sizeof(port->actor)); | |
9f95a23c | 594 | agg = &bond_mode_8023ad_ports[port->aggregator_port_id]; |
7c673cae FG |
595 | ether_addr_copy(&agg->actor.system, &hdr->lacpdu.actor.port_params.system); |
596 | lacpdu->actor.state = port->actor_state; | |
597 | ||
598 | /* PARTNER */ | |
599 | lacpdu->partner.tlv_type_info = TLV_TYPE_PARTNER_INFORMATION; | |
600 | lacpdu->partner.info_length = sizeof(struct lacpdu_actor_partner_params); | |
601 | memcpy(&lacpdu->partner.port_params, &port->partner, | |
602 | sizeof(struct port_params)); | |
603 | lacpdu->partner.state = port->partner_state; | |
604 | ||
605 | /* Other fields */ | |
606 | lacpdu->tlv_type_collector_info = TLV_TYPE_COLLECTOR_INFORMATION; | |
607 | lacpdu->collector_info_length = 0x10; | |
608 | lacpdu->collector_max_delay = 0; | |
609 | ||
610 | lacpdu->tlv_type_terminator = TLV_TYPE_TERMINATOR_INFORMATION; | |
611 | lacpdu->terminator_length = 0; | |
612 | ||
11fdf7f2 TL |
613 | MODE4_DEBUG("Sending LACP frame\n"); |
614 | BOND_PRINT_LACP(lacpdu); | |
615 | ||
616 | if (internals->mode4.dedicated_queues.enabled == 0) { | |
617 | int retval = rte_ring_enqueue(port->tx_ring, lacp_pkt); | |
618 | if (retval != 0) { | |
619 | /* If TX ring full, drop packet and free message. | |
620 | Retransmission will happen in next function call. */ | |
621 | rte_pktmbuf_free(lacp_pkt); | |
622 | set_warning_flags(port, WRN_TX_QUEUE_FULL); | |
623 | return; | |
624 | } | |
625 | } else { | |
626 | uint16_t pkts_sent = rte_eth_tx_burst(slave_id, | |
627 | internals->mode4.dedicated_queues.tx_qid, | |
628 | &lacp_pkt, 1); | |
629 | if (pkts_sent != 1) { | |
630 | rte_pktmbuf_free(lacp_pkt); | |
631 | set_warning_flags(port, WRN_TX_QUEUE_FULL); | |
632 | return; | |
633 | } | |
7c673cae FG |
634 | } |
635 | ||
7c673cae FG |
636 | |
637 | timer_set(&port->tx_machine_timer, internals->mode4.tx_period_timeout); | |
638 | SM_FLAG_CLR(port, NTT); | |
639 | } | |
640 | ||
11fdf7f2 TL |
641 | static uint8_t |
642 | max_index(uint64_t *a, int n) | |
643 | { | |
644 | if (n <= 0) | |
645 | return -1; | |
646 | ||
647 | int i, max_i = 0; | |
648 | uint64_t max = a[0]; | |
649 | ||
650 | for (i = 1; i < n; ++i) { | |
651 | if (a[i] > max) { | |
652 | max = a[i]; | |
653 | max_i = i; | |
654 | } | |
655 | } | |
656 | ||
657 | return max_i; | |
658 | } | |
659 | ||
7c673cae FG |
660 | /** |
661 | * Function assigns port to aggregator. | |
662 | * | |
663 | * @param bond_dev_private Pointer to bond_dev_private structure. | |
664 | * @param port_pos Port to assign. | |
665 | */ | |
666 | static void | |
9f95a23c | 667 | selection_logic(struct bond_dev_private *internals, uint16_t slave_id) |
7c673cae FG |
668 | { |
669 | struct port *agg, *port; | |
11fdf7f2 TL |
670 | uint16_t slaves_count, new_agg_id, i, j = 0; |
671 | uint16_t *slaves; | |
672 | uint64_t agg_bandwidth[8] = {0}; | |
673 | uint64_t agg_count[8] = {0}; | |
674 | uint16_t default_slave = 0; | |
675 | uint8_t mode_count_id, mode_band_id; | |
676 | struct rte_eth_link link_info; | |
7c673cae FG |
677 | |
678 | slaves = internals->active_slaves; | |
679 | slaves_count = internals->active_slave_count; | |
9f95a23c | 680 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
681 | |
682 | /* Search for aggregator suitable for this port */ | |
683 | for (i = 0; i < slaves_count; ++i) { | |
9f95a23c | 684 | agg = &bond_mode_8023ad_ports[slaves[i]]; |
7c673cae FG |
685 | /* Skip ports that are not aggreagators */ |
686 | if (agg->aggregator_port_id != slaves[i]) | |
687 | continue; | |
688 | ||
11fdf7f2 TL |
689 | agg_count[agg->aggregator_port_id] += 1; |
690 | rte_eth_link_get_nowait(slaves[i], &link_info); | |
691 | agg_bandwidth[agg->aggregator_port_id] += link_info.link_speed; | |
692 | ||
7c673cae FG |
693 | /* Actors system ID is not checked since all slave device have the same |
694 | * ID (MAC address). */ | |
695 | if ((agg->actor.key == port->actor.key && | |
696 | agg->partner.system_priority == port->partner.system_priority && | |
697 | is_same_ether_addr(&agg->partner.system, &port->partner.system) == 1 | |
698 | && (agg->partner.key == port->partner.key)) && | |
699 | is_zero_ether_addr(&port->partner.system) != 1 && | |
700 | (agg->actor.key & | |
701 | rte_cpu_to_be_16(BOND_LINK_FULL_DUPLEX_KEY)) != 0) { | |
702 | ||
11fdf7f2 TL |
703 | if (j == 0) |
704 | default_slave = i; | |
705 | j++; | |
7c673cae FG |
706 | } |
707 | } | |
708 | ||
11fdf7f2 TL |
709 | switch (internals->mode4.agg_selection) { |
710 | case AGG_COUNT: | |
711 | mode_count_id = max_index( | |
712 | (uint64_t *)agg_count, slaves_count); | |
713 | new_agg_id = mode_count_id; | |
714 | break; | |
715 | case AGG_BANDWIDTH: | |
716 | mode_band_id = max_index( | |
717 | (uint64_t *)agg_bandwidth, slaves_count); | |
718 | new_agg_id = mode_band_id; | |
719 | break; | |
720 | case AGG_STABLE: | |
721 | if (default_slave == slaves_count) | |
722 | new_agg_id = slave_id; | |
723 | else | |
724 | new_agg_id = slaves[default_slave]; | |
725 | break; | |
726 | default: | |
727 | if (default_slave == slaves_count) | |
728 | new_agg_id = slave_id; | |
729 | else | |
730 | new_agg_id = slaves[default_slave]; | |
731 | break; | |
732 | } | |
7c673cae FG |
733 | |
734 | if (new_agg_id != port->aggregator_port_id) { | |
735 | port->aggregator_port_id = new_agg_id; | |
736 | ||
737 | MODE4_DEBUG("-> SELECTED: ID=%3u\n" | |
738 | "\t%s aggregator ID=%3u\n", | |
739 | port->aggregator_port_id, | |
740 | port->aggregator_port_id == slave_id ? | |
741 | "aggregator not found, using default" : "aggregator found", | |
742 | port->aggregator_port_id); | |
743 | } | |
744 | ||
745 | port->selected = SELECTED; | |
746 | } | |
747 | ||
748 | /* Function maps DPDK speed to bonding speed stored in key field */ | |
749 | static uint16_t | |
750 | link_speed_key(uint16_t speed) { | |
751 | uint16_t key_speed; | |
752 | ||
753 | switch (speed) { | |
754 | case ETH_SPEED_NUM_NONE: | |
755 | key_speed = 0x00; | |
756 | break; | |
757 | case ETH_SPEED_NUM_10M: | |
758 | key_speed = BOND_LINK_SPEED_KEY_10M; | |
759 | break; | |
760 | case ETH_SPEED_NUM_100M: | |
761 | key_speed = BOND_LINK_SPEED_KEY_100M; | |
762 | break; | |
763 | case ETH_SPEED_NUM_1G: | |
764 | key_speed = BOND_LINK_SPEED_KEY_1000M; | |
765 | break; | |
766 | case ETH_SPEED_NUM_10G: | |
767 | key_speed = BOND_LINK_SPEED_KEY_10G; | |
768 | break; | |
769 | case ETH_SPEED_NUM_20G: | |
770 | key_speed = BOND_LINK_SPEED_KEY_20G; | |
771 | break; | |
772 | case ETH_SPEED_NUM_40G: | |
773 | key_speed = BOND_LINK_SPEED_KEY_40G; | |
774 | break; | |
775 | default: | |
776 | /* Unknown speed*/ | |
777 | key_speed = 0xFFFF; | |
778 | } | |
779 | ||
780 | return key_speed; | |
781 | } | |
782 | ||
11fdf7f2 | 783 | static void |
9f95a23c | 784 | rx_machine_update(struct bond_dev_private *internals, uint16_t slave_id, |
11fdf7f2 TL |
785 | struct rte_mbuf *lacp_pkt) { |
786 | struct lacpdu_header *lacp; | |
9f95a23c | 787 | struct lacpdu_actor_partner_params *partner; |
11fdf7f2 TL |
788 | |
789 | if (lacp_pkt != NULL) { | |
790 | lacp = rte_pktmbuf_mtod(lacp_pkt, struct lacpdu_header *); | |
791 | RTE_ASSERT(lacp->lacpdu.subtype == SLOW_SUBTYPE_LACP); | |
792 | ||
9f95a23c TL |
793 | partner = &lacp->lacpdu.partner; |
794 | if (is_same_ether_addr(&partner->port_params.system, | |
795 | &internals->mode4.mac_addr)) { | |
796 | /* This LACP frame is sending to the bonding port | |
797 | * so pass it to rx_machine. | |
798 | */ | |
799 | rx_machine(internals, slave_id, &lacp->lacpdu); | |
800 | } | |
11fdf7f2 TL |
801 | rte_pktmbuf_free(lacp_pkt); |
802 | } else | |
803 | rx_machine(internals, slave_id, NULL); | |
804 | } | |
805 | ||
7c673cae FG |
806 | static void |
807 | bond_mode_8023ad_periodic_cb(void *arg) | |
808 | { | |
809 | struct rte_eth_dev *bond_dev = arg; | |
810 | struct bond_dev_private *internals = bond_dev->data->dev_private; | |
811 | struct port *port; | |
812 | struct rte_eth_link link_info; | |
813 | struct ether_addr slave_addr; | |
11fdf7f2 | 814 | struct rte_mbuf *lacp_pkt = NULL; |
9f95a23c TL |
815 | uint16_t slave_id; |
816 | uint16_t i; | |
7c673cae FG |
817 | |
818 | ||
819 | /* Update link status on each port */ | |
820 | for (i = 0; i < internals->active_slave_count; i++) { | |
821 | uint16_t key; | |
822 | ||
823 | slave_id = internals->active_slaves[i]; | |
11fdf7f2 | 824 | rte_eth_link_get_nowait(slave_id, &link_info); |
7c673cae FG |
825 | rte_eth_macaddr_get(slave_id, &slave_addr); |
826 | ||
827 | if (link_info.link_status != 0) { | |
828 | key = link_speed_key(link_info.link_speed) << 1; | |
829 | if (link_info.link_duplex == ETH_LINK_FULL_DUPLEX) | |
830 | key |= BOND_LINK_FULL_DUPLEX_KEY; | |
831 | } else | |
832 | key = 0; | |
833 | ||
9f95a23c | 834 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
835 | |
836 | key = rte_cpu_to_be_16(key); | |
837 | if (key != port->actor.key) { | |
838 | if (!(key & rte_cpu_to_be_16(BOND_LINK_FULL_DUPLEX_KEY))) | |
839 | set_warning_flags(port, WRN_NOT_LACP_CAPABLE); | |
840 | ||
841 | port->actor.key = key; | |
842 | SM_FLAG_SET(port, NTT); | |
843 | } | |
844 | ||
845 | if (!is_same_ether_addr(&port->actor.system, &slave_addr)) { | |
846 | ether_addr_copy(&slave_addr, &port->actor.system); | |
847 | if (port->aggregator_port_id == slave_id) | |
848 | SM_FLAG_SET(port, NTT); | |
849 | } | |
850 | } | |
851 | ||
852 | for (i = 0; i < internals->active_slave_count; i++) { | |
853 | slave_id = internals->active_slaves[i]; | |
9f95a23c | 854 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
855 | |
856 | if ((port->actor.key & | |
857 | rte_cpu_to_be_16(BOND_LINK_FULL_DUPLEX_KEY)) == 0) { | |
858 | ||
859 | SM_FLAG_SET(port, BEGIN); | |
860 | ||
861 | /* LACP is disabled on half duples or link is down */ | |
862 | if (SM_FLAG(port, LACP_ENABLED)) { | |
863 | /* If port was enabled set it to BEGIN state */ | |
864 | SM_FLAG_CLR(port, LACP_ENABLED); | |
865 | ACTOR_STATE_CLR(port, DISTRIBUTING); | |
866 | ACTOR_STATE_CLR(port, COLLECTING); | |
867 | } | |
868 | ||
869 | /* Skip this port processing */ | |
870 | continue; | |
871 | } | |
872 | ||
873 | SM_FLAG_SET(port, LACP_ENABLED); | |
874 | ||
11fdf7f2 TL |
875 | if (internals->mode4.dedicated_queues.enabled == 0) { |
876 | /* Find LACP packet to this port. Do not check subtype, | |
877 | * it is done in function that queued packet | |
878 | */ | |
879 | int retval = rte_ring_dequeue(port->rx_ring, | |
880 | (void **)&lacp_pkt); | |
7c673cae | 881 | |
11fdf7f2 TL |
882 | if (retval != 0) |
883 | lacp_pkt = NULL; | |
7c673cae | 884 | |
11fdf7f2 TL |
885 | rx_machine_update(internals, slave_id, lacp_pkt); |
886 | } else { | |
887 | uint16_t rx_count = rte_eth_rx_burst(slave_id, | |
888 | internals->mode4.dedicated_queues.rx_qid, | |
889 | &lacp_pkt, 1); | |
890 | ||
891 | if (rx_count == 1) | |
892 | bond_mode_8023ad_handle_slow_pkt(internals, | |
893 | slave_id, lacp_pkt); | |
894 | else | |
895 | rx_machine_update(internals, slave_id, NULL); | |
896 | } | |
7c673cae FG |
897 | |
898 | periodic_machine(internals, slave_id); | |
899 | mux_machine(internals, slave_id); | |
900 | tx_machine(internals, slave_id); | |
901 | selection_logic(internals, slave_id); | |
902 | ||
903 | SM_FLAG_CLR(port, BEGIN); | |
904 | show_warnings(slave_id); | |
905 | } | |
906 | ||
907 | rte_eal_alarm_set(internals->mode4.update_timeout_us, | |
908 | bond_mode_8023ad_periodic_cb, arg); | |
909 | } | |
910 | ||
911 | void | |
11fdf7f2 TL |
912 | bond_mode_8023ad_activate_slave(struct rte_eth_dev *bond_dev, |
913 | uint16_t slave_id) | |
7c673cae FG |
914 | { |
915 | struct bond_dev_private *internals = bond_dev->data->dev_private; | |
916 | ||
9f95a23c | 917 | struct port *port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
918 | struct port_params initial = { |
919 | .system = { { 0 } }, | |
920 | .system_priority = rte_cpu_to_be_16(0xFFFF), | |
921 | .key = rte_cpu_to_be_16(BOND_LINK_FULL_DUPLEX_KEY), | |
922 | .port_priority = rte_cpu_to_be_16(0x00FF), | |
923 | .port_number = 0, | |
924 | }; | |
925 | ||
926 | char mem_name[RTE_ETH_NAME_MAX_LEN]; | |
927 | int socket_id; | |
928 | unsigned element_size; | |
929 | uint32_t total_tx_desc; | |
930 | struct bond_tx_queue *bd_tx_q; | |
931 | uint16_t q_id; | |
932 | ||
933 | /* Given slave mus not be in active list */ | |
934 | RTE_ASSERT(find_slave_by_id(internals->active_slaves, | |
935 | internals->active_slave_count, slave_id) == internals->active_slave_count); | |
936 | RTE_SET_USED(internals); /* used only for assert when enabled */ | |
937 | ||
938 | memcpy(&port->actor, &initial, sizeof(struct port_params)); | |
939 | /* Standard requires that port ID must be grater than 0. | |
940 | * Add 1 do get corresponding port_number */ | |
11fdf7f2 | 941 | port->actor.port_number = rte_cpu_to_be_16(slave_id + 1); |
7c673cae FG |
942 | |
943 | memcpy(&port->partner, &initial, sizeof(struct port_params)); | |
944 | ||
945 | /* default states */ | |
946 | port->actor_state = STATE_AGGREGATION | STATE_LACP_ACTIVE | STATE_DEFAULTED; | |
11fdf7f2 | 947 | port->partner_state = STATE_LACP_ACTIVE | STATE_AGGREGATION; |
7c673cae FG |
948 | port->sm_flags = SM_FLAGS_BEGIN; |
949 | ||
950 | /* use this port as agregator */ | |
951 | port->aggregator_port_id = slave_id; | |
952 | rte_eth_promiscuous_enable(slave_id); | |
953 | ||
954 | timer_cancel(&port->warning_timer); | |
955 | ||
956 | if (port->mbuf_pool != NULL) | |
957 | return; | |
958 | ||
959 | RTE_ASSERT(port->rx_ring == NULL); | |
960 | RTE_ASSERT(port->tx_ring == NULL); | |
7c673cae | 961 | |
11fdf7f2 TL |
962 | socket_id = rte_eth_dev_socket_id(slave_id); |
963 | if (socket_id == (int)LCORE_ID_ANY) | |
964 | socket_id = rte_socket_id(); | |
965 | ||
966 | element_size = sizeof(struct slow_protocol_frame) + | |
967 | RTE_PKTMBUF_HEADROOM; | |
7c673cae FG |
968 | |
969 | /* The size of the mempool should be at least: | |
970 | * the sum of the TX descriptors + BOND_MODE_8023AX_SLAVE_TX_PKTS */ | |
971 | total_tx_desc = BOND_MODE_8023AX_SLAVE_TX_PKTS; | |
972 | for (q_id = 0; q_id < bond_dev->data->nb_tx_queues; q_id++) { | |
973 | bd_tx_q = (struct bond_tx_queue*)bond_dev->data->tx_queues[q_id]; | |
974 | total_tx_desc += bd_tx_q->nb_tx_desc; | |
975 | } | |
976 | ||
977 | snprintf(mem_name, RTE_DIM(mem_name), "slave_port%u_pool", slave_id); | |
11fdf7f2 TL |
978 | port->mbuf_pool = rte_pktmbuf_pool_create(mem_name, total_tx_desc, |
979 | RTE_MEMPOOL_CACHE_MAX_SIZE >= 32 ? | |
980 | 32 : RTE_MEMPOOL_CACHE_MAX_SIZE, | |
981 | 0, element_size, socket_id); | |
7c673cae | 982 | |
11fdf7f2 | 983 | /* Any memory allocation failure in initialization is critical because |
7c673cae FG |
984 | * resources can't be free, so reinitialization is impossible. */ |
985 | if (port->mbuf_pool == NULL) { | |
986 | rte_panic("Slave %u: Failed to create memory pool '%s': %s\n", | |
987 | slave_id, mem_name, rte_strerror(rte_errno)); | |
988 | } | |
989 | ||
990 | snprintf(mem_name, RTE_DIM(mem_name), "slave_%u_rx", slave_id); | |
991 | port->rx_ring = rte_ring_create(mem_name, | |
992 | rte_align32pow2(BOND_MODE_8023AX_SLAVE_RX_PKTS), socket_id, 0); | |
993 | ||
994 | if (port->rx_ring == NULL) { | |
995 | rte_panic("Slave %u: Failed to create rx ring '%s': %s\n", slave_id, | |
996 | mem_name, rte_strerror(rte_errno)); | |
997 | } | |
998 | ||
999 | /* TX ring is at least one pkt longer to make room for marker packet. */ | |
1000 | snprintf(mem_name, RTE_DIM(mem_name), "slave_%u_tx", slave_id); | |
1001 | port->tx_ring = rte_ring_create(mem_name, | |
1002 | rte_align32pow2(BOND_MODE_8023AX_SLAVE_TX_PKTS + 1), socket_id, 0); | |
1003 | ||
1004 | if (port->tx_ring == NULL) { | |
1005 | rte_panic("Slave %u: Failed to create tx ring '%s': %s\n", slave_id, | |
1006 | mem_name, rte_strerror(rte_errno)); | |
1007 | } | |
1008 | } | |
1009 | ||
1010 | int | |
11fdf7f2 TL |
1011 | bond_mode_8023ad_deactivate_slave(struct rte_eth_dev *bond_dev __rte_unused, |
1012 | uint16_t slave_id) | |
7c673cae | 1013 | { |
7c673cae | 1014 | void *pkt = NULL; |
11fdf7f2 TL |
1015 | struct port *port = NULL; |
1016 | uint8_t old_partner_state; | |
7c673cae | 1017 | |
9f95a23c | 1018 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae | 1019 | |
11fdf7f2 TL |
1020 | ACTOR_STATE_CLR(port, AGGREGATION); |
1021 | port->selected = UNSELECTED; | |
7c673cae | 1022 | |
11fdf7f2 TL |
1023 | old_partner_state = port->partner_state; |
1024 | record_default(port); | |
7c673cae | 1025 | |
11fdf7f2 TL |
1026 | /* If partner timeout state changes then disable timer */ |
1027 | if (!((old_partner_state ^ port->partner_state) & | |
1028 | STATE_LACP_SHORT_TIMEOUT)) | |
1029 | timer_cancel(&port->current_while_timer); | |
7c673cae | 1030 | |
11fdf7f2 TL |
1031 | PARTNER_STATE_CLR(port, AGGREGATION); |
1032 | ACTOR_STATE_CLR(port, EXPIRED); | |
7c673cae | 1033 | |
11fdf7f2 | 1034 | /* flush rx/tx rings */ |
7c673cae FG |
1035 | while (rte_ring_dequeue(port->rx_ring, &pkt) == 0) |
1036 | rte_pktmbuf_free((struct rte_mbuf *)pkt); | |
1037 | ||
1038 | while (rte_ring_dequeue(port->tx_ring, &pkt) == 0) | |
1039 | rte_pktmbuf_free((struct rte_mbuf *)pkt); | |
1040 | return 0; | |
1041 | } | |
1042 | ||
1043 | void | |
1044 | bond_mode_8023ad_mac_address_update(struct rte_eth_dev *bond_dev) | |
1045 | { | |
1046 | struct bond_dev_private *internals = bond_dev->data->dev_private; | |
1047 | struct ether_addr slave_addr; | |
1048 | struct port *slave, *agg_slave; | |
11fdf7f2 | 1049 | uint16_t slave_id, i, j; |
7c673cae FG |
1050 | |
1051 | bond_mode_8023ad_stop(bond_dev); | |
1052 | ||
1053 | for (i = 0; i < internals->active_slave_count; i++) { | |
1054 | slave_id = internals->active_slaves[i]; | |
9f95a23c | 1055 | slave = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
1056 | rte_eth_macaddr_get(slave_id, &slave_addr); |
1057 | ||
1058 | if (is_same_ether_addr(&slave_addr, &slave->actor.system)) | |
1059 | continue; | |
1060 | ||
1061 | ether_addr_copy(&slave_addr, &slave->actor.system); | |
1062 | /* Do nothing if this port is not an aggregator. In other case | |
1063 | * Set NTT flag on every port that use this aggregator. */ | |
1064 | if (slave->aggregator_port_id != slave_id) | |
1065 | continue; | |
1066 | ||
1067 | for (j = 0; j < internals->active_slave_count; j++) { | |
9f95a23c | 1068 | agg_slave = &bond_mode_8023ad_ports[internals->active_slaves[j]]; |
7c673cae FG |
1069 | if (agg_slave->aggregator_port_id == slave_id) |
1070 | SM_FLAG_SET(agg_slave, NTT); | |
1071 | } | |
1072 | } | |
1073 | ||
1074 | if (bond_dev->data->dev_started) | |
1075 | bond_mode_8023ad_start(bond_dev); | |
1076 | } | |
1077 | ||
1078 | static void | |
1079 | bond_mode_8023ad_conf_get(struct rte_eth_dev *dev, | |
1080 | struct rte_eth_bond_8023ad_conf *conf) | |
1081 | { | |
1082 | struct bond_dev_private *internals = dev->data->dev_private; | |
1083 | struct mode8023ad_private *mode4 = &internals->mode4; | |
1084 | uint64_t ms_ticks = rte_get_tsc_hz() / 1000; | |
1085 | ||
1086 | conf->fast_periodic_ms = mode4->fast_periodic_timeout / ms_ticks; | |
1087 | conf->slow_periodic_ms = mode4->slow_periodic_timeout / ms_ticks; | |
1088 | conf->short_timeout_ms = mode4->short_timeout / ms_ticks; | |
1089 | conf->long_timeout_ms = mode4->long_timeout / ms_ticks; | |
1090 | conf->aggregate_wait_timeout_ms = mode4->aggregate_wait_timeout / ms_ticks; | |
1091 | conf->tx_period_ms = mode4->tx_period_timeout / ms_ticks; | |
1092 | conf->update_timeout_ms = mode4->update_timeout_us / 1000; | |
1093 | conf->rx_marker_period_ms = mode4->rx_marker_timeout / ms_ticks; | |
7c673cae | 1094 | conf->slowrx_cb = mode4->slowrx_cb; |
11fdf7f2 | 1095 | conf->agg_selection = mode4->agg_selection; |
7c673cae FG |
1096 | } |
1097 | ||
1098 | static void | |
1099 | bond_mode_8023ad_conf_get_default(struct rte_eth_bond_8023ad_conf *conf) | |
1100 | { | |
1101 | conf->fast_periodic_ms = BOND_8023AD_FAST_PERIODIC_MS; | |
1102 | conf->slow_periodic_ms = BOND_8023AD_SLOW_PERIODIC_MS; | |
1103 | conf->short_timeout_ms = BOND_8023AD_SHORT_TIMEOUT_MS; | |
1104 | conf->long_timeout_ms = BOND_8023AD_LONG_TIMEOUT_MS; | |
1105 | conf->aggregate_wait_timeout_ms = BOND_8023AD_AGGREGATE_WAIT_TIMEOUT_MS; | |
1106 | conf->tx_period_ms = BOND_8023AD_TX_MACHINE_PERIOD_MS; | |
1107 | conf->rx_marker_period_ms = BOND_8023AD_RX_MARKER_PERIOD_MS; | |
1108 | conf->update_timeout_ms = BOND_MODE_8023AX_UPDATE_TIMEOUT_MS; | |
1109 | conf->slowrx_cb = NULL; | |
11fdf7f2 | 1110 | conf->agg_selection = AGG_STABLE; |
7c673cae FG |
1111 | } |
1112 | ||
1113 | static void | |
1114 | bond_mode_8023ad_conf_assign(struct mode8023ad_private *mode4, | |
1115 | struct rte_eth_bond_8023ad_conf *conf) | |
1116 | { | |
1117 | uint64_t ms_ticks = rte_get_tsc_hz() / 1000; | |
1118 | ||
1119 | mode4->fast_periodic_timeout = conf->fast_periodic_ms * ms_ticks; | |
1120 | mode4->slow_periodic_timeout = conf->slow_periodic_ms * ms_ticks; | |
1121 | mode4->short_timeout = conf->short_timeout_ms * ms_ticks; | |
1122 | mode4->long_timeout = conf->long_timeout_ms * ms_ticks; | |
1123 | mode4->aggregate_wait_timeout = conf->aggregate_wait_timeout_ms * ms_ticks; | |
1124 | mode4->tx_period_timeout = conf->tx_period_ms * ms_ticks; | |
1125 | mode4->rx_marker_timeout = conf->rx_marker_period_ms * ms_ticks; | |
1126 | mode4->update_timeout_us = conf->update_timeout_ms * 1000; | |
7c673cae | 1127 | |
11fdf7f2 TL |
1128 | mode4->dedicated_queues.enabled = 0; |
1129 | mode4->dedicated_queues.rx_qid = UINT16_MAX; | |
1130 | mode4->dedicated_queues.tx_qid = UINT16_MAX; | |
7c673cae FG |
1131 | } |
1132 | ||
7c673cae FG |
1133 | void |
1134 | bond_mode_8023ad_setup(struct rte_eth_dev *dev, | |
1135 | struct rte_eth_bond_8023ad_conf *conf) | |
1136 | { | |
1137 | struct rte_eth_bond_8023ad_conf def_conf; | |
1138 | struct bond_dev_private *internals = dev->data->dev_private; | |
1139 | struct mode8023ad_private *mode4 = &internals->mode4; | |
1140 | ||
1141 | if (conf == NULL) { | |
1142 | conf = &def_conf; | |
1143 | bond_mode_8023ad_conf_get_default(conf); | |
1144 | } | |
1145 | ||
1146 | bond_mode_8023ad_stop(dev); | |
1147 | bond_mode_8023ad_conf_assign(mode4, conf); | |
1148 | mode4->slowrx_cb = conf->slowrx_cb; | |
11fdf7f2 | 1149 | mode4->agg_selection = AGG_STABLE; |
7c673cae FG |
1150 | |
1151 | if (dev->data->dev_started) | |
1152 | bond_mode_8023ad_start(dev); | |
1153 | } | |
1154 | ||
1155 | int | |
1156 | bond_mode_8023ad_enable(struct rte_eth_dev *bond_dev) | |
1157 | { | |
1158 | struct bond_dev_private *internals = bond_dev->data->dev_private; | |
9f95a23c | 1159 | uint16_t i; |
7c673cae FG |
1160 | |
1161 | for (i = 0; i < internals->active_slave_count; i++) | |
11fdf7f2 TL |
1162 | bond_mode_8023ad_activate_slave(bond_dev, |
1163 | internals->active_slaves[i]); | |
7c673cae FG |
1164 | |
1165 | return 0; | |
1166 | } | |
1167 | ||
1168 | int | |
1169 | bond_mode_8023ad_start(struct rte_eth_dev *bond_dev) | |
1170 | { | |
1171 | struct bond_dev_private *internals = bond_dev->data->dev_private; | |
1172 | struct mode8023ad_private *mode4 = &internals->mode4; | |
1173 | static const uint64_t us = BOND_MODE_8023AX_UPDATE_TIMEOUT_MS * 1000; | |
1174 | ||
9f95a23c | 1175 | rte_eth_macaddr_get(internals->port_id, &mode4->mac_addr); |
7c673cae FG |
1176 | if (mode4->slowrx_cb) |
1177 | return rte_eal_alarm_set(us, &bond_mode_8023ad_ext_periodic_cb, | |
1178 | bond_dev); | |
1179 | ||
1180 | return rte_eal_alarm_set(us, &bond_mode_8023ad_periodic_cb, bond_dev); | |
1181 | } | |
1182 | ||
1183 | void | |
1184 | bond_mode_8023ad_stop(struct rte_eth_dev *bond_dev) | |
1185 | { | |
1186 | struct bond_dev_private *internals = bond_dev->data->dev_private; | |
1187 | struct mode8023ad_private *mode4 = &internals->mode4; | |
1188 | ||
1189 | if (mode4->slowrx_cb) { | |
1190 | rte_eal_alarm_cancel(&bond_mode_8023ad_ext_periodic_cb, | |
1191 | bond_dev); | |
1192 | return; | |
1193 | } | |
1194 | rte_eal_alarm_cancel(&bond_mode_8023ad_periodic_cb, bond_dev); | |
1195 | } | |
1196 | ||
1197 | void | |
1198 | bond_mode_8023ad_handle_slow_pkt(struct bond_dev_private *internals, | |
11fdf7f2 | 1199 | uint16_t slave_id, struct rte_mbuf *pkt) |
7c673cae FG |
1200 | { |
1201 | struct mode8023ad_private *mode4 = &internals->mode4; | |
9f95a23c | 1202 | struct port *port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
1203 | struct marker_header *m_hdr; |
1204 | uint64_t marker_timer, old_marker_timer; | |
1205 | int retval; | |
1206 | uint8_t wrn, subtype; | |
1207 | /* If packet is a marker, we send response now by reusing given packet | |
1208 | * and update only source MAC, destination MAC is multicast so don't | |
1209 | * update it. Other frames will be handled later by state machines */ | |
1210 | subtype = rte_pktmbuf_mtod(pkt, | |
1211 | struct slow_protocol_frame *)->slow_protocol.subtype; | |
1212 | ||
1213 | if (subtype == SLOW_SUBTYPE_MARKER) { | |
1214 | m_hdr = rte_pktmbuf_mtod(pkt, struct marker_header *); | |
1215 | ||
1216 | if (likely(m_hdr->marker.tlv_type_marker != MARKER_TLV_TYPE_INFO)) { | |
1217 | wrn = WRN_UNKNOWN_MARKER_TYPE; | |
1218 | goto free_out; | |
1219 | } | |
1220 | ||
1221 | /* Setup marker timer. Do it in loop in case concurrent access. */ | |
1222 | do { | |
1223 | old_marker_timer = port->rx_marker_timer; | |
1224 | if (!timer_is_expired(&old_marker_timer)) { | |
1225 | wrn = WRN_RX_MARKER_TO_FAST; | |
1226 | goto free_out; | |
1227 | } | |
1228 | ||
1229 | timer_set(&marker_timer, mode4->rx_marker_timeout); | |
1230 | retval = rte_atomic64_cmpset(&port->rx_marker_timer, | |
1231 | old_marker_timer, marker_timer); | |
1232 | } while (unlikely(retval == 0)); | |
1233 | ||
1234 | m_hdr->marker.tlv_type_marker = MARKER_TLV_TYPE_RESP; | |
1235 | rte_eth_macaddr_get(slave_id, &m_hdr->eth_hdr.s_addr); | |
1236 | ||
11fdf7f2 TL |
1237 | if (internals->mode4.dedicated_queues.enabled == 0) { |
1238 | int retval = rte_ring_enqueue(port->tx_ring, pkt); | |
1239 | if (retval != 0) { | |
1240 | /* reset timer */ | |
1241 | port->rx_marker_timer = 0; | |
1242 | wrn = WRN_TX_QUEUE_FULL; | |
1243 | goto free_out; | |
1244 | } | |
1245 | } else { | |
1246 | /* Send packet directly to the slow queue */ | |
1247 | uint16_t tx_count = rte_eth_tx_burst(slave_id, | |
1248 | internals->mode4.dedicated_queues.tx_qid, | |
1249 | &pkt, 1); | |
1250 | if (tx_count != 1) { | |
1251 | /* reset timer */ | |
1252 | port->rx_marker_timer = 0; | |
1253 | wrn = WRN_TX_QUEUE_FULL; | |
1254 | goto free_out; | |
1255 | } | |
7c673cae FG |
1256 | } |
1257 | } else if (likely(subtype == SLOW_SUBTYPE_LACP)) { | |
11fdf7f2 TL |
1258 | if (internals->mode4.dedicated_queues.enabled == 0) { |
1259 | int retval = rte_ring_enqueue(port->rx_ring, pkt); | |
1260 | if (retval != 0) { | |
1261 | /* If RX fing full free lacpdu message and drop packet */ | |
1262 | wrn = WRN_RX_QUEUE_FULL; | |
1263 | goto free_out; | |
1264 | } | |
1265 | } else | |
1266 | rx_machine_update(internals, slave_id, pkt); | |
7c673cae FG |
1267 | } else { |
1268 | wrn = WRN_UNKNOWN_SLOW_TYPE; | |
1269 | goto free_out; | |
1270 | } | |
1271 | ||
1272 | return; | |
1273 | ||
1274 | free_out: | |
1275 | set_warning_flags(port, wrn); | |
1276 | rte_pktmbuf_free(pkt); | |
1277 | } | |
1278 | ||
1279 | int | |
11fdf7f2 | 1280 | rte_eth_bond_8023ad_conf_get(uint16_t port_id, |
7c673cae FG |
1281 | struct rte_eth_bond_8023ad_conf *conf) |
1282 | { | |
1283 | struct rte_eth_dev *bond_dev; | |
1284 | ||
1285 | if (valid_bonded_port_id(port_id) != 0) | |
1286 | return -EINVAL; | |
1287 | ||
1288 | if (conf == NULL) | |
1289 | return -EINVAL; | |
1290 | ||
1291 | bond_dev = &rte_eth_devices[port_id]; | |
1292 | bond_mode_8023ad_conf_get(bond_dev, conf); | |
1293 | return 0; | |
1294 | } | |
7c673cae FG |
1295 | |
1296 | int | |
11fdf7f2 TL |
1297 | rte_eth_bond_8023ad_agg_selection_set(uint16_t port_id, |
1298 | enum rte_bond_8023ad_agg_selection agg_selection) | |
7c673cae FG |
1299 | { |
1300 | struct rte_eth_dev *bond_dev; | |
11fdf7f2 TL |
1301 | struct bond_dev_private *internals; |
1302 | struct mode8023ad_private *mode4; | |
1303 | ||
1304 | bond_dev = &rte_eth_devices[port_id]; | |
1305 | internals = bond_dev->data->dev_private; | |
7c673cae FG |
1306 | |
1307 | if (valid_bonded_port_id(port_id) != 0) | |
1308 | return -EINVAL; | |
11fdf7f2 | 1309 | if (internals->mode != 4) |
7c673cae FG |
1310 | return -EINVAL; |
1311 | ||
11fdf7f2 TL |
1312 | mode4 = &internals->mode4; |
1313 | if (agg_selection == AGG_COUNT || agg_selection == AGG_BANDWIDTH | |
1314 | || agg_selection == AGG_STABLE) | |
1315 | mode4->agg_selection = agg_selection; | |
7c673cae FG |
1316 | return 0; |
1317 | } | |
11fdf7f2 TL |
1318 | |
1319 | int rte_eth_bond_8023ad_agg_selection_get(uint16_t port_id) | |
1320 | { | |
1321 | struct rte_eth_dev *bond_dev; | |
1322 | struct bond_dev_private *internals; | |
1323 | struct mode8023ad_private *mode4; | |
1324 | ||
1325 | bond_dev = &rte_eth_devices[port_id]; | |
1326 | internals = bond_dev->data->dev_private; | |
1327 | ||
1328 | if (valid_bonded_port_id(port_id) != 0) | |
1329 | return -EINVAL; | |
1330 | if (internals->mode != 4) | |
1331 | return -EINVAL; | |
1332 | mode4 = &internals->mode4; | |
1333 | ||
1334 | return mode4->agg_selection; | |
1335 | } | |
1336 | ||
1337 | ||
7c673cae FG |
1338 | |
1339 | static int | |
11fdf7f2 | 1340 | bond_8023ad_setup_validate(uint16_t port_id, |
7c673cae FG |
1341 | struct rte_eth_bond_8023ad_conf *conf) |
1342 | { | |
1343 | if (valid_bonded_port_id(port_id) != 0) | |
1344 | return -EINVAL; | |
1345 | ||
1346 | if (conf != NULL) { | |
1347 | /* Basic sanity check */ | |
1348 | if (conf->slow_periodic_ms == 0 || | |
1349 | conf->fast_periodic_ms >= conf->slow_periodic_ms || | |
1350 | conf->long_timeout_ms == 0 || | |
1351 | conf->short_timeout_ms >= conf->long_timeout_ms || | |
1352 | conf->aggregate_wait_timeout_ms == 0 || | |
1353 | conf->tx_period_ms == 0 || | |
1354 | conf->rx_marker_period_ms == 0 || | |
1355 | conf->update_timeout_ms == 0) { | |
11fdf7f2 | 1356 | RTE_BOND_LOG(ERR, "given mode 4 configuration is invalid"); |
7c673cae FG |
1357 | return -EINVAL; |
1358 | } | |
1359 | } | |
1360 | ||
1361 | return 0; | |
1362 | } | |
1363 | ||
11fdf7f2 | 1364 | |
7c673cae | 1365 | int |
11fdf7f2 | 1366 | rte_eth_bond_8023ad_setup(uint16_t port_id, |
7c673cae FG |
1367 | struct rte_eth_bond_8023ad_conf *conf) |
1368 | { | |
1369 | struct rte_eth_dev *bond_dev; | |
1370 | int err; | |
1371 | ||
1372 | err = bond_8023ad_setup_validate(port_id, conf); | |
1373 | if (err != 0) | |
1374 | return err; | |
1375 | ||
1376 | bond_dev = &rte_eth_devices[port_id]; | |
11fdf7f2 | 1377 | bond_mode_8023ad_setup(bond_dev, conf); |
7c673cae FG |
1378 | |
1379 | return 0; | |
1380 | } | |
7c673cae | 1381 | |
7c673cae | 1382 | |
7c673cae | 1383 | |
7c673cae | 1384 | |
7c673cae FG |
1385 | |
1386 | int | |
11fdf7f2 | 1387 | rte_eth_bond_8023ad_slave_info(uint16_t port_id, uint16_t slave_id, |
7c673cae FG |
1388 | struct rte_eth_bond_8023ad_slave_info *info) |
1389 | { | |
1390 | struct rte_eth_dev *bond_dev; | |
1391 | struct bond_dev_private *internals; | |
1392 | struct port *port; | |
1393 | ||
1394 | if (info == NULL || valid_bonded_port_id(port_id) != 0 || | |
1395 | rte_eth_bond_mode_get(port_id) != BONDING_MODE_8023AD) | |
1396 | return -EINVAL; | |
1397 | ||
1398 | bond_dev = &rte_eth_devices[port_id]; | |
1399 | ||
1400 | internals = bond_dev->data->dev_private; | |
1401 | if (find_slave_by_id(internals->active_slaves, | |
1402 | internals->active_slave_count, slave_id) == | |
1403 | internals->active_slave_count) | |
1404 | return -EINVAL; | |
1405 | ||
9f95a23c | 1406 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
1407 | info->selected = port->selected; |
1408 | ||
1409 | info->actor_state = port->actor_state; | |
1410 | rte_memcpy(&info->actor, &port->actor, sizeof(port->actor)); | |
1411 | ||
1412 | info->partner_state = port->partner_state; | |
1413 | rte_memcpy(&info->partner, &port->partner, sizeof(port->partner)); | |
1414 | ||
1415 | info->agg_port_id = port->aggregator_port_id; | |
1416 | return 0; | |
1417 | } | |
1418 | ||
1419 | static int | |
11fdf7f2 | 1420 | bond_8023ad_ext_validate(uint16_t port_id, uint16_t slave_id) |
7c673cae FG |
1421 | { |
1422 | struct rte_eth_dev *bond_dev; | |
1423 | struct bond_dev_private *internals; | |
1424 | struct mode8023ad_private *mode4; | |
1425 | ||
1426 | if (rte_eth_bond_mode_get(port_id) != BONDING_MODE_8023AD) | |
1427 | return -EINVAL; | |
1428 | ||
1429 | bond_dev = &rte_eth_devices[port_id]; | |
1430 | ||
1431 | if (!bond_dev->data->dev_started) | |
1432 | return -EINVAL; | |
1433 | ||
1434 | internals = bond_dev->data->dev_private; | |
1435 | if (find_slave_by_id(internals->active_slaves, | |
1436 | internals->active_slave_count, slave_id) == | |
1437 | internals->active_slave_count) | |
1438 | return -EINVAL; | |
1439 | ||
1440 | mode4 = &internals->mode4; | |
1441 | if (mode4->slowrx_cb == NULL) | |
1442 | return -EINVAL; | |
1443 | ||
1444 | return 0; | |
1445 | } | |
1446 | ||
1447 | int | |
11fdf7f2 TL |
1448 | rte_eth_bond_8023ad_ext_collect(uint16_t port_id, uint16_t slave_id, |
1449 | int enabled) | |
7c673cae FG |
1450 | { |
1451 | struct port *port; | |
1452 | int res; | |
1453 | ||
1454 | res = bond_8023ad_ext_validate(port_id, slave_id); | |
1455 | if (res != 0) | |
1456 | return res; | |
1457 | ||
9f95a23c | 1458 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
1459 | |
1460 | if (enabled) | |
1461 | ACTOR_STATE_SET(port, COLLECTING); | |
1462 | else | |
1463 | ACTOR_STATE_CLR(port, COLLECTING); | |
1464 | ||
1465 | return 0; | |
1466 | } | |
1467 | ||
1468 | int | |
11fdf7f2 TL |
1469 | rte_eth_bond_8023ad_ext_distrib(uint16_t port_id, uint16_t slave_id, |
1470 | int enabled) | |
7c673cae FG |
1471 | { |
1472 | struct port *port; | |
1473 | int res; | |
1474 | ||
1475 | res = bond_8023ad_ext_validate(port_id, slave_id); | |
1476 | if (res != 0) | |
1477 | return res; | |
1478 | ||
9f95a23c | 1479 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
1480 | |
1481 | if (enabled) | |
1482 | ACTOR_STATE_SET(port, DISTRIBUTING); | |
1483 | else | |
1484 | ACTOR_STATE_CLR(port, DISTRIBUTING); | |
1485 | ||
1486 | return 0; | |
1487 | } | |
1488 | ||
1489 | int | |
11fdf7f2 | 1490 | rte_eth_bond_8023ad_ext_distrib_get(uint16_t port_id, uint16_t slave_id) |
7c673cae FG |
1491 | { |
1492 | struct port *port; | |
1493 | int err; | |
1494 | ||
1495 | err = bond_8023ad_ext_validate(port_id, slave_id); | |
1496 | if (err != 0) | |
1497 | return err; | |
1498 | ||
9f95a23c | 1499 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
1500 | return ACTOR_STATE(port, DISTRIBUTING); |
1501 | } | |
1502 | ||
1503 | int | |
11fdf7f2 | 1504 | rte_eth_bond_8023ad_ext_collect_get(uint16_t port_id, uint16_t slave_id) |
7c673cae FG |
1505 | { |
1506 | struct port *port; | |
1507 | int err; | |
1508 | ||
1509 | err = bond_8023ad_ext_validate(port_id, slave_id); | |
1510 | if (err != 0) | |
1511 | return err; | |
1512 | ||
9f95a23c | 1513 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
1514 | return ACTOR_STATE(port, COLLECTING); |
1515 | } | |
1516 | ||
1517 | int | |
11fdf7f2 | 1518 | rte_eth_bond_8023ad_ext_slowtx(uint16_t port_id, uint16_t slave_id, |
7c673cae FG |
1519 | struct rte_mbuf *lacp_pkt) |
1520 | { | |
1521 | struct port *port; | |
1522 | int res; | |
1523 | ||
1524 | res = bond_8023ad_ext_validate(port_id, slave_id); | |
1525 | if (res != 0) | |
1526 | return res; | |
1527 | ||
9f95a23c | 1528 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
1529 | |
1530 | if (rte_pktmbuf_pkt_len(lacp_pkt) < sizeof(struct lacpdu_header)) | |
1531 | return -EINVAL; | |
1532 | ||
1533 | struct lacpdu_header *lacp; | |
1534 | ||
1535 | /* only enqueue LACPDUs */ | |
1536 | lacp = rte_pktmbuf_mtod(lacp_pkt, struct lacpdu_header *); | |
1537 | if (lacp->lacpdu.subtype != SLOW_SUBTYPE_LACP) | |
1538 | return -EINVAL; | |
1539 | ||
1540 | MODE4_DEBUG("sending LACP frame\n"); | |
1541 | ||
1542 | return rte_ring_enqueue(port->tx_ring, lacp_pkt); | |
1543 | } | |
1544 | ||
1545 | static void | |
1546 | bond_mode_8023ad_ext_periodic_cb(void *arg) | |
1547 | { | |
1548 | struct rte_eth_dev *bond_dev = arg; | |
1549 | struct bond_dev_private *internals = bond_dev->data->dev_private; | |
1550 | struct mode8023ad_private *mode4 = &internals->mode4; | |
1551 | struct port *port; | |
1552 | void *pkt = NULL; | |
1553 | uint16_t i, slave_id; | |
1554 | ||
1555 | for (i = 0; i < internals->active_slave_count; i++) { | |
1556 | slave_id = internals->active_slaves[i]; | |
9f95a23c | 1557 | port = &bond_mode_8023ad_ports[slave_id]; |
7c673cae FG |
1558 | |
1559 | if (rte_ring_dequeue(port->rx_ring, &pkt) == 0) { | |
1560 | struct rte_mbuf *lacp_pkt = pkt; | |
1561 | struct lacpdu_header *lacp; | |
1562 | ||
1563 | lacp = rte_pktmbuf_mtod(lacp_pkt, | |
1564 | struct lacpdu_header *); | |
1565 | RTE_VERIFY(lacp->lacpdu.subtype == SLOW_SUBTYPE_LACP); | |
1566 | ||
1567 | /* This is LACP frame so pass it to rx callback. | |
1568 | * Callback is responsible for freeing mbuf. | |
1569 | */ | |
1570 | mode4->slowrx_cb(slave_id, lacp_pkt); | |
1571 | } | |
1572 | } | |
1573 | ||
1574 | rte_eal_alarm_set(internals->mode4.update_timeout_us, | |
1575 | bond_mode_8023ad_ext_periodic_cb, arg); | |
1576 | } | |
11fdf7f2 TL |
1577 | |
1578 | int | |
1579 | rte_eth_bond_8023ad_dedicated_queues_enable(uint16_t port) | |
1580 | { | |
1581 | int retval = 0; | |
1582 | struct rte_eth_dev *dev = &rte_eth_devices[port]; | |
1583 | struct bond_dev_private *internals = (struct bond_dev_private *) | |
1584 | dev->data->dev_private; | |
1585 | ||
1586 | if (check_for_bonded_ethdev(dev) != 0) | |
1587 | return -1; | |
1588 | ||
1589 | if (bond_8023ad_slow_pkt_hw_filter_supported(port) != 0) | |
1590 | return -1; | |
1591 | ||
1592 | /* Device must be stopped to set up slow queue */ | |
1593 | if (dev->data->dev_started) | |
1594 | return -1; | |
1595 | ||
1596 | internals->mode4.dedicated_queues.enabled = 1; | |
1597 | ||
1598 | bond_ethdev_mode_set(dev, internals->mode); | |
1599 | return retval; | |
1600 | } | |
1601 | ||
1602 | int | |
1603 | rte_eth_bond_8023ad_dedicated_queues_disable(uint16_t port) | |
1604 | { | |
1605 | int retval = 0; | |
1606 | struct rte_eth_dev *dev = &rte_eth_devices[port]; | |
1607 | struct bond_dev_private *internals = (struct bond_dev_private *) | |
1608 | dev->data->dev_private; | |
1609 | ||
1610 | if (check_for_bonded_ethdev(dev) != 0) | |
1611 | return -1; | |
1612 | ||
1613 | /* Device must be stopped to set up slow queue */ | |
1614 | if (dev->data->dev_started) | |
1615 | return -1; | |
1616 | ||
1617 | internals->mode4.dedicated_queues.enabled = 0; | |
1618 | ||
1619 | bond_ethdev_mode_set(dev, internals->mode); | |
1620 | ||
1621 | return retval; | |
1622 | } |