Branch data Line data Source code
1 : : /* Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
2 : : *
3 : : * Licensed under the Apache License, Version 2.0 (the "License");
4 : : * you may not use this file except in compliance with the License.
5 : : * You may obtain a copy of the License at:
6 : : *
7 : : * http://www.apache.org/licenses/LICENSE-2.0
8 : : *
9 : : * Unless required by applicable law or agreed to in writing, software
10 : : * distributed under the License is distributed on an "AS IS" BASIS,
11 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : : * See the License for the specific language governing permissions and
13 : : * limitations under the License.
14 : : */
15 : :
16 : : #include <config.h>
17 : : #include "lacp.h"
18 : :
19 : : #include <stdlib.h>
20 : :
21 : : #include "connectivity.h"
22 : : #include "openvswitch/dynamic-string.h"
23 : : #include "hash.h"
24 : : #include "openvswitch/hmap.h"
25 : : #include "dp-packet.h"
26 : : #include "ovs-atomic.h"
27 : : #include "packets.h"
28 : : #include "poll-loop.h"
29 : : #include "seq.h"
30 : : #include "openvswitch/shash.h"
31 : : #include "timer.h"
32 : : #include "timeval.h"
33 : : #include "unixctl.h"
34 : : #include "openvswitch/vlog.h"
35 : : #include "util.h"
36 : :
37 : 1288 : VLOG_DEFINE_THIS_MODULE(lacp);
38 : :
39 : : /* Masks for lacp_info state member. */
40 : : #define LACP_STATE_ACT 0x01 /* Activity. Active or passive? */
41 : : #define LACP_STATE_TIME 0x02 /* Timeout. Short or long timeout? */
42 : : #define LACP_STATE_AGG 0x04 /* Aggregation. Is the link is bondable? */
43 : : #define LACP_STATE_SYNC 0x08 /* Synchronization. Is the link in up to date? */
44 : : #define LACP_STATE_COL 0x10 /* Collecting. Is the link receiving frames? */
45 : : #define LACP_STATE_DIST 0x20 /* Distributing. Is the link sending frames? */
46 : : #define LACP_STATE_DEF 0x40 /* Defaulted. Using default partner info? */
47 : : #define LACP_STATE_EXP 0x80 /* Expired. Using expired partner info? */
48 : :
49 : : #define LACP_FAST_TIME_TX 1000 /* Fast transmission rate. */
50 : : #define LACP_SLOW_TIME_TX 30000 /* Slow transmission rate. */
51 : : #define LACP_RX_MULTIPLIER 3 /* Multiply by TX rate to get RX rate. */
52 : :
53 : : #define LACP_INFO_LEN 15
54 : : OVS_PACKED(
55 : : struct lacp_info {
56 : : ovs_be16 sys_priority; /* System priority. */
57 : : struct eth_addr sys_id; /* System ID. */
58 : : ovs_be16 key; /* Operational key. */
59 : : ovs_be16 port_priority; /* Port priority. */
60 : : ovs_be16 port_id; /* Port ID. */
61 : : uint8_t state; /* State mask. See LACP_STATE macros. */
62 : : });
63 : : BUILD_ASSERT_DECL(LACP_INFO_LEN == sizeof(struct lacp_info));
64 : :
65 : : #define LACP_PDU_LEN 110
66 : : struct lacp_pdu {
67 : : uint8_t subtype; /* Always 1. */
68 : : uint8_t version; /* Always 1. */
69 : :
70 : : uint8_t actor_type; /* Always 1. */
71 : : uint8_t actor_len; /* Always 20. */
72 : : struct lacp_info actor; /* LACP actor information. */
73 : : uint8_t z1[3]; /* Reserved. Always 0. */
74 : :
75 : : uint8_t partner_type; /* Always 2. */
76 : : uint8_t partner_len; /* Always 20. */
77 : : struct lacp_info partner; /* LACP partner information. */
78 : : uint8_t z2[3]; /* Reserved. Always 0. */
79 : :
80 : : uint8_t collector_type; /* Always 3. */
81 : : uint8_t collector_len; /* Always 16. */
82 : : ovs_be16 collector_delay; /* Maximum collector delay. Set to UINT16_MAX. */
83 : : uint8_t z3[64]; /* Combination of several fields. Always 0. */
84 : : };
85 : : BUILD_ASSERT_DECL(LACP_PDU_LEN == sizeof(struct lacp_pdu));
86 : :
87 : : /* Implementation. */
88 : :
89 : : enum slave_status {
90 : : LACP_CURRENT, /* Current State. Partner up to date. */
91 : : LACP_EXPIRED, /* Expired State. Partner out of date. */
92 : : LACP_DEFAULTED, /* Defaulted State. No partner. */
93 : : };
94 : :
95 : : struct lacp {
96 : : struct ovs_list node; /* Node in all_lacps list. */
97 : : char *name; /* Name of this lacp object. */
98 : : struct eth_addr sys_id; /* System ID. */
99 : : uint16_t sys_priority; /* System Priority. */
100 : : bool active; /* Active or Passive. */
101 : :
102 : : struct hmap slaves; /* Slaves this LACP object controls. */
103 : : struct slave *key_slave; /* Slave whose ID will be the aggregation key. */
104 : :
105 : : bool fast; /* True if using fast probe interval. */
106 : : bool negotiated; /* True if LACP negotiations were successful. */
107 : : bool update; /* True if lacp_update() needs to be called. */
108 : : bool fallback_ab; /* True if fallback to active-backup on LACP failure. */
109 : :
110 : : struct ovs_refcount ref_cnt;
111 : : };
112 : :
113 : : struct slave {
114 : : void *aux; /* Handle used to identify this slave. */
115 : : struct hmap_node node; /* Node in master's slaves map. */
116 : :
117 : : struct lacp *lacp; /* LACP object containing this slave. */
118 : : uint16_t port_id; /* Port ID. */
119 : : uint16_t port_priority; /* Port Priority. */
120 : : uint16_t key; /* Aggregation Key. 0 if default. */
121 : : char *name; /* Name of this slave. */
122 : :
123 : : enum slave_status status; /* Slave status. */
124 : : bool attached; /* Attached. Traffic may flow. */
125 : : struct lacp_info partner; /* Partner information. */
126 : : struct lacp_info ntt_actor; /* Used to decide if we Need To Transmit. */
127 : : struct timer tx; /* Next message transmission timer. */
128 : : struct timer rx; /* Expected message receive timer. */
129 : :
130 : : uint32_t count_rx_pdus; /* dot3adAggPortStatsLACPDUsRx */
131 : : uint32_t count_rx_pdus_bad; /* dot3adAggPortStatsIllegalRx */
132 : : uint32_t count_tx_pdus; /* dot3adAggPortStatsLACPDUsTx */
133 : : };
134 : :
135 : : static struct ovs_mutex mutex;
136 : : static struct ovs_list all_lacps__ = OVS_LIST_INITIALIZER(&all_lacps__);
137 : : static struct ovs_list *const all_lacps OVS_GUARDED_BY(mutex) = &all_lacps__;
138 : :
139 : : static void lacp_update_attached(struct lacp *) OVS_REQUIRES(mutex);
140 : :
141 : : static void slave_destroy(struct slave *) OVS_REQUIRES(mutex);
142 : : static void slave_set_defaulted(struct slave *) OVS_REQUIRES(mutex);
143 : : static void slave_set_expired(struct slave *) OVS_REQUIRES(mutex);
144 : : static void slave_get_actor(struct slave *, struct lacp_info *actor)
145 : : OVS_REQUIRES(mutex);
146 : : static void slave_get_priority(struct slave *, struct lacp_info *priority)
147 : : OVS_REQUIRES(mutex);
148 : : static bool slave_may_tx(const struct slave *)
149 : : OVS_REQUIRES(mutex);
150 : : static struct slave *slave_lookup(const struct lacp *, const void *slave)
151 : : OVS_REQUIRES(mutex);
152 : : static bool info_tx_equal(struct lacp_info *, struct lacp_info *)
153 : : OVS_REQUIRES(mutex);
154 : :
155 : : static unixctl_cb_func lacp_unixctl_show;
156 : :
157 : : /* Populates 'pdu' with a LACP PDU comprised of 'actor' and 'partner'. */
158 : : static void
159 : 80 : compose_lacp_pdu(const struct lacp_info *actor,
160 : : const struct lacp_info *partner, struct lacp_pdu *pdu)
161 : : {
162 : 80 : memset(pdu, 0, sizeof *pdu);
163 : :
164 : 80 : pdu->subtype = 1;
165 : 80 : pdu->version = 1;
166 : :
167 : 80 : pdu->actor_type = 1;
168 : 80 : pdu->actor_len = 20;
169 : 80 : pdu->actor = *actor;
170 : :
171 : 80 : pdu->partner_type = 2;
172 : 80 : pdu->partner_len = 20;
173 : 80 : pdu->partner = *partner;
174 : :
175 : 80 : pdu->collector_type = 3;
176 : 80 : pdu->collector_len = 16;
177 : 80 : pdu->collector_delay = htons(0);
178 : 80 : }
179 : :
180 : : /* Parses 'b' which represents a packet containing a LACP PDU. This function
181 : : * returns NULL if 'b' is malformed, or does not represent a LACP PDU format
182 : : * supported by OVS. Otherwise, it returns a pointer to the lacp_pdu contained
183 : : * within 'b'. */
184 : : static const struct lacp_pdu *
185 : 54 : parse_lacp_packet(const struct dp_packet *p)
186 : : {
187 : : const struct lacp_pdu *pdu;
188 : :
189 : 54 : pdu = dp_packet_at(p, (uint8_t *)dp_packet_l3(p) - (uint8_t *)dp_packet_data(p),
190 : : LACP_PDU_LEN);
191 : :
192 [ + - ][ + - ]: 54 : if (pdu && pdu->subtype == 1
193 [ + - ][ + - ]: 54 : && pdu->actor_type == 1 && pdu->actor_len == 20
194 [ + - ][ + - ]: 54 : && pdu->partner_type == 2 && pdu->partner_len == 20) {
195 : 54 : return pdu;
196 : : } else {
197 : 0 : return NULL;
198 : : }
199 : : }
200 : :
201 : : /* LACP Protocol Implementation. */
202 : :
203 : : /* Initializes the lacp module. */
204 : : void
205 : 617 : lacp_init(void)
206 : : {
207 : 617 : unixctl_command_register("lacp/show", "[port]", 0, 1,
208 : : lacp_unixctl_show, NULL);
209 : 617 : }
210 : :
211 : : static void
212 : 12199 : lacp_lock(void) OVS_ACQUIRES(mutex)
213 : : {
214 : : static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
215 : :
216 [ + + ]: 12199 : if (ovsthread_once_start(&once)) {
217 : 9 : ovs_mutex_init_recursive(&mutex);
218 : 9 : ovsthread_once_done(&once);
219 : : }
220 : 12199 : ovs_mutex_lock(&mutex);
221 : 12199 : }
222 : :
223 : : static void
224 : 12199 : lacp_unlock(void) OVS_RELEASES(mutex)
225 : : {
226 : 12199 : ovs_mutex_unlock(&mutex);
227 : 12199 : }
228 : :
229 : : /* Creates a LACP object. */
230 : : struct lacp *
231 : 13 : lacp_create(void) OVS_EXCLUDED(mutex)
232 : : {
233 : : struct lacp *lacp;
234 : :
235 : 13 : lacp = xzalloc(sizeof *lacp);
236 : 13 : hmap_init(&lacp->slaves);
237 : 13 : ovs_refcount_init(&lacp->ref_cnt);
238 : :
239 : 13 : lacp_lock();
240 : 13 : ovs_list_push_back(all_lacps, &lacp->node);
241 : 13 : lacp_unlock();
242 : 13 : return lacp;
243 : : }
244 : :
245 : : struct lacp *
246 : 229 : lacp_ref(const struct lacp *lacp_)
247 : : {
248 : 229 : struct lacp *lacp = CONST_CAST(struct lacp *, lacp_);
249 [ + - ]: 229 : if (lacp) {
250 : 229 : ovs_refcount_ref(&lacp->ref_cnt);
251 : : }
252 : 229 : return lacp;
253 : : }
254 : :
255 : : /* Destroys 'lacp' and its slaves. Does nothing if 'lacp' is NULL. */
256 : : void
257 : 228401 : lacp_unref(struct lacp *lacp) OVS_EXCLUDED(mutex)
258 : : {
259 [ + + ][ + + ]: 228401 : if (lacp && ovs_refcount_unref_relaxed(&lacp->ref_cnt) == 1) {
260 : : struct slave *slave, *next;
261 : :
262 : 13 : lacp_lock();
263 [ + - ][ - + ]: 13 : HMAP_FOR_EACH_SAFE (slave, next, node, &lacp->slaves) {
[ - + ]
264 : 0 : slave_destroy(slave);
265 : : }
266 : :
267 : 13 : hmap_destroy(&lacp->slaves);
268 : 13 : ovs_list_remove(&lacp->node);
269 : 13 : free(lacp->name);
270 : 13 : free(lacp);
271 : 13 : lacp_unlock();
272 : : }
273 : 228401 : }
274 : :
275 : : /* Configures 'lacp' with settings from 's'. */
276 : : void
277 : 20 : lacp_configure(struct lacp *lacp, const struct lacp_settings *s)
278 : : OVS_EXCLUDED(mutex)
279 : : {
280 [ - + ]: 20 : ovs_assert(!eth_addr_is_zero(s->id));
281 : :
282 : 20 : lacp_lock();
283 [ + + ][ - + ]: 20 : if (!lacp->name || strcmp(s->name, lacp->name)) {
284 : 13 : free(lacp->name);
285 : 13 : lacp->name = xstrdup(s->name);
286 : : }
287 : :
288 [ + + ]: 20 : if (!eth_addr_equals(lacp->sys_id, s->id)
289 [ - + ]: 7 : || lacp->sys_priority != s->priority) {
290 : 13 : lacp->sys_id = s->id;
291 : 13 : lacp->sys_priority = s->priority;
292 : 13 : lacp->update = true;
293 : : }
294 : :
295 : 20 : lacp->active = s->active;
296 : 20 : lacp->fast = s->fast;
297 : :
298 [ - + ]: 20 : if (lacp->fallback_ab != s->fallback_ab_cfg) {
299 : 0 : lacp->fallback_ab = s->fallback_ab_cfg;
300 : 0 : lacp->update = true;
301 : : }
302 : :
303 : 20 : lacp_unlock();
304 : 20 : }
305 : :
306 : : /* Returns true if 'lacp' is configured in active mode, false if 'lacp' is
307 : : * configured for passive mode. */
308 : : bool
309 : 0 : lacp_is_active(const struct lacp *lacp) OVS_EXCLUDED(mutex)
310 : : {
311 : : bool ret;
312 : 0 : lacp_lock();
313 : 0 : ret = lacp->active;
314 : 0 : lacp_unlock();
315 : 0 : return ret;
316 : : }
317 : :
318 : : /* Processes 'packet' which was received on 'slave_'. This function should be
319 : : * called on all packets received on 'slave_' with Ethernet Type ETH_TYPE_LACP.
320 : : */
321 : : void
322 : 54 : lacp_process_packet(struct lacp *lacp, const void *slave_,
323 : : const struct dp_packet *packet)
324 : : OVS_EXCLUDED(mutex)
325 : : {
326 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
327 : : const struct lacp_pdu *pdu;
328 : : long long int tx_rate;
329 : : struct slave *slave;
330 : :
331 : 54 : lacp_lock();
332 : 54 : slave = slave_lookup(lacp, slave_);
333 [ - + ]: 54 : if (!slave) {
334 : 0 : goto out;
335 : : }
336 : 54 : slave->count_rx_pdus++;
337 : :
338 : 54 : pdu = parse_lacp_packet(packet);
339 [ - + ]: 54 : if (!pdu) {
340 : 0 : slave->count_rx_pdus_bad++;
341 [ # # ]: 0 : VLOG_WARN_RL(&rl, "%s: received an unparsable LACP PDU.", lacp->name);
342 : 0 : goto out;
343 : : }
344 : :
345 : 54 : slave->status = LACP_CURRENT;
346 [ + + ]: 54 : tx_rate = lacp->fast ? LACP_FAST_TIME_TX : LACP_SLOW_TIME_TX;
347 : 54 : timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER * tx_rate);
348 : :
349 : 54 : slave->ntt_actor = pdu->partner;
350 : :
351 : : /* Update our information about our partner if it's out of date. This may
352 : : * cause priorities to change so re-calculate attached status of all
353 : : * slaves. */
354 [ + + ]: 54 : if (memcmp(&slave->partner, &pdu->actor, sizeof pdu->actor)) {
355 : 30 : lacp->update = true;
356 : 30 : slave->partner = pdu->actor;
357 : : }
358 : :
359 : : out:
360 : 54 : lacp_unlock();
361 : 54 : }
362 : :
363 : : /* Returns the lacp_status of the given 'lacp' object (which may be NULL). */
364 : : enum lacp_status
365 : 5410 : lacp_status(const struct lacp *lacp) OVS_EXCLUDED(mutex)
366 : : {
367 [ + + ]: 5410 : if (lacp) {
368 : : enum lacp_status ret;
369 : :
370 : 3894 : lacp_lock();
371 [ + - ]: 3894 : ret = lacp->negotiated ? LACP_NEGOTIATED : LACP_CONFIGURED;
372 : 3894 : lacp_unlock();
373 : 3894 : return ret;
374 : : } else {
375 : : /* Don't take 'mutex'. It might not even be initialized, since we
376 : : * don't know that any lacp object has been created. */
377 : 1516 : return LACP_DISABLED;
378 : : }
379 : : }
380 : :
381 : : /* Registers 'slave_' as subordinate to 'lacp'. This should be called at least
382 : : * once per slave in a LACP managed bond. Should also be called whenever a
383 : : * slave's settings change. */
384 : : void
385 : 41 : lacp_slave_register(struct lacp *lacp, void *slave_,
386 : : const struct lacp_slave_settings *s)
387 : : OVS_EXCLUDED(mutex)
388 : : {
389 : : struct slave *slave;
390 : :
391 : 41 : lacp_lock();
392 : 41 : slave = slave_lookup(lacp, slave_);
393 [ + + ]: 41 : if (!slave) {
394 : 27 : slave = xzalloc(sizeof *slave);
395 : 27 : slave->lacp = lacp;
396 : 27 : slave->aux = slave_;
397 : 27 : hmap_insert(&lacp->slaves, &slave->node, hash_pointer(slave_, 0));
398 : 27 : slave_set_defaulted(slave);
399 : :
400 [ + + ]: 27 : if (!lacp->key_slave) {
401 : 13 : lacp->key_slave = slave;
402 : : }
403 : : }
404 : :
405 [ + + ][ - + ]: 41 : if (!slave->name || strcmp(s->name, slave->name)) {
406 : 27 : free(slave->name);
407 : 27 : slave->name = xstrdup(s->name);
408 : : }
409 : :
410 [ + + ]: 41 : if (slave->port_id != s->id
411 [ + - ]: 14 : || slave->port_priority != s->priority
412 [ - + ]: 14 : || slave->key != s->key) {
413 : 27 : slave->port_id = s->id;
414 : 27 : slave->port_priority = s->priority;
415 : 27 : slave->key = s->key;
416 : :
417 : 27 : lacp->update = true;
418 : :
419 [ - + ][ # # ]: 27 : if (lacp->active || lacp->negotiated) {
420 : 27 : slave_set_expired(slave);
421 : : }
422 : : }
423 : 41 : lacp_unlock();
424 : 41 : }
425 : :
426 : : /* Unregisters 'slave_' with 'lacp'. */
427 : : void
428 : 27 : lacp_slave_unregister(struct lacp *lacp, const void *slave_)
429 : : OVS_EXCLUDED(mutex)
430 : : {
431 : : struct slave *slave;
432 : :
433 : 27 : lacp_lock();
434 : 27 : slave = slave_lookup(lacp, slave_);
435 [ + - ]: 27 : if (slave) {
436 : 27 : slave_destroy(slave);
437 : 27 : lacp->update = true;
438 : : }
439 : 27 : lacp_unlock();
440 : 27 : }
441 : :
442 : : /* This function should be called whenever the carrier status of 'slave_' has
443 : : * changed. If 'lacp' is null, this function has no effect.*/
444 : : void
445 : 97 : lacp_slave_carrier_changed(const struct lacp *lacp, const void *slave_)
446 : : OVS_EXCLUDED(mutex)
447 : : {
448 : : struct slave *slave;
449 [ + - ]: 97 : if (!lacp) {
450 : 97 : return;
451 : : }
452 : :
453 : 0 : lacp_lock();
454 : 0 : slave = slave_lookup(lacp, slave_);
455 [ # # ]: 0 : if (!slave) {
456 : 0 : goto out;
457 : : }
458 : :
459 [ # # ][ # # ]: 0 : if (slave->status == LACP_CURRENT || slave->lacp->active) {
460 : 0 : slave_set_expired(slave);
461 : : }
462 : :
463 : : out:
464 : 0 : lacp_unlock();
465 : : }
466 : :
467 : : static bool
468 : 213 : slave_may_enable__(struct slave *slave) OVS_REQUIRES(mutex)
469 : : {
470 : : /* The slave may be enabled if it's attached to an aggregator and its
471 : : * partner is synchronized.*/
472 [ + + ][ + + ]: 251 : return slave->attached && (slave->partner.state & LACP_STATE_SYNC
473 [ + - ][ - + ]: 38 : || (slave->lacp && slave->lacp->fallback_ab
474 [ # # ]: 0 : && slave->status == LACP_DEFAULTED));
475 : : }
476 : :
477 : : /* This function should be called before enabling 'slave_' to send or receive
478 : : * traffic. If it returns false, 'slave_' should not enabled. As a
479 : : * convenience, returns true if 'lacp' is NULL. */
480 : : bool
481 : 7020 : lacp_slave_may_enable(const struct lacp *lacp, const void *slave_)
482 : : OVS_EXCLUDED(mutex)
483 : : {
484 [ + + ]: 7020 : if (lacp) {
485 : : struct slave *slave;
486 : : bool ret;
487 : :
488 : 152 : lacp_lock();
489 : 152 : slave = slave_lookup(lacp, slave_);
490 [ + - ][ + + ]: 152 : ret = slave ? slave_may_enable__(slave) : false;
491 : 152 : lacp_unlock();
492 : 152 : return ret;
493 : : } else {
494 : 6868 : return true;
495 : : }
496 : : }
497 : :
498 : : /* Returns true if partner information on 'slave_' is up to date. 'slave_'
499 : : * not being current, generally indicates a connectivity problem, or a
500 : : * misconfigured (or broken) partner. */
501 : : bool
502 : 145 : lacp_slave_is_current(const struct lacp *lacp, const void *slave_)
503 : : OVS_EXCLUDED(mutex)
504 : : {
505 : : struct slave *slave;
506 : : bool ret;
507 : :
508 : 145 : lacp_lock();
509 : 145 : slave = slave_lookup(lacp, slave_);
510 [ + - ][ + + ]: 145 : ret = slave ? slave->status != LACP_DEFAULTED : false;
511 : 145 : lacp_unlock();
512 : 145 : return ret;
513 : : }
514 : :
515 : : /* This function should be called periodically to update 'lacp'. */
516 : : void
517 : 3909 : lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu) OVS_EXCLUDED(mutex)
518 : : {
519 : : struct slave *slave;
520 : :
521 : 3909 : lacp_lock();
522 [ + + ][ - + ]: 14690 : HMAP_FOR_EACH (slave, node, &lacp->slaves) {
523 [ + + ]: 10781 : if (timer_expired(&slave->rx)) {
524 : 70 : enum slave_status old_status = slave->status;
525 : :
526 [ + + ]: 70 : if (slave->status == LACP_CURRENT) {
527 : 4 : slave_set_expired(slave);
528 [ + + ]: 66 : } else if (slave->status == LACP_EXPIRED) {
529 : 2 : slave_set_defaulted(slave);
530 : : }
531 [ + + ]: 70 : if (slave->status != old_status) {
532 : 6 : seq_change(connectivity_seq_get());
533 : : }
534 : : }
535 : : }
536 : :
537 [ + + ]: 3909 : if (lacp->update) {
538 : 27 : lacp_update_attached(lacp);
539 : : }
540 : :
541 [ + + ][ - + ]: 14690 : HMAP_FOR_EACH (slave, node, &lacp->slaves) {
542 : : struct lacp_info actor;
543 : :
544 [ - + ]: 10781 : if (!slave_may_tx(slave)) {
545 : 0 : continue;
546 : : }
547 : :
548 : 10781 : slave_get_actor(slave, &actor);
549 : :
550 [ + + ]: 10781 : if (timer_expired(&slave->tx)
551 [ + + ]: 10710 : || !info_tx_equal(&actor, &slave->ntt_actor)) {
552 : : long long int duration;
553 : : struct lacp_pdu pdu;
554 : :
555 : 80 : slave->ntt_actor = actor;
556 : 80 : compose_lacp_pdu(&actor, &slave->partner, &pdu);
557 : 80 : send_pdu(slave->aux, &pdu, sizeof pdu);
558 : 80 : slave->count_tx_pdus++;
559 : :
560 [ + + ]: 80 : duration = (slave->partner.state & LACP_STATE_TIME
561 : : ? LACP_FAST_TIME_TX
562 : : : LACP_SLOW_TIME_TX);
563 : :
564 : 80 : timer_set_duration(&slave->tx, duration);
565 : 10781 : seq_change(connectivity_seq_get());
566 : : }
567 : : }
568 : 3909 : lacp_unlock();
569 : 3909 : }
570 : :
571 : : /* Causes poll_block() to wake up when lacp_run() needs to be called again. */
572 : : void
573 : 3902 : lacp_wait(struct lacp *lacp) OVS_EXCLUDED(mutex)
574 : : {
575 : : struct slave *slave;
576 : :
577 : 3902 : lacp_lock();
578 [ + + ][ - + ]: 14669 : HMAP_FOR_EACH (slave, node, &lacp->slaves) {
579 [ + - ]: 10767 : if (slave_may_tx(slave)) {
580 : 10767 : timer_wait(&slave->tx);
581 : : }
582 : :
583 [ + + ]: 10767 : if (slave->status != LACP_DEFAULTED) {
584 : 10701 : timer_wait(&slave->rx);
585 : : }
586 : : }
587 : 3902 : lacp_unlock();
588 : 3902 : }
589 : :
590 : : /* Static Helpers. */
591 : :
592 : : /* Updates the attached status of all slaves controlled by 'lacp' and sets its
593 : : * negotiated parameter to true if any slaves are attachable. */
594 : : static void
595 : 27 : lacp_update_attached(struct lacp *lacp) OVS_REQUIRES(mutex)
596 : : {
597 : : struct slave *lead, *slave;
598 : : struct lacp_info lead_pri;
599 : : static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
600 : :
601 : 27 : lacp->update = false;
602 : :
603 : 27 : lead = NULL;
604 [ + + ][ - + ]: 84 : HMAP_FOR_EACH (slave, node, &lacp->slaves) {
605 : : struct lacp_info pri;
606 : :
607 : 57 : slave->attached = false;
608 : :
609 : : /* XXX: In the future allow users to configure the expected system ID.
610 : : * For now just special case loopback. */
611 [ - + ]: 57 : if (eth_addr_equals(slave->partner.sys_id, slave->lacp->sys_id)) {
612 [ # # ]: 0 : VLOG_WARN_RL(&rl, "slave %s: Loopback detected. Slave is "
613 : : "connected to its own bond", slave->name);
614 : 2 : continue;
615 : : }
616 : :
617 [ + + ]: 57 : if (slave->status == LACP_DEFAULTED) {
618 [ - + ]: 2 : if (lacp->fallback_ab) {
619 : 0 : slave->attached = true;
620 : : }
621 : 2 : continue;
622 : : }
623 : :
624 : 55 : slave->attached = true;
625 : 55 : slave_get_priority(slave, &pri);
626 : :
627 [ + + ][ + + ]: 55 : if (!lead || memcmp(&pri, &lead_pri, sizeof pri) < 0) {
628 : 33 : lead = slave;
629 : 55 : lead_pri = pri;
630 : : }
631 : : }
632 : :
633 : 27 : lacp->negotiated = lead != NULL;
634 : :
635 [ + - ]: 27 : if (lead) {
636 [ + + ][ - + ]: 84 : HMAP_FOR_EACH (slave, node, &lacp->slaves) {
637 [ - + ][ # # ]: 57 : if ((lacp->fallback_ab && slave->status == LACP_DEFAULTED)
638 [ + + ]: 57 : || lead->partner.key != slave->partner.key
639 [ - + ]: 55 : || !eth_addr_equals(lead->partner.sys_id,
640 : : slave->partner.sys_id)) {
641 : 2 : slave->attached = false;
642 : : }
643 : : }
644 : : }
645 : 27 : }
646 : :
647 : : static void
648 : 27 : slave_destroy(struct slave *slave) OVS_REQUIRES(mutex)
649 : : {
650 [ + - ]: 27 : if (slave) {
651 : 27 : struct lacp *lacp = slave->lacp;
652 : :
653 : 27 : lacp->update = true;
654 : 27 : hmap_remove(&lacp->slaves, &slave->node);
655 : :
656 [ + + ]: 27 : if (lacp->key_slave == slave) {
657 : 26 : struct hmap_node *slave_node = hmap_first(&lacp->slaves);
658 : :
659 [ + + ]: 26 : if (slave_node) {
660 : 13 : lacp->key_slave = CONTAINER_OF(slave_node, struct slave, node);
661 : : } else {
662 : 13 : lacp->key_slave = NULL;
663 : : }
664 : : }
665 : :
666 : 27 : free(slave->name);
667 : 27 : free(slave);
668 : : }
669 : 27 : }
670 : :
671 : : static void
672 : 29 : slave_set_defaulted(struct slave *slave) OVS_REQUIRES(mutex)
673 : : {
674 : 29 : memset(&slave->partner, 0, sizeof slave->partner);
675 : :
676 : 29 : slave->lacp->update = true;
677 : 29 : slave->status = LACP_DEFAULTED;
678 : 29 : }
679 : :
680 : : static void
681 : 31 : slave_set_expired(struct slave *slave) OVS_REQUIRES(mutex)
682 : : {
683 : 31 : slave->status = LACP_EXPIRED;
684 : 31 : slave->partner.state |= LACP_STATE_TIME;
685 : 31 : slave->partner.state &= ~LACP_STATE_SYNC;
686 : :
687 : 31 : timer_set_duration(&slave->rx, LACP_RX_MULTIPLIER * LACP_FAST_TIME_TX);
688 : 31 : }
689 : :
690 : : static void
691 : 10864 : slave_get_actor(struct slave *slave, struct lacp_info *actor)
692 : : OVS_REQUIRES(mutex)
693 : : {
694 : 10864 : struct lacp *lacp = slave->lacp;
695 : : uint16_t key;
696 : 10864 : uint8_t state = 0;
697 : :
698 [ + - ]: 10864 : if (lacp->active) {
699 : 10864 : state |= LACP_STATE_ACT;
700 : : }
701 : :
702 [ + + ]: 10864 : if (lacp->fast) {
703 : 10294 : state |= LACP_STATE_TIME;
704 : : }
705 : :
706 [ + + ]: 10864 : if (slave->attached) {
707 : 10796 : state |= LACP_STATE_SYNC;
708 : : }
709 : :
710 [ + + ]: 10864 : if (slave->status == LACP_DEFAULTED) {
711 : 68 : state |= LACP_STATE_DEF;
712 : : }
713 : :
714 [ + + ]: 10864 : if (slave->status == LACP_EXPIRED) {
715 : 276 : state |= LACP_STATE_EXP;
716 : : }
717 : :
718 [ + + ]: 10864 : if (hmap_count(&lacp->slaves) > 1) {
719 : 10848 : state |= LACP_STATE_AGG;
720 : : }
721 : :
722 [ + + ][ - + ]: 10864 : if (slave->attached || !lacp->negotiated) {
723 : 10796 : state |= LACP_STATE_COL | LACP_STATE_DIST;
724 : : }
725 : :
726 : 10864 : key = lacp->key_slave->key;
727 [ + + ]: 10864 : if (!key) {
728 : 9903 : key = lacp->key_slave->port_id;
729 : : }
730 : :
731 : 10864 : actor->state = state;
732 : 10864 : actor->key = htons(key);
733 : 10864 : actor->port_priority = htons(slave->port_priority);
734 : 10864 : actor->port_id = htons(slave->port_id);
735 : 10864 : actor->sys_priority = htons(lacp->sys_priority);
736 : 10864 : actor->sys_id = lacp->sys_id;
737 : 10864 : }
738 : :
739 : : /* Given 'slave', populates 'priority' with data representing its LACP link
740 : : * priority. If two priority objects populated by this function are compared
741 : : * using memcmp, the higher priority link will be less than the lower priority
742 : : * link. */
743 : : static void
744 : 55 : slave_get_priority(struct slave *slave, struct lacp_info *priority)
745 : : OVS_REQUIRES(mutex)
746 : : {
747 : : uint16_t partner_priority, actor_priority;
748 : :
749 : : /* Choose the lacp_info of the higher priority system by comparing their
750 : : * system priorities and mac addresses. */
751 : 55 : actor_priority = slave->lacp->sys_priority;
752 : 55 : partner_priority = ntohs(slave->partner.sys_priority);
753 [ + + ]: 55 : if (actor_priority < partner_priority) {
754 : 8 : slave_get_actor(slave, priority);
755 [ + + ]: 47 : } else if (partner_priority < actor_priority) {
756 : 23 : *priority = slave->partner;
757 [ + + ]: 24 : } else if (eth_addr_compare_3way(slave->lacp->sys_id,
758 : : slave->partner.sys_id) < 0) {
759 : 12 : slave_get_actor(slave, priority);
760 : : } else {
761 : 12 : *priority = slave->partner;
762 : : }
763 : :
764 : : /* Key and state are not used in priority comparisons. */
765 : 55 : priority->key = 0;
766 : 55 : priority->state = 0;
767 : 55 : }
768 : :
769 : : static bool
770 : 21548 : slave_may_tx(const struct slave *slave) OVS_REQUIRES(mutex)
771 : : {
772 [ - + ][ # # ]: 21548 : return slave->lacp->active || slave->status != LACP_DEFAULTED;
773 : : }
774 : :
775 : : static struct slave *
776 : 421 : slave_lookup(const struct lacp *lacp, const void *slave_) OVS_REQUIRES(mutex)
777 : : {
778 : : struct slave *slave;
779 : :
780 [ + + ][ - + ]: 511 : HMAP_FOR_EACH_IN_BUCKET (slave, node, hash_pointer(slave_, 0),
781 : : &lacp->slaves) {
782 [ + + ]: 484 : if (slave->aux == slave_) {
783 : 394 : return slave;
784 : : }
785 : : }
786 : :
787 : 27 : return NULL;
788 : : }
789 : :
790 : : /* Two lacp_info structures are tx_equal if and only if they do not differ in
791 : : * ways which would require a lacp_pdu transmission. */
792 : : static bool
793 : 10710 : info_tx_equal(struct lacp_info *a, struct lacp_info *b)
794 : : {
795 : :
796 : : /* LACP specification dictates that we transmit whenever the actor and
797 : : * remote_actor differ in the following fields: Port, Port Priority,
798 : : * System, System Priority, Aggregation Key, Activity State, Timeout State,
799 : : * Sync State, and Aggregation State. The state flags are most likely to
800 : : * change so are checked first. */
801 : 10710 : return !((a->state ^ b->state) & (LACP_STATE_ACT
802 : : | LACP_STATE_TIME
803 : : | LACP_STATE_SYNC
804 : : | LACP_STATE_AGG))
805 [ + - ]: 10701 : && a->port_id == b->port_id
806 [ + - ]: 10701 : && a->port_priority == b->port_priority
807 [ + - ]: 10701 : && a->key == b->key
808 [ + - ]: 10701 : && a->sys_priority == b->sys_priority
809 [ + + ][ + - ]: 21411 : && eth_addr_equals(a->sys_id, b->sys_id);
810 : : }
811 : :
812 : : static struct lacp *
813 : 26 : lacp_find(const char *name) OVS_REQUIRES(mutex)
814 : : {
815 : : struct lacp *lacp;
816 : :
817 [ + - ]: 39 : LIST_FOR_EACH (lacp, node, all_lacps) {
818 [ + + ]: 39 : if (!strcmp(lacp->name, name)) {
819 : 26 : return lacp;
820 : : }
821 : : }
822 : :
823 : 0 : return NULL;
824 : : }
825 : :
826 : : static void
827 : 122 : ds_put_lacp_state(struct ds *ds, uint8_t state)
828 : : {
829 [ + + ]: 122 : if (state & LACP_STATE_ACT) {
830 : 117 : ds_put_cstr(ds, " activity");
831 : : }
832 : :
833 [ + + ]: 122 : if (state & LACP_STATE_TIME) {
834 : 119 : ds_put_cstr(ds, " timeout");
835 : : }
836 : :
837 [ + + ]: 122 : if (state & LACP_STATE_AGG) {
838 : 116 : ds_put_cstr(ds, " aggregation");
839 : : }
840 : :
841 [ + + ]: 122 : if (state & LACP_STATE_SYNC) {
842 : 113 : ds_put_cstr(ds, " synchronized");
843 : : }
844 : :
845 [ + + ]: 122 : if (state & LACP_STATE_COL) {
846 : 115 : ds_put_cstr(ds, " collecting");
847 : : }
848 : :
849 [ + + ]: 122 : if (state & LACP_STATE_DIST) {
850 : 115 : ds_put_cstr(ds, " distributing");
851 : : }
852 : :
853 [ + + ]: 122 : if (state & LACP_STATE_DEF) {
854 : 2 : ds_put_cstr(ds, " defaulted");
855 : : }
856 : :
857 [ + + ]: 122 : if (state & LACP_STATE_EXP) {
858 : 26 : ds_put_cstr(ds, " expired");
859 : : }
860 : 122 : }
861 : :
862 : : static void
863 : 30 : lacp_print_details(struct ds *ds, struct lacp *lacp) OVS_REQUIRES(mutex)
864 : : {
865 : 30 : struct shash slave_shash = SHASH_INITIALIZER(&slave_shash);
866 : 30 : const struct shash_node **sorted_slaves = NULL;
867 : :
868 : : struct slave *slave;
869 : : int i;
870 : :
871 : 30 : ds_put_format(ds, "---- %s ----\n", lacp->name);
872 [ + - ]: 30 : ds_put_format(ds, "\tstatus: %s", lacp->active ? "active" : "passive");
873 [ + - ]: 30 : if (lacp->negotiated) {
874 : 30 : ds_put_cstr(ds, " negotiated");
875 : : }
876 : 30 : ds_put_cstr(ds, "\n");
877 : :
878 : 30 : ds_put_format(ds, "\tsys_id: " ETH_ADDR_FMT "\n", ETH_ADDR_ARGS(lacp->sys_id));
879 : 30 : ds_put_format(ds, "\tsys_priority: %u\n", lacp->sys_priority);
880 : 30 : ds_put_cstr(ds, "\taggregation key: ");
881 [ + - ]: 30 : if (lacp->key_slave) {
882 [ + + ]: 30 : ds_put_format(ds, "%u", lacp->key_slave->key
883 : 27 : ? lacp->key_slave->key
884 : 3 : : lacp->key_slave->port_id);
885 : : } else {
886 : 0 : ds_put_cstr(ds, "none");
887 : : }
888 : 30 : ds_put_cstr(ds, "\n");
889 : :
890 : 30 : ds_put_cstr(ds, "\tlacp_time: ");
891 [ + + ]: 30 : if (lacp->fast) {
892 : 29 : ds_put_cstr(ds, "fast\n");
893 : : } else {
894 : 1 : ds_put_cstr(ds, "slow\n");
895 : : }
896 : :
897 [ + + ][ - + ]: 91 : HMAP_FOR_EACH (slave, node, &lacp->slaves) {
898 : 61 : shash_add(&slave_shash, slave->name, slave);
899 : : }
900 : 30 : sorted_slaves = shash_sort(&slave_shash);
901 : :
902 [ + + ]: 91 : for (i = 0; i < shash_count(&slave_shash); i++) {
903 : : char *status;
904 : : struct lacp_info actor;
905 : :
906 : 61 : slave = sorted_slaves[i]->data;
907 : 61 : slave_get_actor(slave, &actor);
908 [ + + + - ]: 61 : switch (slave->status) {
909 : : case LACP_CURRENT:
910 : 54 : status = "current";
911 : 54 : break;
912 : : case LACP_EXPIRED:
913 : 5 : status = "expired";
914 : 5 : break;
915 : : case LACP_DEFAULTED:
916 : 2 : status = "defaulted";
917 : 2 : break;
918 : : default:
919 : 0 : OVS_NOT_REACHED();
920 : : }
921 : :
922 [ + + ]: 61 : ds_put_format(ds, "\nslave: %s: %s %s\n", slave->name, status,
923 : 61 : slave->attached ? "attached" : "detached");
924 : 61 : ds_put_format(ds, "\tport_id: %u\n", slave->port_id);
925 : 61 : ds_put_format(ds, "\tport_priority: %u\n", slave->port_priority);
926 [ + + ]: 61 : ds_put_format(ds, "\tmay_enable: %s\n", (slave_may_enable__(slave)
927 : : ? "true" : "false"));
928 : :
929 : 61 : ds_put_format(ds, "\n\tactor sys_id: " ETH_ADDR_FMT "\n",
930 : 366 : ETH_ADDR_ARGS(actor.sys_id));
931 : 61 : ds_put_format(ds, "\tactor sys_priority: %u\n",
932 : 61 : ntohs(actor.sys_priority));
933 : 61 : ds_put_format(ds, "\tactor port_id: %u\n",
934 : 61 : ntohs(actor.port_id));
935 : 61 : ds_put_format(ds, "\tactor port_priority: %u\n",
936 : 61 : ntohs(actor.port_priority));
937 : 61 : ds_put_format(ds, "\tactor key: %u\n",
938 : 61 : ntohs(actor.key));
939 : 61 : ds_put_cstr(ds, "\tactor state:");
940 : 61 : ds_put_lacp_state(ds, actor.state);
941 : 61 : ds_put_cstr(ds, "\n\n");
942 : :
943 : 61 : ds_put_format(ds, "\tpartner sys_id: " ETH_ADDR_FMT "\n",
944 : 366 : ETH_ADDR_ARGS(slave->partner.sys_id));
945 : 61 : ds_put_format(ds, "\tpartner sys_priority: %u\n",
946 : 61 : ntohs(slave->partner.sys_priority));
947 : 61 : ds_put_format(ds, "\tpartner port_id: %u\n",
948 : 61 : ntohs(slave->partner.port_id));
949 : 61 : ds_put_format(ds, "\tpartner port_priority: %u\n",
950 : 61 : ntohs(slave->partner.port_priority));
951 : 61 : ds_put_format(ds, "\tpartner key: %u\n",
952 : 61 : ntohs(slave->partner.key));
953 : 61 : ds_put_cstr(ds, "\tpartner state:");
954 : 61 : ds_put_lacp_state(ds, slave->partner.state);
955 : 61 : ds_put_cstr(ds, "\n");
956 : : }
957 : :
958 : 30 : shash_destroy(&slave_shash);
959 : 30 : free(sorted_slaves);
960 : 30 : }
961 : :
962 : : static void
963 : 29 : lacp_unixctl_show(struct unixctl_conn *conn, int argc, const char *argv[],
964 : : void *aux OVS_UNUSED) OVS_EXCLUDED(mutex)
965 : : {
966 : 29 : struct ds ds = DS_EMPTY_INITIALIZER;
967 : : struct lacp *lacp;
968 : :
969 : 29 : lacp_lock();
970 [ + + ]: 29 : if (argc > 1) {
971 : 26 : lacp = lacp_find(argv[1]);
972 [ - + ]: 26 : if (!lacp) {
973 : 0 : unixctl_command_reply_error(conn, "no such lacp object");
974 : 0 : goto out;
975 : : }
976 : 26 : lacp_print_details(&ds, lacp);
977 : : } else {
978 [ + + ]: 7 : LIST_FOR_EACH (lacp, node, all_lacps) {
979 : 4 : lacp_print_details(&ds, lacp);
980 : : }
981 : : }
982 : :
983 : 29 : unixctl_command_reply(conn, ds_cstr(&ds));
984 : 29 : ds_destroy(&ds);
985 : :
986 : : out:
987 : 29 : lacp_unlock();
988 : 29 : }
989 : :
990 : : /* Extract a snapshot of the current state and counters for a slave port.
991 : : Return false if the slave is not active. */
992 : : bool
993 : 2 : lacp_get_slave_stats(const struct lacp *lacp, const void *slave_, struct lacp_slave_stats *stats)
994 : : OVS_EXCLUDED(mutex)
995 : : {
996 : : struct slave *slave;
997 : : struct lacp_info actor;
998 : : bool ret;
999 : :
1000 : 2 : ovs_mutex_lock(&mutex);
1001 : :
1002 : 2 : slave = slave_lookup(lacp, slave_);
1003 [ + - ]: 2 : if (slave) {
1004 : 2 : ret = true;
1005 : 2 : slave_get_actor(slave, &actor);
1006 : 2 : stats->dot3adAggPortActorSystemID = actor.sys_id;
1007 : 2 : stats->dot3adAggPortPartnerOperSystemID = slave->partner.sys_id;
1008 [ + - ]: 2 : stats->dot3adAggPortAttachedAggID = (lacp->key_slave->key ?
1009 : 2 : lacp->key_slave->key :
1010 : 0 : lacp->key_slave->port_id);
1011 : :
1012 : : /* Construct my admin-state. Assume aggregation is configured on. */
1013 : 2 : stats->dot3adAggPortActorAdminState = LACP_STATE_AGG;
1014 [ + - ]: 2 : if (lacp->active) {
1015 : 2 : stats->dot3adAggPortActorAdminState |= LACP_STATE_ACT;
1016 : : }
1017 [ + - ]: 2 : if (lacp->fast) {
1018 : 2 : stats->dot3adAggPortActorAdminState |= LACP_STATE_TIME;
1019 : : }
1020 : : /* XXX Not sure how to know the partner admin state. It
1021 : : * might have to be captured and remembered during the
1022 : : * negotiation phase.
1023 : : */
1024 : 2 : stats->dot3adAggPortPartnerAdminState = 0;
1025 : :
1026 : 2 : stats->dot3adAggPortActorOperState = actor.state;
1027 : 2 : stats->dot3adAggPortPartnerOperState = slave->partner.state;
1028 : :
1029 : : /* Read out the latest counters */
1030 : 2 : stats->dot3adAggPortStatsLACPDUsRx = slave->count_rx_pdus;
1031 : 2 : stats->dot3adAggPortStatsIllegalRx = slave->count_rx_pdus_bad;
1032 : 2 : stats->dot3adAggPortStatsLACPDUsTx = slave->count_tx_pdus;
1033 : : } else {
1034 : 0 : ret = false;
1035 : : }
1036 : 2 : ovs_mutex_unlock(&mutex);
1037 : 2 : return ret;
1038 : :
1039 : : }
|