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