lldp-structs: Fix use of list of struct lldpd_mgmt.
[cascardo/ovs.git] / lib / ovs-lldp.c
1 /*
2  * Copyright (c) 2015 Nicira, Inc.
3  * Copyright (c) 2014 WindRiver, Inc.
4  * Copyright (c) 2015 Avaya, Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 /* Implementation of Auto Attach.
20  * Based on sample implementation in 802.1ab.  Above copyright and license
21  * applies to all modifications.
22  * Limitations:
23  * - No support for multiple bridge.
24  * - Auto Attach state machine not implemented.
25  * - Auto Attach and LLDP code are bundled together.  The plan is to decoupled
26  *   them.
27  */
28
29 #include <config.h>
30 #include "ovs-lldp.h"
31 #include <arpa/inet.h>
32 #include <inttypes.h>
33 #include <netinet/in.h>
34 #include <stdbool.h>
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include "dynamic-string.h"
38 #include "flow.h"
39 #include "list.h"
40 #include "lldp/lldpd.h"
41 #include "lldp/lldpd-structs.h"
42 #include "netdev.h"
43 #include "openvswitch/types.h"
44 #include "packets.h"
45 #include "poll-loop.h"
46 #include "smap.h"
47 #include "unixctl.h"
48 #include "util.h"
49 #include "openvswitch/vlog.h"
50
51 VLOG_DEFINE_THIS_MODULE(ovs_lldp);
52
53 #define LLDP_PROTOCOL_ID        0x0000
54 #define LLDP_PROTOCOL_VERSION   0x00
55 #define LLDP_TYPE_CONFIG        0x00
56 #define LLDP_CHASSIS_TTL        120
57 #define ETH_TYPE_LLDP           0x88cc
58 #define MINIMUM_ETH_PACKET_SIZE 68
59
60 #define AA_STATUS_MULTIPLE \
61     AA_STATUS(ACTIVE,2,Active) \
62     AA_STATUS(REJECT_GENERIC,3,Reject (Generic)) \
63     AA_STATUS(REJECT_AA_RES_NOTAVAIL,4,Reject (AA resources unavailable)) \
64     AA_STATUS(REJECT_INVALID,6,Reject (Invalid)) \
65     AA_STATUS(REJECT_VLAN_RES_UNAVAIL,8,Reject (VLAN resources unavailable)) \
66     AA_STATUS(REJECT_VLAN_APP_ISSUE,9,Reject (Application interaction issue)) \
67     AA_STATUS(PENDING,255,Pending)
68
69 enum aa_status {
70 #define AA_STATUS(NAME, VALUE, STR) AA_STATUS_##NAME = VALUE,
71     AA_STATUS_MULTIPLE
72 #undef AA_STATUS
73     AA_STATUS_N_MULTIPLE
74 };
75
76 /* Internal structure for an Auto Attach mapping.
77  */
78 struct aa_mapping_internal {
79     struct hmap_node hmap_node_isid;
80     struct hmap_node hmap_node_aux;
81     int64_t          isid;
82     int64_t          vlan;
83     void             *aux;
84     enum aa_status   status;
85 };
86
87 static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
88
89 /* Hash map of all LLDP instances keyed by name (port at the moment).
90  */
91 static struct hmap all_lldps__ = HMAP_INITIALIZER(&all_lldps__);
92 static struct hmap *const all_lldps OVS_GUARDED_BY(mutex) = &all_lldps__;
93
94 /* Hash map of all the Auto Attach mappings.  Global at the moment (but will
95  * be per bridge).  Used when adding a new port to a bridge so that we can
96  * properly install all the configured mapping on the port and export them
97  * To the Auto Attach server via LLDP.
98  */
99 static struct hmap all_mappings__ = HMAP_INITIALIZER(&all_mappings__);
100 static struct hmap *const all_mappings OVS_GUARDED_BY(mutex) = &all_mappings__;
101
102 static struct lldp_aa_element_system_id system_id_null;
103
104 /* Convert an LLDP chassis ID to a string.
105  */
106 static void
107 chassisid_to_string(uint8_t *array, size_t len, char **str)
108 {
109     unsigned int i;
110
111     *str = xmalloc(len * 3);
112
113     for (i = 0; i < len; i++) {
114         snprintf(&(*str)[i * 3], 4, "%02x:", array[i]);
115     }
116     (*str)[(i * 3) - 1] = '\0';
117 }
118
119 /* Find an Auto Attach mapping keyed by I-SID.
120  */
121 static struct aa_mapping_internal *
122 mapping_find_by_isid(struct lldp *lldp, const uint64_t isid)
123     OVS_REQUIRES(mutex)
124 {
125     struct aa_mapping_internal *m;
126
127     HMAP_FOR_EACH_IN_BUCKET (m,
128                              hmap_node_isid,
129                              hash_bytes(&isid, sizeof isid, 0),
130                              &lldp->mappings_by_isid) {
131         if (isid == m->isid) {
132             return m;
133         }
134     }
135
136     return NULL;
137 }
138
139 /* Find an Auto Attach mapping keyed by aux.  aux is an opaque pointer created
140  * by the bridge that refers to an OVSDB mapping record.
141  */
142 static struct aa_mapping_internal *
143 mapping_find_by_aux(struct lldp *lldp, const void *aux) OVS_REQUIRES(mutex)
144 {
145     struct aa_mapping_internal *m;
146
147     HMAP_FOR_EACH_IN_BUCKET (m, hmap_node_aux, hash_pointer(aux, 0),
148                              &lldp->mappings_by_aux) {
149         if (aux == m->aux) {
150             return m;
151         }
152     }
153
154     return NULL;
155 }
156
157 /* Convert an Auto Attach request status to a string.
158  */
159 static char *
160 aa_status_to_str(uint8_t status)
161 {
162     switch (status) {
163 #define AA_STATUS(NAME, VALUE, STR) case AA_STATUS_##NAME: return #STR;
164         AA_STATUS_MULTIPLE
165 #undef AA_STATUS
166         default: return "Undefined";
167     }
168 }
169
170 /* Display LLDP and Auto Attach statistics.
171  */
172 static void
173 aa_print_lldp_and_aa_stats(struct ds *ds, struct lldp *lldp)
174     OVS_REQUIRES(mutex)
175 {
176     struct lldpd_hardware *hw;
177
178     ds_put_format(ds, "Statistics: %s\n", lldp->name);
179
180     if (!lldp->lldpd) {
181         return;
182     }
183
184     LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
185         ds_put_format(ds, "\ttx cnt: %"PRIu64"\n", hw->h_tx_cnt);
186         ds_put_format(ds, "\trx cnt: %"PRIu64"\n", hw->h_rx_cnt);
187         ds_put_format(ds, "\trx discarded cnt: %"PRIu64"\n",
188                       hw->h_rx_discarded_cnt);
189         ds_put_format(ds, "\trx unrecognized cnt: %"PRIu64"\n",
190                       hw->h_rx_unrecognized_cnt);
191         ds_put_format(ds, "\tageout cnt: %"PRIu64"\n", hw->h_ageout_cnt);
192         ds_put_format(ds, "\tinsert cnt: %"PRIu64"\n", hw->h_insert_cnt);
193         ds_put_format(ds, "\tdelete cnt: %"PRIu64"\n", hw->h_delete_cnt);
194         ds_put_format(ds, "\tdrop cnt: %"PRIu64"\n", hw->h_drop_cnt);
195     }
196 }
197
198 static void
199 aa_print_element_status_port(struct ds *ds, struct lldpd_hardware *hw)
200 {
201     struct lldpd_port *port;
202
203     LIST_FOR_EACH (port, p_entries, &hw->h_rports.p_entries) {
204         if (memcmp(&port->p_element.system_id,
205                    &system_id_null,
206                    sizeof port->p_element.system_id)) {
207             static char *none_str = "<None>";
208             char *id = none_str, *descr = none_str, *system = none_str;
209
210             if (port->p_chassis) {
211                 if (port->p_chassis->c_id_len > 0) {
212                     chassisid_to_string((uint8_t *) port->p_chassis->c_id,
213                                         port->p_chassis->c_id_len, &id);
214                 }
215
216                 descr = port->p_chassis->c_descr
217                     ? port->p_chassis->c_descr : none_str;
218             }
219
220             chassisid_to_string((uint8_t *) &port->p_element.system_id,
221                 sizeof port->p_element.system_id, &system);
222
223             ds_put_format(ds,
224                           "\tAuto Attach Primary Server Id: %s\n",
225                           id);
226             ds_put_format(ds,
227                           "\tAuto Attach Primary Server Descr: %s\n",
228                           descr);
229             ds_put_format(ds,
230                           "\tAuto Attach Primary Server System Id: %s\n",
231                           system);
232
233             free(id);
234             free(system);
235         }
236     }
237 }
238
239 /* Auto Attach server broadcast an LLDP message periodically.  Display
240  * the discovered server.
241  */
242 static void
243 aa_print_element_status(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex)
244 {
245     struct lldpd_hardware *hw;
246
247     ds_put_format(ds, "LLDP: %s\n", lldp->name);
248
249     if (!lldp->lldpd) {
250         return;
251     }
252
253     LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
254         aa_print_element_status_port(ds, hw);
255     }
256 }
257
258 static void
259 aa_print_isid_status_port_isid(struct lldp *lldp, struct lldpd_port *port)
260     OVS_REQUIRES(mutex)
261 {
262     struct lldpd_aa_isid_vlan_maps_tlv *mapping;
263
264     if (list_is_empty(&port->p_isid_vlan_maps)) {
265         return;
266     }
267
268     LIST_FOR_EACH (mapping, m_entries, &port->p_isid_vlan_maps) {
269         uint32_t isid = mapping->isid_vlan_data.isid;
270         struct aa_mapping_internal *m = mapping_find_by_isid(lldp, isid);
271
272         VLOG_INFO("h_rport: isid=%u, vlan=%u, status=%d",
273                   isid,
274                   mapping->isid_vlan_data.vlan,
275                   mapping->isid_vlan_data.status);
276
277         /* Update the status of our internal state for the mapping. */
278         if (m) {
279             VLOG_INFO("Setting status for ISID=%"PRIu32" to %"PRIu16,
280                       isid, mapping->isid_vlan_data.status);
281             m->status = mapping->isid_vlan_data.status;
282         } else {
283             VLOG_WARN("Couldn't find mapping for I-SID=%"PRIu32, isid);
284         }
285     }
286 }
287
288 static void
289 aa_print_isid_status_port(struct lldp *lldp, struct lldpd_hardware *hw)
290     OVS_REQUIRES(mutex)
291 {
292     struct lldpd_port *port;
293
294     LIST_FOR_EACH (port, p_entries, &hw->h_rports.p_entries) {
295         aa_print_isid_status_port_isid(lldp, port);
296     }
297 }
298
299 /* The Auto Attach server will broadcast the status of the configured mappings
300  * via LLDP.  Display the status.
301  */
302 static void
303 aa_print_isid_status(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex)
304 {
305     struct lldpd_hardware *hw;
306     struct aa_mapping_internal *m;
307
308     if (!lldp->lldpd) {
309         return;
310     }
311
312     ds_put_format(ds, "LLDP: %s\n", lldp->name);
313
314     LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
315         aa_print_isid_status_port(lldp, hw);
316     }
317
318     ds_put_format(ds, "%-8s %-4s %-11s %-8s\n",
319                       "I-SID",
320                       "VLAN",
321                       "Source",
322                       "Status");
323     ds_put_format(ds, "-------- ---- ----------- --------\n");
324
325     HMAP_FOR_EACH (m, hmap_node_isid, &lldp->mappings_by_isid) {
326         ds_put_format(ds, "%-8ld %-4ld %-11s %-11s\n",
327                           (long int) m->isid,
328                           (long int) m->vlan,
329                           "Switch",
330                           aa_status_to_str(m->status));
331     }
332 }
333
334 static void
335 aa_unixctl_status(struct unixctl_conn *conn, int argc OVS_UNUSED,
336                   const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
337     OVS_EXCLUDED(mutex)
338 {
339     struct lldp *lldp;
340     struct ds ds = DS_EMPTY_INITIALIZER;
341
342     ovs_mutex_lock(&mutex);
343
344     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
345         aa_print_element_status(&ds, lldp);
346     }
347     unixctl_command_reply(conn, ds_cstr(&ds));
348     ds_destroy(&ds);
349
350     ovs_mutex_unlock(&mutex);
351 }
352
353 static void
354 aa_unixctl_show_isid(struct unixctl_conn *conn, int argc OVS_UNUSED,
355                      const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
356     OVS_EXCLUDED(mutex)
357 {
358     struct lldp *lldp;
359     struct ds ds = DS_EMPTY_INITIALIZER;
360
361     ovs_mutex_lock(&mutex);
362
363     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
364         aa_print_isid_status(&ds, lldp);
365     }
366     unixctl_command_reply(conn, ds_cstr(&ds));
367     ds_destroy(&ds);
368
369     ovs_mutex_unlock(&mutex);
370 }
371
372 static void
373 aa_unixctl_statistics(struct unixctl_conn *conn, int argc OVS_UNUSED,
374                       const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
375     OVS_EXCLUDED(mutex)
376 {
377     struct ds ds = DS_EMPTY_INITIALIZER;
378     struct lldp *lldp;
379
380     ovs_mutex_lock(&mutex);
381
382     /* Cycle through all ports and dump the stats for each one */
383     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
384         aa_print_lldp_and_aa_stats(&ds, lldp);
385     }
386
387     ovs_mutex_unlock(&mutex);
388
389     unixctl_command_reply(conn, ds_cstr(&ds));
390 }
391
392 /* An Auto Attach mapping was configured.  Populate the corresponding
393  * structures in the LLDP hardware.
394  */
395 static void
396 update_mapping_on_lldp(struct lldp *lldp, struct lldpd_hardware *hardware,
397                        struct aa_mapping_internal *m)
398 {
399     struct lldpd_aa_isid_vlan_maps_tlv *lm = xzalloc(sizeof *lm);
400
401     if (hardware->h_ifname) {
402         VLOG_INFO("\t\t hardware->h_ifname=%s", hardware->h_ifname);
403     }
404
405     lm->isid_vlan_data.isid = m->isid;
406     lm->isid_vlan_data.vlan = m->vlan;
407
408     list_push_back(&hardware->h_lport.p_isid_vlan_maps, &lm->m_entries);
409
410     /* TODO Should be done in the Auto Attach state machine when a mapping goes
411      * from "pending" to "active".
412      */
413     {
414         struct bridge_aa_vlan *node = xmalloc(sizeof *node);
415
416         node->port_name = xstrdup(hardware->h_ifname);
417         node->vlan = m->vlan;
418         node->oper = BRIDGE_AA_VLAN_OPER_ADD;
419
420         list_push_back(&lldp->active_mapping_queue, &node->list_node);
421     }
422 }
423
424 /* Bridge will poll the list of VLAN that needs to be auto configure based on
425  * the Auto Attach mappings that have been exchanged with the server.
426  */
427 int
428 aa_get_vlan_queued(struct ovs_list *list)
429 {
430     struct lldp *lldp;
431
432     ovs_mutex_lock(&mutex);
433
434     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
435         struct bridge_aa_vlan *node, *node_next;
436
437         LIST_FOR_EACH_SAFE (node,
438                             node_next,
439                             list_node,
440                             &lldp->active_mapping_queue) {
441             struct bridge_aa_vlan *copy;
442
443             copy = xmalloc(sizeof *copy);
444             copy->port_name = xstrdup(node->port_name);
445             copy->vlan = node->vlan;
446             copy->oper = node->oper;
447
448             list_push_back(list, &copy->list_node);
449
450             /* Cleanup */
451             list_remove(&node->list_node);
452             free(node->port_name);
453             free(node);
454         }
455     }
456
457     ovs_mutex_unlock(&mutex);
458
459     return 0;
460 }
461
462 /* Bridge will poll whether or not VLAN have been auto-configured.
463  */
464 unsigned int
465 aa_get_vlan_queue_size(void)
466 {
467     struct lldp *lldp;
468     unsigned int size = 0;
469
470     ovs_mutex_lock(&mutex);
471
472     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
473         size += list_size(&lldp->active_mapping_queue);
474     }
475
476     ovs_mutex_unlock(&mutex);
477
478     return size;
479 }
480
481 /* Configure Auto Attach.
482  */
483 int
484 aa_configure(const struct aa_settings *s)
485 {
486     struct lldp *lldp;
487
488     ovs_mutex_lock(&mutex);
489
490     /* TODO Change all instances for now */
491     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
492         struct lldpd_chassis *chassis;
493
494         LIST_FOR_EACH (chassis, list, &lldp->lldpd->g_chassis.list) {
495             /* System Description */
496             if (chassis->c_descr) {
497                 free(chassis->c_descr);
498             }
499             chassis->c_descr = s->system_description[0] ?
500                 xstrdup(s->system_description) : xstrdup(PACKAGE_STRING);
501
502             /* System Name */
503             if (chassis->c_name) {
504                 free(chassis->c_name);
505             }
506             chassis->c_name = xstrdup(s->system_name);
507         }
508     }
509
510     ovs_mutex_unlock(&mutex);
511
512     return 0;
513 }
514
515 /* Add a new Auto Attach mapping.
516  */
517 int
518 aa_mapping_register(void *aux, const struct aa_mapping_settings *s)
519 {
520     struct aa_mapping_internal *bridge_m;
521     struct lldp *lldp;
522
523     VLOG_INFO("Adding mapping ISID=%ld, VLAN=%ld, aux=%p", (long int) s->isid,
524               (long int) s->vlan, aux);
525
526     ovs_mutex_lock(&mutex);
527
528     /* TODO These mappings should be stores per bridge.  This is used
529      * When a port is added.  Auto Attach mappings need to be added on this
530      * port.
531      */
532     bridge_m = xzalloc(sizeof *bridge_m);
533     bridge_m->isid = s->isid;
534     bridge_m->vlan = s->vlan;
535     bridge_m->aux = aux;
536     bridge_m->status = AA_STATUS_PENDING;
537     hmap_insert(all_mappings,
538                 &bridge_m->hmap_node_isid,
539                 hash_bytes((const void *) &bridge_m->isid,
540                            sizeof bridge_m->isid,
541                            0));
542
543     /* Update mapping on the all the LLDP instances. */
544     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
545         struct lldpd_hardware *hw;
546         struct aa_mapping_internal *m;
547
548         VLOG_INFO("\t lldp->name=%s", lldp->name);
549
550         if (mapping_find_by_isid(lldp, s->isid)) {
551             continue;
552         }
553
554         m = xzalloc(sizeof *m);
555         m->isid = s->isid;
556         m->vlan = s->vlan;
557         m->status = AA_STATUS_PENDING;
558         m->aux = aux;
559         hmap_insert(&lldp->mappings_by_isid,
560                     &m->hmap_node_isid,
561                     hash_bytes((const void *) &m->isid,
562                                sizeof m->isid,
563                                0));
564         hmap_insert(&lldp->mappings_by_aux,
565                     &m->hmap_node_aux,
566                     hash_pointer(m->aux, 0));
567
568         /* Configure the mapping on each port of the LLDP stack. */
569         LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
570             update_mapping_on_lldp(lldp, hw, m);
571         }
572     }
573
574     ovs_mutex_unlock(&mutex);
575
576     return 0;
577 }
578
579 static void
580 aa_mapping_unregister_mapping(struct lldp *lldp,
581                               struct lldpd_hardware *hw,
582                               struct aa_mapping_internal *m)
583 {
584     struct lldpd_aa_isid_vlan_maps_tlv *lm, *lm_next;
585
586     LIST_FOR_EACH_SAFE (lm, lm_next, m_entries,
587                         &hw->h_lport.p_isid_vlan_maps) {
588         uint32_t isid = lm->isid_vlan_data.isid;
589
590         if (isid == (uint32_t) m->isid) {
591             VLOG_INFO("\t\t Removing lport, isid=%u, vlan=%u",
592                       isid,
593                       lm->isid_vlan_data.vlan);
594
595             list_remove(&lm->m_entries);
596
597             /* TODO Should be done in the AA SM when a mapping goes
598              * from "pending" to "active".
599              */
600             {
601                 struct bridge_aa_vlan *node = xmalloc(sizeof *node);
602
603                 node->port_name = xstrdup(hw->h_ifname);
604                 node->vlan = (uint32_t) m->vlan;
605                 node->oper = BRIDGE_AA_VLAN_OPER_REMOVE;
606
607                 list_push_back(&lldp->active_mapping_queue, &node->list_node);
608             }
609
610             break;
611         }
612     }
613 }
614
615 /* Remove an existing Auto Attach mapping.
616  */
617 int
618 aa_mapping_unregister(void *aux)
619 {
620     struct lldp *lldp;
621
622     VLOG_INFO("Removing mapping aux=%p", aux);
623
624     ovs_mutex_lock(&mutex);
625
626     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
627         struct lldpd_hardware *hw;
628         struct aa_mapping_internal *m = mapping_find_by_aux(lldp, aux);
629         int64_t isid_tmp = -1, vlan_tmp = -1;
630
631         /* Remove from internal hash tables. */
632         if (m) {
633             struct aa_mapping_internal *p =
634                 mapping_find_by_isid(lldp, m->isid);
635
636             isid_tmp = m->isid;
637             vlan_tmp = m->vlan;
638             VLOG_INFO("\t Removing mapping ISID=%ld, VLAN=%ld (lldp->name=%s)",
639                       (long int) m->isid, (long int) m->vlan, lldp->name);
640
641             if (p) {
642                 hmap_remove(&lldp->mappings_by_isid, &p->hmap_node_isid);
643             }
644
645             hmap_remove(&lldp->mappings_by_aux, &m->hmap_node_aux);
646             free(m);
647
648             /* Remove from all the lldp instances */
649             LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
650                 if (hw->h_ifname) {
651                     VLOG_INFO("\t\t hardware->h_ifname=%s", hw->h_ifname);
652                 }
653
654                 aa_mapping_unregister_mapping(lldp, hw, m);
655             }
656
657             if (isid_tmp >= 0 && vlan_tmp >= 0) {
658                 /* Remove from the all_mappings */
659                 HMAP_FOR_EACH (m, hmap_node_isid, all_mappings) {
660                     if (m && isid_tmp == m->isid && vlan_tmp == m->vlan) {
661                          hmap_remove(all_mappings, &m->hmap_node_isid);
662                          break;
663                     }
664                 }
665             }
666         }
667     }
668
669     ovs_mutex_unlock(&mutex);
670
671     return 0;
672 }
673
674 void
675 lldp_init(void)
676 {
677     unixctl_command_register("autoattach/status", "[bridge]", 0, 1,
678                              aa_unixctl_status, NULL);
679     unixctl_command_register("autoattach/show-isid", "[bridge]", 0, 1,
680                              aa_unixctl_show_isid, NULL);
681     unixctl_command_register("autoattach/statistics", "[bridge]", 0, 1,
682                              aa_unixctl_statistics, NULL);
683 }
684
685 /* Returns true if 'lldp' should process packets from 'flow'.  Sets
686  * fields in 'wc' that were used to make the determination.
687  */
688 bool
689 lldp_should_process_flow(const struct flow *flow)
690 {
691     return (flow->dl_type == htons(ETH_TYPE_LLDP));
692 }
693
694
695 /* Process an LLDP packet that was received on a bridge port.
696  */
697 void
698 lldp_process_packet(struct lldp *lldp, const struct dp_packet *p)
699 {
700     if (lldp) {
701         lldpd_recv(lldp->lldpd,
702                    (struct lldpd_hardware *)
703                        lldp->lldpd->g_hardware.h_entries.next,
704                    (char *) p->data_,
705                    p->size_);
706     }
707 }
708
709 /* This code is called periodically to check if the LLDP module has an LLDP
710  * message it wishes to send.  It is called several times every second.
711  */
712 bool
713 lldp_should_send_packet(struct lldp *cfg) OVS_EXCLUDED(mutex)
714 {
715     bool ret;
716
717     ovs_mutex_lock(&mutex);
718     ret = timer_expired(&cfg->tx_timer);
719     ovs_mutex_unlock(&mutex);
720
721     return ret;
722 }
723
724 /* Returns the next wake up time.
725  */
726 long long int
727 lldp_wake_time(const struct lldp *lldp) OVS_EXCLUDED(mutex)
728 {
729     long long int retval;
730
731     if (!lldp) {
732         return LLONG_MAX;
733     }
734
735     ovs_mutex_lock(&mutex);
736     retval = lldp->tx_timer.t;
737     ovs_mutex_unlock(&mutex);
738
739     return retval;
740 }
741
742 /* Put the monitor thread to sleep until it's next wake time.
743  */
744 long long int
745 lldp_wait(struct lldp *lldp) OVS_EXCLUDED(mutex)
746 {
747     long long int wake_time = lldp_wake_time(lldp);
748     poll_timer_wait_until(wake_time);
749     return wake_time;
750 }
751
752 /* Prepare the LLDP packet to be sent on a bridge port.
753  */
754 void
755 lldp_put_packet(struct lldp *lldp, struct dp_packet *packet,
756                 uint8_t eth_src[ETH_ADDR_LEN]) OVS_EXCLUDED(mutex)
757 {
758     struct lldpd *mylldpd = lldp->lldpd;
759     struct lldpd_hardware *hw = (struct lldpd_hardware *)
760         mylldpd->g_hardware.h_entries.next;
761     uint32_t lldp_size = 0;
762     static const uint8_t eth_addr_lldp[6] =
763         {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
764
765     ovs_mutex_lock(&mutex);
766
767     eth_compose(packet, eth_addr_lldp, eth_src, ETH_TYPE_LLDP, 0);
768
769     lldp_size = lldpd_send(hw, packet);
770     if (lldp_size + ETH_HEADER_LEN < MINIMUM_ETH_PACKET_SIZE) {
771         lldp_size = MINIMUM_ETH_PACKET_SIZE;
772     }
773
774     timer_set_duration(&lldp->tx_timer, lldp->lldpd->g_config.c_tx_interval);
775     ovs_mutex_unlock(&mutex);
776 }
777
778 /* Configures the LLDP stack.
779  */
780 bool
781 lldp_configure(struct lldp *lldp) OVS_EXCLUDED(mutex)
782 {
783     if (lldp) {
784         ovs_mutex_lock(&mutex);
785         timer_set_expired(&lldp->tx_timer);
786         timer_set_duration(&lldp->tx_timer, LLDP_DEFAULT_TRANSMIT_INTERVAL_MS);
787         lldp->lldpd->g_config.c_tx_interval =
788             LLDP_DEFAULT_TRANSMIT_INTERVAL_MS;
789         ovs_mutex_unlock(&mutex);
790     }
791
792     return true;
793 }
794
795 /* Create an LLDP stack instance.  At the moment there is one per bridge port.
796  */
797 struct lldp *
798 lldp_create(const struct netdev *netdev,
799             const uint32_t mtu,
800             const struct smap *cfg) OVS_EXCLUDED(mutex)
801 {
802     struct lldp *lldp;
803     struct lldpd_chassis *lchassis;
804     struct lldpd_hardware *hw;
805     struct aa_mapping_internal *m;
806
807     if (!cfg || !smap_get_bool(cfg, "enable", false)) {
808         return NULL;
809     }
810
811     lldp = xzalloc(sizeof *lldp);
812     lldp->name = xstrdup(netdev_get_name(netdev));
813     lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
814
815     hmap_init(&lldp->mappings_by_isid);
816     hmap_init(&lldp->mappings_by_aux);
817     list_init(&lldp->active_mapping_queue);
818
819     lchassis = xzalloc(sizeof *lchassis);
820     lchassis->c_cap_available = LLDP_CAP_BRIDGE;
821     lchassis->c_cap_enabled = LLDP_CAP_BRIDGE;
822     lchassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
823     lchassis->c_id_len = ETH_ADDR_LEN;
824     lchassis->c_id = xmalloc(ETH_ADDR_LEN);
825     netdev_get_etheraddr(netdev, (uint8_t *) lchassis->c_id);
826
827     list_init(&lchassis->c_mgmt);
828     lchassis->c_ttl = lldp->lldpd->g_config.c_tx_interval *
829                       lldp->lldpd->g_config.c_tx_hold;
830     lchassis->c_ttl = LLDP_CHASSIS_TTL;
831     lldpd_assign_cfg_to_protocols(lldp->lldpd);
832     list_init(&lldp->lldpd->g_chassis.list);
833     list_push_back(&lldp->lldpd->g_chassis.list, &lchassis->list);
834
835     if ((hw = lldpd_alloc_hardware(lldp->lldpd,
836                                    (char *) netdev_get_name(netdev),
837                                    0)) == NULL) {
838         VLOG_WARN("Unable to allocate space for %s",
839                   (char *) netdev_get_name(netdev));
840         out_of_memory();
841     }
842
843     ovs_refcount_init(&lldp->ref_cnt);
844 #ifndef _WIN32
845     hw->h_flags |= IFF_RUNNING;
846 #endif
847     hw->h_mtu = mtu;
848     hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
849     hw->h_lport.p_id = xstrdup(netdev_get_name(netdev));
850
851     /* p_id is not necessarily a null terminated string. */
852     hw->h_lport.p_id_len = strlen(netdev_get_name(netdev));
853
854     /* Auto Attach element tlv */
855     hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
856     hw->h_lport.p_element.mgmt_vlan = 0;
857     memcpy(&hw->h_lport.p_element.system_id.system_mac,
858            lchassis->c_id, lchassis->c_id_len);
859     hw->h_lport.p_element.system_id.conn_type =
860         LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
861
862     hw->h_lport.p_element.system_id.smlt_id = 0;
863     hw->h_lport.p_element.system_id.mlt_id[0] = 0;
864     hw->h_lport.p_element.system_id.mlt_id[1] = 0;
865
866     list_init(&hw->h_lport.p_isid_vlan_maps);
867     list_init(&lldp->lldpd->g_hardware.h_entries);
868     list_push_back(&lldp->lldpd->g_hardware.h_entries, &hw->h_entries);
869
870     ovs_mutex_lock(&mutex);
871
872     /* Update port with Auto Attach mappings configured. */
873     HMAP_FOR_EACH (m, hmap_node_isid, all_mappings) {
874         struct aa_mapping_internal *p;
875
876         if (mapping_find_by_isid(lldp, m->isid)) {
877             continue;
878         }
879
880         p = xmemdup(m, sizeof *p);
881         hmap_insert(&lldp->mappings_by_isid,
882                     &p->hmap_node_isid,
883                     hash_bytes((const void *) &p->isid,
884                                sizeof p->isid,
885                                0));
886         hmap_insert(&lldp->mappings_by_aux,
887                     &p->hmap_node_aux,
888                     hash_pointer(p->aux, 0));
889
890         update_mapping_on_lldp(lldp, hw, p);
891     }
892
893     hmap_insert(all_lldps, &lldp->hmap_node,
894                 hash_string(netdev_get_name(netdev), 0));
895
896     ovs_mutex_unlock(&mutex);
897
898     return lldp;
899 }
900
901
902 struct lldp *
903 lldp_create_dummy(void)
904 {
905     struct lldp *lldp;
906     struct lldpd_chassis *lchassis;
907     struct lldpd_hardware *hw;
908
909     lldp = xzalloc(sizeof *lldp);
910     lldp->name = "dummy-lldp";
911     lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
912
913     hmap_init(&lldp->mappings_by_isid);
914     hmap_init(&lldp->mappings_by_aux);
915     list_init(&lldp->active_mapping_queue);
916
917     lchassis = xzalloc(sizeof *lchassis);
918     lchassis->c_cap_available = LLDP_CAP_BRIDGE;
919     lchassis->c_cap_enabled = LLDP_CAP_BRIDGE;
920     lchassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
921     lchassis->c_id_len = ETH_ADDR_LEN;
922     lchassis->c_id = xmalloc(ETH_ADDR_LEN);
923
924     list_init(&lchassis->c_mgmt);
925     lchassis->c_ttl = LLDP_CHASSIS_TTL;
926     lldpd_assign_cfg_to_protocols(lldp->lldpd);
927     list_init(&lldp->lldpd->g_chassis.list);
928     list_push_back(&lldp->lldpd->g_chassis.list, &lchassis->list);
929
930     hw = lldpd_alloc_hardware(lldp->lldpd, "dummy-hw", 0);
931
932     ovs_refcount_init(&lldp->ref_cnt);
933 #ifndef _WIN32
934     hw->h_flags |= IFF_RUNNING;
935 #endif
936     hw->h_mtu = 1500;
937     hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
938     hw->h_lport.p_id = "dummy-port";
939
940     /* p_id is not necessarily a null terminated string. */
941     hw->h_lport.p_id_len = strlen(hw->h_lport.p_id);
942
943     /* Auto Attach element tlv */
944     hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
945     hw->h_lport.p_element.mgmt_vlan = 0;
946     memcpy(&hw->h_lport.p_element.system_id.system_mac,
947            lchassis->c_id, lchassis->c_id_len);
948     hw->h_lport.p_element.system_id.conn_type =
949         LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
950     hw->h_lport.p_element.system_id.smlt_id = 0;
951     hw->h_lport.p_element.system_id.mlt_id[0] = 0;
952     hw->h_lport.p_element.system_id.mlt_id[1] = 0;
953
954     list_init(&hw->h_lport.p_isid_vlan_maps);
955     list_init(&lldp->lldpd->g_hardware.h_entries);
956     list_push_back(&lldp->lldpd->g_hardware.h_entries, &hw->h_entries);
957
958     return lldp;
959 }
960
961 /* Unreference a specific LLDP instance.
962  */
963 void
964 lldp_unref(struct lldp *lldp)
965 {
966     if (!lldp) {
967         return;
968     }
969
970     ovs_mutex_lock(&mutex);
971     if (ovs_refcount_unref_relaxed(&lldp->ref_cnt) != 1) {
972         ovs_mutex_unlock(&mutex);
973         return;
974     }
975
976     hmap_remove(all_lldps, &lldp->hmap_node);
977     ovs_mutex_unlock(&mutex);
978
979     lldpd_cleanup(lldp->lldpd);
980     free(lldp->lldpd);
981     free(lldp->name);
982     free(lldp);
983 }
984
985 /* Unreference a specific LLDP instance.
986  */
987 struct lldp *
988 lldp_ref(const struct lldp *lldp_)
989 {
990     struct lldp *lldp = CONST_CAST(struct lldp *, lldp_);
991     if (lldp) {
992         ovs_refcount_ref(&lldp->ref_cnt);
993     }
994     return lldp;
995 }