vswitchd: Modularize LACP.
[sliver-openvswitch.git] / lib / lacp.c
1 /* Copyright (c) 2011 Nicira Networks
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 <assert.h>
20 #include <stdlib.h>
21
22 #include "dynamic-string.h"
23 #include "hash.h"
24 #include "hmap.h"
25 #include "ofpbuf.h"
26 #include "packets.h"
27 #include "poll-loop.h"
28 #include "timeval.h"
29 #include "unixctl.h"
30 #include "vlog.h"
31
32 VLOG_DEFINE_THIS_MODULE(lacp);
33
34 enum slave_status {
35     LACP_CURRENT,   /* Current State.  Partner up to date. */
36     LACP_EXPIRED,   /* Expired State.  Partner out of date. */
37     LACP_DEFAULTED, /* Defaulted State.  No partner. */
38 };
39
40 struct lacp {
41     struct list node;             /* Node in all_lacps list. */
42     char *name;                   /* Name of this lacp object. */
43     uint8_t sys_id[ETH_ADDR_LEN]; /* System ID. */
44     uint16_t sys_priority;        /* System Priority. */
45     bool active;                  /* Active or Passive. */
46
47     struct hmap slaves;      /* Slaves this LACP object controls. */
48     struct slave *key_slave; /* Slave whose ID will be the aggregation key. */
49
50     bool negotiated;         /* True if LACP negotiations were successful. */
51     bool update;             /* True if lacp_update() needs to be called. */
52 };
53
54 struct slave {
55     void *aux;                    /* Handle used to identify this slave. */
56     struct hmap_node node;        /* Node in master's slaves map. */
57
58     struct lacp *lacp;            /* LACP object containing this slave. */
59     uint16_t port_id;             /* Port ID. */
60     uint16_t port_priority;       /* Port Priority. */
61     char *name;                   /* Name of this slave. */
62
63     enum slave_status status;     /* Slave status. */
64     bool attached;                /* Attached. Traffic may flow. */
65     bool enabled;                 /* Enabled. Traffic is flowing. */
66     struct lacp_info actor;       /* Actor information. */
67     struct lacp_info partner;     /* Partner information. */
68     long long int tx;             /* Next message transmission time. */
69     long long int rx;             /* Expected message receive time. */
70 };
71
72 static struct list all_lacps = LIST_INITIALIZER(&all_lacps);
73
74 static void lacp_update_attached(struct lacp *);
75
76 static void slave_destroy(struct slave *);
77 static void slave_set_defaulted(struct slave *);
78 static void slave_set_expired(struct slave *);
79 static void slave_update_actor(struct slave *);
80 static void slave_get_priority(struct slave *, struct lacp_info *priority);
81 static bool slave_may_tx(const struct slave *);
82 static struct slave *slave_lookup(const struct lacp *, const void *slave);
83
84 static void lacp_unixctl_show(struct unixctl_conn *, const char *args,
85                               void *aux);
86
87 /* Initializes the lacp module. */
88 void
89 lacp_init(void)
90 {
91     unixctl_command_register("lacp/show", lacp_unixctl_show, NULL);
92 }
93
94 /* Creates a LACP object. */
95 struct lacp *
96 lacp_create(void)
97 {
98     struct lacp *lacp;
99
100     lacp = xzalloc(sizeof *lacp);
101     hmap_init(&lacp->slaves);
102     list_push_back(&all_lacps, &lacp->node);
103     return lacp;
104 }
105
106 /* Destroys 'lacp' and its slaves. Does nothing if 'lacp' is NULL. */
107 void
108 lacp_destroy(struct lacp *lacp)
109 {
110     if (lacp) {
111         struct slave *slave, *next;
112
113         HMAP_FOR_EACH_SAFE (slave, next, node, &lacp->slaves) {
114             slave_destroy(slave);
115         }
116
117         hmap_destroy(&lacp->slaves);
118         list_remove(&lacp->node);
119         free(lacp->name);
120         free(lacp);
121     }
122 }
123
124 /* Configures 'lacp' with the given 'name', 'sys_id', 'sys_priority', and
125  * 'active' parameters. */
126 void
127 lacp_configure(struct lacp *lacp, const char *name,
128                uint8_t sys_id[ETH_ADDR_LEN], uint16_t sys_priority,
129                bool active)
130 {
131     if (!lacp->name || strcmp(name, lacp->name)) {
132         free(lacp->name);
133         lacp->name = xstrdup(name);
134     }
135
136     memcpy(lacp->sys_id, sys_id, ETH_ADDR_LEN);
137     lacp->sys_priority = sys_priority;
138     lacp->active = active;
139 }
140
141 /* Processes 'pdu', a parsed LACP packet received on 'slave_'.  This function
142  * should be called on all packets received on 'slave_' with Ethernet Type
143  * ETH_TYPE_LACP and parsable by parse_lacp_packet(). */
144 void
145 lacp_process_pdu(struct lacp *lacp, const void *slave_,
146                  const struct lacp_pdu *pdu)
147 {
148     struct slave *slave = slave_lookup(lacp, slave_);
149
150     slave->status = LACP_CURRENT;
151     slave->rx = time_msec() + LACP_SLOW_TIME_RX;
152
153     /* Check if our partner has incorrect information about our current state.
154      * If so update them. */
155     slave_update_actor(slave);
156     if (memcmp(&slave->actor, &pdu->partner, sizeof pdu->partner)) {
157         slave->tx = LLONG_MIN;
158     }
159
160     /* Update our information about our partner if it's out of date.  This may
161      * cause priorities to change so re-calculate attached status of all
162      * slaves.  */
163     if (memcmp(&slave->partner, &pdu->actor, sizeof pdu->actor)) {
164         lacp->update = true;
165         slave->partner = pdu->actor;
166     }
167 }
168
169 /* Returns true if 'lacp' has successfully negotiated with its partner.  False
170  * if 'lacp' is NULL. */
171 bool
172 lacp_negotiated(const struct lacp *lacp)
173 {
174     return lacp ? lacp->negotiated : false;
175 }
176
177 /* Registers 'slave_' as subordinate to 'lacp'.  This should be called at least
178  * once per slave in a LACP managed bond.  Should also be called whenever a
179  * slave's name, port_id, or port_priority change. */
180 void
181 lacp_slave_register(struct lacp *lacp, void *slave_, const char *name,
182                     uint16_t port_id, uint16_t port_priority)
183 {
184     struct slave *slave = slave_lookup(lacp, slave_);
185
186     if (!slave) {
187         slave = xzalloc(sizeof *slave);
188         slave->lacp = lacp;
189         slave->aux = slave_;
190         hmap_insert(&lacp->slaves, &slave->node, hash_pointer(slave_, 0));
191         slave_set_defaulted(slave);
192
193         if (!lacp->key_slave) {
194             lacp->key_slave = slave;
195         }
196     }
197
198     if (!slave->name || strcmp(name, slave->name)) {
199         free(slave->name);
200         slave->name = xstrdup(name);
201     }
202
203     if (slave->port_id != port_id || slave->port_priority != port_priority) {
204
205         slave->port_id = port_id;
206         slave->port_priority = port_priority;
207
208         slave->tx = LLONG_MIN;
209         lacp->update = true;
210
211         if (lacp->active || lacp->negotiated) {
212             slave_set_expired(slave);
213         }
214     }
215 }
216
217 /* Unregisters 'slave_' with 'lacp'.  */
218 void
219 lacp_slave_unregister(struct lacp *lacp, const void *slave_)
220 {
221     struct slave *slave = slave_lookup(lacp, slave_);
222
223     if (slave) {
224         slave_destroy(slave);
225     }
226 }
227
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. */
232 void
233 lacp_slave_enable(struct lacp *lacp, void *slave_, bool enabled)
234 {
235     struct slave *slave = slave_lookup(lacp, slave_);
236
237     if (slave->enabled != enabled) {
238         slave->enabled = enabled;
239         slave->tx = LLONG_MIN;
240     }
241 }
242
243 /* This function should be called whenever the carrier status of 'slave_' has
244  * changed. */
245 void
246 lacp_slave_carrier_changed(const struct lacp *lacp, const void *slave_)
247 {
248     struct slave *slave = slave_lookup(lacp, slave_);
249
250     slave->tx = LLONG_MIN;
251     if (slave->status == LACP_CURRENT || slave->lacp->active) {
252         slave_set_expired(slave);
253     }
254 }
255
256 /* This function should be called before enabling 'slave_' to send or receive
257  * traffic.  If it returns false, 'slave_' should not enabled.  As a
258  * convenience, returns true if 'lacp' is NULL. */
259 bool
260 lacp_slave_may_enable(const struct lacp *lacp, const void *slave_)
261 {
262     if (lacp) {
263         struct slave *slave = slave_lookup(lacp, slave_);
264
265         /* The slave may be enabled if it's attached to an aggregator and its
266          * partner is synchronized.  The only exception is defaulted slaves.
267          * They are not required to have synchronized partners because they
268          * have no partners at all.  They will only be attached if negotiations
269          * failed on all slaves in the bond. */
270         return slave->attached && (slave->partner.state & LACP_STATE_SYNC
271                                    || slave->status == LACP_DEFAULTED);
272     } else {
273         return true;
274     }
275 }
276
277 /* This function should be called periodically to update 'lacp'. */
278 void
279 lacp_run(struct lacp *lacp, lacp_send_pdu *send_pdu)
280 {
281     struct slave *slave;
282
283     HMAP_FOR_EACH (slave, node, &lacp->slaves) {
284         if (time_msec() >= slave->rx) {
285             if (slave->status == LACP_CURRENT) {
286                 slave_set_expired(slave);
287             } else if (slave->status == LACP_EXPIRED) {
288                 slave_set_defaulted(slave);
289             }
290         }
291         slave_update_actor(slave);
292     }
293
294     if (lacp->update) {
295         lacp_update_attached(lacp);
296     }
297
298     HMAP_FOR_EACH (slave, node, &lacp->slaves) {
299         struct lacp_pdu pdu;
300
301         if (time_msec() < slave->tx || !slave_may_tx(slave)) {
302             continue;
303         }
304
305         compose_lacp_pdu(&slave->actor, &slave->partner, &pdu);
306         send_pdu(slave->aux, &pdu);
307
308         slave->tx = time_msec() +
309             (slave->partner.state & LACP_STATE_TIME
310              ? LACP_FAST_TIME_TX
311              : LACP_SLOW_TIME_TX);
312     }
313 }
314
315 /* Causes poll_block() to wake up when lacp_run() needs to be called again. */
316 void
317 lacp_wait(struct lacp *lacp)
318 {
319     struct slave *slave;
320
321     HMAP_FOR_EACH (slave, node, &lacp->slaves) {
322         if (slave_may_tx(slave)) {
323             poll_timer_wait_until(slave->tx);
324         }
325
326         if (slave->status != LACP_DEFAULTED) {
327             poll_timer_wait_until(slave->rx);
328         }
329     }
330 }
331 \f
332 /* Static Helpers. */
333
334 /* Updates the attached status of all slaves controlled b 'lacp' and sets its
335  * negotiated parameter to true if any slaves are attachable. */
336 static void
337 lacp_update_attached(struct lacp *lacp)
338 {
339     struct slave *lead, *slave;
340     struct lacp_info lead_pri;
341     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 10);
342
343     lacp->update = false;
344
345     lead = NULL;
346     HMAP_FOR_EACH (slave, node, &lacp->slaves) {
347         struct lacp_info pri;
348
349         slave->attached = true;
350
351         /* XXX: In the future allow users to configure the expected system ID.
352          * For now just special case loopback. */
353         if (eth_addr_equals(slave->partner.sys_id, slave->actor.sys_id)) {
354             VLOG_WARN_RL(&rl, "slave %s: Loopback detected. Slave is "
355                          "connected to its own bond", slave->name);
356             slave->attached = false;
357             continue;
358         }
359
360         if (slave->status == LACP_DEFAULTED) {
361             continue;
362         }
363
364         slave_get_priority(slave, &pri);
365
366         if (!lead || memcmp(&pri, &lead_pri, sizeof pri) < 0) {
367             lead = slave;
368             lead_pri = pri;
369         }
370     }
371
372     lacp->negotiated = lead != NULL;
373
374     if (lead) {
375         HMAP_FOR_EACH (slave, node, &lacp->slaves) {
376             if (slave->status == LACP_DEFAULTED
377                 || lead->partner.key != slave->partner.key
378                 || !eth_addr_equals(lead->partner.sys_id,
379                                     slave->partner.sys_id)) {
380                 slave->attached = false;
381             }
382         }
383     }
384 }
385
386 static void
387 slave_destroy(struct slave *slave)
388 {
389     if (slave) {
390         struct lacp *lacp = slave->lacp;
391
392         lacp->update = true;
393         hmap_remove(&lacp->slaves, &slave->node);
394
395         if (lacp->key_slave == slave) {
396             struct hmap_node *slave_node = hmap_first(&lacp->slaves);
397
398             if (slave_node) {
399                 lacp->key_slave = CONTAINER_OF(slave_node, struct slave, node);
400             } else {
401                 lacp->key_slave = NULL;
402             }
403         }
404
405         free(slave->name);
406         free(slave);
407     }
408 }
409
410 static void
411 slave_set_defaulted(struct slave *slave)
412 {
413     memset(&slave->partner, 0, sizeof slave->partner);
414
415     slave->tx = LLONG_MIN;
416     slave->lacp->update = true;
417     slave->status = LACP_DEFAULTED;
418 }
419
420 static void
421 slave_set_expired(struct slave *slave)
422 {
423     slave->status = LACP_EXPIRED;
424     slave->partner.state |= LACP_STATE_TIME;
425     slave->partner.state &= ~LACP_STATE_SYNC;
426
427     slave->rx = time_msec() + LACP_FAST_TIME_RX;
428     slave->tx = LLONG_MIN;
429 }
430
431 static void
432 slave_update_actor(struct slave *slave)
433 {
434     uint8_t state = 0;
435
436     if (slave->lacp->active) {
437         state |= LACP_STATE_ACT;
438     }
439
440     if (slave->attached) {
441         state |= LACP_STATE_SYNC;
442     }
443
444     if (slave->status == LACP_DEFAULTED) {
445         state |= LACP_STATE_DEF;
446     }
447
448     if (slave->status == LACP_EXPIRED) {
449         state |= LACP_STATE_EXP;
450     }
451
452     if (hmap_count(&slave->lacp->slaves) > 1) {
453         state |= LACP_STATE_AGG;
454     }
455
456     if (slave->enabled) {
457         state |= LACP_STATE_COL | LACP_STATE_DIST;
458     }
459
460     slave->actor.state = state;
461     slave->actor.key = htons(slave->lacp->key_slave->port_id);
462     slave->actor.port_priority = htons(slave->port_priority);
463     slave->actor.port_id = htons(slave->port_id);
464     slave->actor.sys_priority = htons(slave->lacp->sys_priority);
465     memcpy(&slave->actor.sys_id, slave->lacp->sys_id, ETH_ADDR_LEN);
466 }
467
468 /* Given 'slave', populates 'priority' with data representing its LACP link
469  * priority.  If two priority objects populated by this function are compared
470  * using memcmp, the higher priority link will be less than the lower priority
471  * link. */
472 static void
473 slave_get_priority(struct slave *slave, struct lacp_info *priority)
474 {
475     uint16_t partner_priority, actor_priority;
476
477     /* Choose the lacp_info of the higher priority system by comparing their
478      * system priorities and mac addresses. */
479     actor_priority = ntohs(slave->actor.sys_priority);
480     partner_priority = ntohs(slave->partner.sys_priority);
481     if (actor_priority < partner_priority) {
482         *priority = slave->actor;
483     } else if (partner_priority < actor_priority) {
484         *priority = slave->partner;
485     } else if (eth_addr_compare_3way(slave->actor.sys_id,
486                                      slave->partner.sys_id) < 0) {
487         *priority = slave->actor;
488     } else {
489         *priority = slave->partner;
490     }
491
492     /* Key and state are not used in priority comparisons. */
493     priority->key = 0;
494     priority->state = 0;
495 }
496
497 static bool
498 slave_may_tx(const struct slave *slave)
499 {
500     return slave->lacp->active || slave->status != LACP_DEFAULTED;
501 }
502
503 static struct slave *
504 slave_lookup(const struct lacp *lacp, const void *slave_)
505 {
506     struct slave *slave;
507
508     HMAP_FOR_EACH_IN_BUCKET (slave, node, hash_pointer(slave_, 0),
509                              &lacp->slaves) {
510         if (slave->aux == slave_) {
511             return slave;
512         }
513     }
514
515     return NULL;
516 }
517 \f
518 static struct lacp *
519 lacp_find(const char *name)
520 {
521     struct lacp *lacp;
522
523     LIST_FOR_EACH (lacp, node, &all_lacps) {
524         if (!strcmp(lacp->name, name)) {
525             return lacp;
526         }
527     }
528
529     return NULL;
530 }
531
532 static void
533 ds_put_lacp_state(struct ds *ds, uint8_t state)
534 {
535     if (state & LACP_STATE_ACT) {
536         ds_put_cstr(ds, "activity ");
537     }
538
539     if (state & LACP_STATE_TIME) {
540         ds_put_cstr(ds, "timeout ");
541     }
542
543     if (state & LACP_STATE_AGG) {
544         ds_put_cstr(ds, "aggregation ");
545     }
546
547     if (state & LACP_STATE_SYNC) {
548         ds_put_cstr(ds, "synchronized ");
549     }
550
551     if (state & LACP_STATE_COL) {
552         ds_put_cstr(ds, "collecting ");
553     }
554
555     if (state & LACP_STATE_DIST) {
556         ds_put_cstr(ds, "distributing ");
557     }
558
559     if (state & LACP_STATE_DEF) {
560         ds_put_cstr(ds, "defaulted ");
561     }
562
563     if (state & LACP_STATE_EXP) {
564         ds_put_cstr(ds, "expired ");
565     }
566 }
567
568 static void
569 lacp_unixctl_show(struct unixctl_conn *conn,
570                   const char *args, void *aux OVS_UNUSED)
571 {
572     struct ds ds = DS_EMPTY_INITIALIZER;
573     struct lacp *lacp;
574     struct slave *slave;
575
576     lacp = lacp_find(args);
577     if (!lacp) {
578         unixctl_command_reply(conn, 501, "no such lacp object");
579         return;
580     }
581
582     ds_put_format(&ds, "lacp: %s\n", lacp->name);
583     ds_put_format(&ds, "\tstatus: %s %s\n",
584                   lacp->active ? "active" : "passive",
585                   lacp->negotiated ? "negotiated" : "");
586     ds_put_format(&ds, "\tsys_id: " ETH_ADDR_FMT "\n", ETH_ADDR_ARGS(lacp->sys_id));
587     ds_put_format(&ds, "\tsys_priority: %u\n", lacp->sys_priority);
588     ds_put_cstr(&ds, "\taggregation key: ");
589     if (lacp->key_slave) {
590         ds_put_format(&ds, "%u", lacp->key_slave->port_id);
591     } else {
592         ds_put_cstr(&ds, "none");
593     }
594     ds_put_cstr(&ds, "\n");
595
596     HMAP_FOR_EACH (slave, node, &lacp->slaves) {
597         char *status;
598
599         slave_update_actor(slave);
600         switch (slave->status) {
601         case LACP_CURRENT:
602             status = "current";
603             break;
604         case LACP_EXPIRED:
605             status = "expired";
606             break;
607         case LACP_DEFAULTED:
608             status = "defaulted";
609             break;
610         default:
611             NOT_REACHED();
612         }
613
614         ds_put_format(&ds, "\nslave: %s: %s %s %s\n", slave->name, status,
615                       slave->attached ? "attached" : "detached",
616                       slave->enabled ? "enabled" : "disabled");
617         ds_put_format(&ds, "\tport_id: %u\n", slave->port_id);
618         ds_put_format(&ds, "\tport_priority: %u\n", slave->port_priority);
619
620         ds_put_format(&ds, "\n\tactor sys_id: " ETH_ADDR_FMT "\n",
621                       ETH_ADDR_ARGS(slave->actor.sys_id));
622         ds_put_format(&ds, "\tactor sys_priority: %u\n",
623                       ntohs(slave->actor.sys_priority));
624         ds_put_format(&ds, "\tactor port_id: %u\n",
625                       ntohs(slave->actor.port_id));
626         ds_put_format(&ds, "\tactor port_priority: %u\n",
627                       ntohs(slave->actor.port_priority));
628         ds_put_format(&ds, "\tactor key: %u\n",
629                       ntohs(slave->actor.key));
630         ds_put_cstr(&ds, "\tactor state: ");
631         ds_put_lacp_state(&ds, slave->actor.state);
632         ds_put_cstr(&ds, "\n\n");
633
634         ds_put_format(&ds, "\tpartner sys_id: " ETH_ADDR_FMT "\n",
635                       ETH_ADDR_ARGS(slave->partner.sys_id));
636         ds_put_format(&ds, "\tpartner sys_priority: %u\n",
637                       ntohs(slave->partner.sys_priority));
638         ds_put_format(&ds, "\tpartner port_id: %u\n",
639                       ntohs(slave->partner.port_id));
640         ds_put_format(&ds, "\tpartner port_priority: %u\n",
641                       ntohs(slave->partner.port_priority));
642         ds_put_format(&ds, "\tpartner key: %u\n",
643                       ntohs(slave->partner.key));
644         ds_put_cstr(&ds, "\tpartner state: ");
645         ds_put_lacp_state(&ds, slave->partner.state);
646         ds_put_cstr(&ds, "\n");
647     }
648
649     unixctl_command_reply(conn, 200, ds_cstr(&ds));
650     ds_destroy(&ds);
651 }