]>
git.proxmox.com Git - mirror_ovs.git/blob - lib/lacp.c
1 /* Copyright (c) 2011 Nicira Networks
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include "dynamic-string.h"
27 #include "poll-loop.h"
33 VLOG_DEFINE_THIS_MODULE(lacp
);
36 LACP_CURRENT
, /* Current State. Partner up to date. */
37 LACP_EXPIRED
, /* Expired State. Partner out of date. */
38 LACP_DEFAULTED
, /* Defaulted State. No partner. */
42 struct list node
; /* Node in all_lacps list. */
43 char *name
; /* Name of this lacp object. */
44 uint8_t sys_id
[ETH_ADDR_LEN
]; /* System ID. */
45 uint16_t sys_priority
; /* System Priority. */
46 bool active
; /* Active or Passive. */
48 struct hmap slaves
; /* Slaves this LACP object controls. */
49 struct slave
*key_slave
; /* Slave whose ID will be the aggregation key. */
51 bool fast
; /* Fast or Slow LACP time. */
52 bool negotiated
; /* True if LACP negotiations were successful. */
53 bool update
; /* True if lacp_update() needs to be called. */
57 void *aux
; /* Handle used to identify this slave. */
58 struct hmap_node node
; /* Node in master's slaves map. */
60 struct lacp
*lacp
; /* LACP object containing this slave. */
61 uint16_t port_id
; /* Port ID. */
62 uint16_t port_priority
; /* Port Priority. */
63 char *name
; /* Name of this slave. */
65 enum slave_status status
; /* Slave status. */
66 bool attached
; /* Attached. Traffic may flow. */
67 bool enabled
; /* Enabled. Traffic is flowing. */
68 struct lacp_info partner
; /* Partner information. */
69 struct lacp_info ntt_actor
; /* Used to decide if we Need To Transmit. */
70 struct timer tx
; /* Next message transmission timer. */
71 struct timer rx
; /* Expected message receive timer. */
74 static struct list all_lacps
= LIST_INITIALIZER(&all_lacps
);
76 static void lacp_update_attached(struct lacp
*);
78 static void slave_destroy(struct slave
*);
79 static void slave_set_defaulted(struct slave
*);
80 static void slave_set_expired(struct slave
*);
81 static void slave_get_actor(struct slave
*, struct lacp_info
*actor
);
82 static void slave_get_priority(struct slave
*, struct lacp_info
*priority
);
83 static bool slave_may_tx(const struct slave
*);
84 static struct slave
*slave_lookup(const struct lacp
*, const void *slave
);
85 static bool info_tx_equal(struct lacp_info
*, struct lacp_info
*);
87 static void lacp_unixctl_show(struct unixctl_conn
*, const char *args
,
90 /* Initializes the lacp module. */
94 unixctl_command_register("lacp/show", lacp_unixctl_show
, NULL
);
97 /* Creates a LACP object. */
103 lacp
= xzalloc(sizeof *lacp
);
104 hmap_init(&lacp
->slaves
);
105 list_push_back(&all_lacps
, &lacp
->node
);
109 /* Destroys 'lacp' and its slaves. Does nothing if 'lacp' is NULL. */
111 lacp_destroy(struct lacp
*lacp
)
114 struct slave
*slave
, *next
;
116 HMAP_FOR_EACH_SAFE (slave
, next
, node
, &lacp
->slaves
) {
117 slave_destroy(slave
);
120 hmap_destroy(&lacp
->slaves
);
121 list_remove(&lacp
->node
);
127 /* Configures 'lacp' with the given 'name', 'sys_id', 'sys_priority', and
128 * 'active' parameters. */
130 lacp_configure(struct lacp
*lacp
, const char *name
,
131 uint8_t sys_id
[ETH_ADDR_LEN
], uint16_t sys_priority
,
132 bool active
, bool fast
)
134 if (!lacp
->name
|| strcmp(name
, lacp
->name
)) {
136 lacp
->name
= xstrdup(name
);
139 memcpy(lacp
->sys_id
, sys_id
, ETH_ADDR_LEN
);
140 lacp
->sys_priority
= sys_priority
;
141 lacp
->active
= active
;
145 /* Processes 'pdu', a parsed LACP packet received on 'slave_'. This function
146 * should be called on all packets received on 'slave_' with Ethernet Type
147 * ETH_TYPE_LACP and parsable by parse_lacp_packet(). */
149 lacp_process_pdu(struct lacp
*lacp
, const void *slave_
,
150 const struct lacp_pdu
*pdu
)
152 struct slave
*slave
= slave_lookup(lacp
, slave_
);
154 slave
->status
= LACP_CURRENT
;
155 timer_set_duration(&slave
->rx
, (lacp
->fast
157 : LACP_SLOW_TIME_RX
));
159 slave
->ntt_actor
= pdu
->partner
;
161 /* Update our information about our partner if it's out of date. This may
162 * cause priorities to change so re-calculate attached status of all
164 if (memcmp(&slave
->partner
, &pdu
->actor
, sizeof pdu
->actor
)) {
166 slave
->partner
= pdu
->actor
;
170 /* Returns true if 'lacp' has successfully negotiated with its partner. False
171 * if 'lacp' is NULL. */
173 lacp_negotiated(const struct lacp
*lacp
)
175 return lacp
? lacp
->negotiated
: false;
178 /* Registers 'slave_' as subordinate to 'lacp'. This should be called at least
179 * once per slave in a LACP managed bond. Should also be called whenever a
180 * slave's name, port_id, or port_priority change. */
182 lacp_slave_register(struct lacp
*lacp
, void *slave_
, const char *name
,
183 uint16_t port_id
, uint16_t port_priority
)
185 struct slave
*slave
= slave_lookup(lacp
, slave_
);
188 slave
= xzalloc(sizeof *slave
);
191 hmap_insert(&lacp
->slaves
, &slave
->node
, hash_pointer(slave_
, 0));
192 slave_set_defaulted(slave
);
194 if (!lacp
->key_slave
) {
195 lacp
->key_slave
= slave
;
199 if (!slave
->name
|| strcmp(name
, slave
->name
)) {
201 slave
->name
= xstrdup(name
);
204 if (slave
->port_id
!= port_id
|| slave
->port_priority
!= port_priority
) {
206 slave
->port_id
= port_id
;
207 slave
->port_priority
= port_priority
;
211 if (lacp
->active
|| lacp
->negotiated
) {
212 slave_set_expired(slave
);
217 /* Unregisters 'slave_' with 'lacp'. */
219 lacp_slave_unregister(struct lacp
*lacp
, const void *slave_
)
221 struct slave
*slave
= slave_lookup(lacp
, slave_
);
224 slave_destroy(slave
);
228 /* Should be called regularly to indicate whether 'slave_' is enabled. An
229 * enabled slave is allowed to send and receive traffic. Generally a slave
230 * should not be enabled if its carrier is down, or lacp_slave_may_enable()
231 * indicates it should not be enabled. */
233 lacp_slave_enable(struct lacp
*lacp
, void *slave_
, bool enabled
)
235 slave_lookup(lacp
, slave_
)->enabled
= enabled
;
238 /* This function should be called whenever the carrier status of 'slave_' has
241 lacp_slave_carrier_changed(const struct lacp
*lacp
, const void *slave_
)
243 struct slave
*slave
= slave_lookup(lacp
, slave_
);
245 if (slave
->status
== LACP_CURRENT
|| slave
->lacp
->active
) {
246 slave_set_expired(slave
);
250 /* This function should be called before enabling 'slave_' to send or receive
251 * traffic. If it returns false, 'slave_' should not enabled. As a
252 * convenience, returns true if 'lacp' is NULL. */
254 lacp_slave_may_enable(const struct lacp
*lacp
, const void *slave_
)
257 struct slave
*slave
= slave_lookup(lacp
, slave_
);
259 /* The slave may be enabled if it's attached to an aggregator and its
260 * partner is synchronized. The only exception is defaulted slaves.
261 * They are not required to have synchronized partners because they
262 * have no partners at all. They will only be attached if negotiations
263 * failed on all slaves in the bond. */
264 return slave
->attached
&& (slave
->partner
.state
& LACP_STATE_SYNC
265 || slave
->status
== LACP_DEFAULTED
);
271 /* This function should be called periodically to update 'lacp'. */
273 lacp_run(struct lacp
*lacp
, lacp_send_pdu
*send_pdu
)
277 HMAP_FOR_EACH (slave
, node
, &lacp
->slaves
) {
278 if (timer_expired(&slave
->rx
)) {
279 if (slave
->status
== LACP_CURRENT
) {
280 slave_set_expired(slave
);
281 } else if (slave
->status
== LACP_EXPIRED
) {
282 slave_set_defaulted(slave
);
288 lacp_update_attached(lacp
);
291 HMAP_FOR_EACH (slave
, node
, &lacp
->slaves
) {
293 struct lacp_info actor
;
295 if (!slave_may_tx(slave
)) {
299 slave_get_actor(slave
, &actor
);
301 if (timer_expired(&slave
->tx
)
302 || !info_tx_equal(&actor
, &slave
->ntt_actor
)) {
304 slave
->ntt_actor
= actor
;
305 compose_lacp_pdu(&actor
, &slave
->partner
, &pdu
);
306 send_pdu(slave
->aux
, &pdu
);
308 timer_set_duration(&slave
->tx
,
309 (slave
->partner
.state
& LACP_STATE_TIME
311 : LACP_SLOW_TIME_TX
));
316 /* Causes poll_block() to wake up when lacp_run() needs to be called again. */
318 lacp_wait(struct lacp
*lacp
)
322 HMAP_FOR_EACH (slave
, node
, &lacp
->slaves
) {
323 if (slave_may_tx(slave
)) {
324 timer_wait(&slave
->tx
);
327 if (slave
->status
!= LACP_DEFAULTED
) {
328 timer_wait(&slave
->rx
);
333 /* Static Helpers. */
335 /* Updates the attached status of all slaves controlled b 'lacp' and sets its
336 * negotiated parameter to true if any slaves are attachable. */
338 lacp_update_attached(struct lacp
*lacp
)
340 struct slave
*lead
, *slave
;
341 struct lacp_info lead_pri
;
342 static struct vlog_rate_limit rl
= VLOG_RATE_LIMIT_INIT(1, 10);
344 lacp
->update
= false;
347 HMAP_FOR_EACH (slave
, node
, &lacp
->slaves
) {
348 struct lacp_info pri
;
350 slave
->attached
= true;
352 /* XXX: In the future allow users to configure the expected system ID.
353 * For now just special case loopback. */
354 if (eth_addr_equals(slave
->partner
.sys_id
, slave
->lacp
->sys_id
)) {
355 VLOG_WARN_RL(&rl
, "slave %s: Loopback detected. Slave is "
356 "connected to its own bond", slave
->name
);
357 slave
->attached
= false;
361 if (slave
->status
== LACP_DEFAULTED
) {
365 slave_get_priority(slave
, &pri
);
367 if (!lead
|| memcmp(&pri
, &lead_pri
, sizeof pri
) < 0) {
373 lacp
->negotiated
= lead
!= NULL
;
376 HMAP_FOR_EACH (slave
, node
, &lacp
->slaves
) {
377 if (slave
->status
== LACP_DEFAULTED
378 || lead
->partner
.key
!= slave
->partner
.key
379 || !eth_addr_equals(lead
->partner
.sys_id
,
380 slave
->partner
.sys_id
)) {
381 slave
->attached
= false;
388 slave_destroy(struct slave
*slave
)
391 struct lacp
*lacp
= slave
->lacp
;
394 hmap_remove(&lacp
->slaves
, &slave
->node
);
396 if (lacp
->key_slave
== slave
) {
397 struct hmap_node
*slave_node
= hmap_first(&lacp
->slaves
);
400 lacp
->key_slave
= CONTAINER_OF(slave_node
, struct slave
, node
);
402 lacp
->key_slave
= NULL
;
412 slave_set_defaulted(struct slave
*slave
)
414 memset(&slave
->partner
, 0, sizeof slave
->partner
);
416 slave
->lacp
->update
= true;
417 slave
->status
= LACP_DEFAULTED
;
421 slave_set_expired(struct slave
*slave
)
423 slave
->status
= LACP_EXPIRED
;
424 slave
->partner
.state
|= LACP_STATE_TIME
;
425 slave
->partner
.state
&= ~LACP_STATE_SYNC
;
426 timer_set_duration(&slave
->rx
, LACP_FAST_TIME_RX
);
430 slave_get_actor(struct slave
*slave
, struct lacp_info
*actor
)
434 if (slave
->lacp
->active
) {
435 state
|= LACP_STATE_ACT
;
438 if (slave
->lacp
->fast
) {
439 state
|= LACP_STATE_TIME
;
442 if (slave
->attached
) {
443 state
|= LACP_STATE_SYNC
;
446 if (slave
->status
== LACP_DEFAULTED
) {
447 state
|= LACP_STATE_DEF
;
450 if (slave
->status
== LACP_EXPIRED
) {
451 state
|= LACP_STATE_EXP
;
454 if (hmap_count(&slave
->lacp
->slaves
) > 1) {
455 state
|= LACP_STATE_AGG
;
458 if (slave
->enabled
) {
459 state
|= LACP_STATE_COL
| LACP_STATE_DIST
;
462 actor
->state
= state
;
463 actor
->key
= htons(slave
->lacp
->key_slave
->port_id
);
464 actor
->port_priority
= htons(slave
->port_priority
);
465 actor
->port_id
= htons(slave
->port_id
);
466 actor
->sys_priority
= htons(slave
->lacp
->sys_priority
);
467 memcpy(&actor
->sys_id
, slave
->lacp
->sys_id
, ETH_ADDR_LEN
);
470 /* Given 'slave', populates 'priority' with data representing its LACP link
471 * priority. If two priority objects populated by this function are compared
472 * using memcmp, the higher priority link will be less than the lower priority
475 slave_get_priority(struct slave
*slave
, struct lacp_info
*priority
)
477 uint16_t partner_priority
, actor_priority
;
479 /* Choose the lacp_info of the higher priority system by comparing their
480 * system priorities and mac addresses. */
481 actor_priority
= slave
->lacp
->sys_priority
;
482 partner_priority
= ntohs(slave
->partner
.sys_priority
);
483 if (actor_priority
< partner_priority
) {
484 slave_get_actor(slave
, priority
);
485 } else if (partner_priority
< actor_priority
) {
486 *priority
= slave
->partner
;
487 } else if (eth_addr_compare_3way(slave
->lacp
->sys_id
,
488 slave
->partner
.sys_id
) < 0) {
489 slave_get_actor(slave
, priority
);
491 *priority
= slave
->partner
;
494 /* Key and state are not used in priority comparisons. */
500 slave_may_tx(const struct slave
*slave
)
502 return slave
->lacp
->active
|| slave
->status
!= LACP_DEFAULTED
;
505 static struct slave
*
506 slave_lookup(const struct lacp
*lacp
, const void *slave_
)
510 HMAP_FOR_EACH_IN_BUCKET (slave
, node
, hash_pointer(slave_
, 0),
512 if (slave
->aux
== slave_
) {
520 /* Two lacp_info structures are tx_equal if and only if they do not differ in
521 * ways which would require a lacp_pdu transmission. */
523 info_tx_equal(struct lacp_info
*a
, struct lacp_info
*b
)
526 /* LACP specification dictates that we transmit whenever the actor and
527 * remote_actor differ in the following fields: Port, Port Priority,
528 * System, System Priority, Aggregation Key, Activity State, Timeout State,
529 * Sync State, and Aggregation State. The state flags are most likely to
530 * change so are checked first. */
531 return !((a
->state
^ b
->state
) & (LACP_STATE_ACT
535 && a
->port_id
== b
->port_id
536 && a
->port_priority
== b
->port_priority
538 && a
->sys_priority
== b
->sys_priority
539 && eth_addr_equals(a
->sys_id
, b
->sys_id
);
543 lacp_find(const char *name
)
547 LIST_FOR_EACH (lacp
, node
, &all_lacps
) {
548 if (!strcmp(lacp
->name
, name
)) {
557 ds_put_lacp_state(struct ds
*ds
, uint8_t state
)
559 if (state
& LACP_STATE_ACT
) {
560 ds_put_cstr(ds
, "activity ");
563 if (state
& LACP_STATE_TIME
) {
564 ds_put_cstr(ds
, "timeout ");
567 if (state
& LACP_STATE_AGG
) {
568 ds_put_cstr(ds
, "aggregation ");
571 if (state
& LACP_STATE_SYNC
) {
572 ds_put_cstr(ds
, "synchronized ");
575 if (state
& LACP_STATE_COL
) {
576 ds_put_cstr(ds
, "collecting ");
579 if (state
& LACP_STATE_DIST
) {
580 ds_put_cstr(ds
, "distributing ");
583 if (state
& LACP_STATE_DEF
) {
584 ds_put_cstr(ds
, "defaulted ");
587 if (state
& LACP_STATE_EXP
) {
588 ds_put_cstr(ds
, "expired ");
593 lacp_unixctl_show(struct unixctl_conn
*conn
,
594 const char *args
, void *aux OVS_UNUSED
)
596 struct ds ds
= DS_EMPTY_INITIALIZER
;
600 lacp
= lacp_find(args
);
602 unixctl_command_reply(conn
, 501, "no such lacp object");
606 ds_put_format(&ds
, "lacp: %s\n", lacp
->name
);
607 ds_put_format(&ds
, "\tstatus: %s %s\n",
608 lacp
->active
? "active" : "passive",
609 lacp
->negotiated
? "negotiated" : "");
610 ds_put_format(&ds
, "\tsys_id: " ETH_ADDR_FMT
"\n", ETH_ADDR_ARGS(lacp
->sys_id
));
611 ds_put_format(&ds
, "\tsys_priority: %u\n", lacp
->sys_priority
);
612 ds_put_cstr(&ds
, "\taggregation key: ");
613 if (lacp
->key_slave
) {
614 ds_put_format(&ds
, "%u", lacp
->key_slave
->port_id
);
616 ds_put_cstr(&ds
, "none");
618 ds_put_cstr(&ds
, "\n");
620 HMAP_FOR_EACH (slave
, node
, &lacp
->slaves
) {
622 struct lacp_info actor
;
624 slave_get_actor(slave
, &actor
);
625 switch (slave
->status
) {
633 status
= "defaulted";
639 ds_put_format(&ds
, "\nslave: %s: %s %s %s\n", slave
->name
, status
,
640 slave
->attached
? "attached" : "detached",
641 slave
->enabled
? "enabled" : "disabled");
642 ds_put_format(&ds
, "\tport_id: %u\n", slave
->port_id
);
643 ds_put_format(&ds
, "\tport_priority: %u\n", slave
->port_priority
);
645 ds_put_format(&ds
, "\n\tactor sys_id: " ETH_ADDR_FMT
"\n",
646 ETH_ADDR_ARGS(actor
.sys_id
));
647 ds_put_format(&ds
, "\tactor sys_priority: %u\n",
648 ntohs(actor
.sys_priority
));
649 ds_put_format(&ds
, "\tactor port_id: %u\n",
650 ntohs(actor
.port_id
));
651 ds_put_format(&ds
, "\tactor port_priority: %u\n",
652 ntohs(actor
.port_priority
));
653 ds_put_format(&ds
, "\tactor key: %u\n",
655 ds_put_cstr(&ds
, "\tactor state: ");
656 ds_put_lacp_state(&ds
, actor
.state
);
657 ds_put_cstr(&ds
, "\n\n");
659 ds_put_format(&ds
, "\tpartner sys_id: " ETH_ADDR_FMT
"\n",
660 ETH_ADDR_ARGS(slave
->partner
.sys_id
));
661 ds_put_format(&ds
, "\tpartner sys_priority: %u\n",
662 ntohs(slave
->partner
.sys_priority
));
663 ds_put_format(&ds
, "\tpartner port_id: %u\n",
664 ntohs(slave
->partner
.port_id
));
665 ds_put_format(&ds
, "\tpartner port_priority: %u\n",
666 ntohs(slave
->partner
.port_priority
));
667 ds_put_format(&ds
, "\tpartner key: %u\n",
668 ntohs(slave
->partner
.key
));
669 ds_put_cstr(&ds
, "\tpartner state: ");
670 ds_put_lacp_state(&ds
, slave
->partner
.state
);
671 ds_put_cstr(&ds
, "\n");
674 unixctl_command_reply(conn
, 200, ds_cstr(&ds
));