ovs-lldp: Use correct printf specifiers.
[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 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         if (m) {
312             VLOG_INFO("Setting status for ISID=%"PRIu32" to %"PRIu16,
313                       isid, mapping->isid_vlan_data.status);
314             m->status = mapping->isid_vlan_data.status;
315         } else {
316             VLOG_WARN("Couldn't find mapping for I-SID=%"PRIu32, isid);
317         }
318     }
319 }
320
321 static void
322 aa_print_isid_status_port(struct lldp *lldp, struct lldpd_hardware *hw)
323     OVS_REQUIRES(mutex)
324 {
325     struct lldpd_port *port;
326
327     LIST_FOR_EACH (port, p_entries, &hw->h_rports.p_entries) {
328         aa_print_isid_status_port_isid(lldp, port);
329     }
330 }
331
332 /* The Auto Attach server will broadcast the status of the configured mappings
333  * via LLDP.  Display the status.
334  */
335 static void
336 aa_print_isid_status(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex)
337 {
338     struct lldpd_hardware *hw;
339     struct aa_mapping_internal *m;
340
341     if (!lldp->lldpd) {
342         return;
343     }
344
345     ds_put_format(ds, "LLDP: %s\n", lldp->name);
346
347     LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
348         aa_print_isid_status_port(lldp, hw);
349     }
350
351     ds_put_format(ds, "%-8s %-4s %-11s %-8s\n",
352                       "I-SID",
353                       "VLAN",
354                       "Source",
355                       "Status");
356     ds_put_format(ds, "-------- ---- ----------- --------\n");
357
358     HMAP_FOR_EACH (m, hmap_node_isid, &lldp->mappings_by_isid) {
359         ds_put_format(ds, "%-8ld %-4ld %-11s %-11s\n",
360                           (long int) m->isid,
361                           (long int) m->vlan,
362                           "Switch",
363                           aa_status_to_str(m->status));
364     }
365 }
366
367 static void
368 aa_unixctl_status(struct unixctl_conn *conn, int argc OVS_UNUSED,
369                   const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
370     OVS_EXCLUDED(mutex)
371 {
372     struct lldp *lldp;
373     struct ds ds = DS_EMPTY_INITIALIZER;
374
375     ovs_mutex_lock(&mutex);
376
377     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
378         aa_print_element_status(&ds, lldp);
379     }
380     unixctl_command_reply(conn, ds_cstr(&ds));
381     ds_destroy(&ds);
382
383     ovs_mutex_unlock(&mutex);
384 }
385
386 static void
387 aa_unixctl_show_isid(struct unixctl_conn *conn, int argc OVS_UNUSED,
388                      const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
389     OVS_EXCLUDED(mutex)
390 {
391     struct lldp *lldp;
392     struct ds ds = DS_EMPTY_INITIALIZER;
393
394     ovs_mutex_lock(&mutex);
395
396     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
397         aa_print_isid_status(&ds, lldp);
398     }
399     unixctl_command_reply(conn, ds_cstr(&ds));
400     ds_destroy(&ds);
401
402     ovs_mutex_unlock(&mutex);
403 }
404
405 static void
406 aa_unixctl_statistics(struct unixctl_conn *conn, int argc OVS_UNUSED,
407                       const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
408     OVS_EXCLUDED(mutex)
409 {
410     struct ds ds = DS_EMPTY_INITIALIZER;
411     struct lldp *lldp;
412
413     ovs_mutex_lock(&mutex);
414
415     /* Cycle through all ports and dump the stats for each one */
416     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
417         aa_print_lldp_and_aa_stats(&ds, lldp);
418     }
419
420     ovs_mutex_unlock(&mutex);
421
422     unixctl_command_reply(conn, ds_cstr(&ds));
423 }
424
425 /* An Auto Attach mapping was configured.  Populate the corresponding
426  * structures in the LLDP hardware.
427  */
428 static void
429 update_mapping_on_lldp(struct lldp *lldp, struct lldpd_hardware *hardware,
430                        struct aa_mapping_internal *m)
431 {
432     struct lldpd_aa_isid_vlan_maps_tlv *lm = xzalloc(sizeof *lm);
433
434     if (hardware->h_ifname) {
435         VLOG_INFO("\t\t hardware->h_ifname=%s", hardware->h_ifname);
436     }
437
438     int_to_array(lm->isid_vlan_data.isid,
439                  ARRAY_SIZE(lm->isid_vlan_data.isid),
440                  (uint32_t) m->isid);
441     lm->isid_vlan_data.vlan = m->vlan;
442
443     list_push_back(&hardware->h_lport.p_isid_vlan_maps.m_entries,
444                    &lm->m_entries);
445
446     /* TODO Should be done in the Auto Attach state machine when a mapping goes
447      * from "pending" to "active".
448      */
449     {
450         struct bridge_aa_vlan *node = xmalloc(sizeof *node);
451
452         node->port_name = xstrdup(hardware->h_ifname);
453         node->vlan = m->vlan;
454         node->oper = BRIDGE_AA_VLAN_OPER_ADD;
455
456         list_push_back(&lldp->active_mapping_queue, &node->list_node);
457     }
458 }
459
460 /* Bridge will poll the list of VLAN that needs to be auto configure based on
461  * the Auto Attach mappings that have been exchanged with the server.
462  */
463 int
464 aa_get_vlan_queued(struct ovs_list *list)
465 {
466     struct lldp *lldp;
467
468     ovs_mutex_lock(&mutex);
469
470     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
471         struct bridge_aa_vlan *node, *node_next;
472
473         LIST_FOR_EACH_SAFE (node,
474                             node_next,
475                             list_node,
476                             &lldp->active_mapping_queue) {
477             struct bridge_aa_vlan *copy;
478
479             copy = xmalloc(sizeof *copy);
480             copy->port_name = xstrdup(node->port_name);
481             copy->vlan = node->vlan;
482             copy->oper = node->oper;
483
484             list_push_back(list, &copy->list_node);
485
486             /* Cleanup */
487             list_remove(&node->list_node);
488             free(node->port_name);
489             free(node);
490         }
491     }
492
493     ovs_mutex_unlock(&mutex);
494
495     return 0;
496 }
497
498 /* Bridge will poll whether or not VLAN have been auto-configured.
499  */
500 unsigned int
501 aa_get_vlan_queue_size(void)
502 {
503     struct lldp *lldp;
504     unsigned int size = 0;
505
506     ovs_mutex_lock(&mutex);
507
508     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
509         size += list_size(&lldp->active_mapping_queue);
510     }
511
512     ovs_mutex_unlock(&mutex);
513
514     return size;
515 }
516
517 /* Configure Auto Attach.
518  */
519 int
520 aa_configure(const struct aa_settings *s)
521 {
522     struct lldp *lldp;
523
524     ovs_mutex_lock(&mutex);
525
526     /* TODO Change all instances for now */
527     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
528         struct lldpd_chassis *chassis;
529
530         LIST_FOR_EACH (chassis, list, &lldp->lldpd->g_chassis.list) {
531             /* System Description */
532             if (chassis->c_descr) {
533                 free(chassis->c_descr);
534             }
535             chassis->c_descr = s->system_description[0] ?
536                 xstrdup(s->system_description) : xstrdup(PACKAGE_STRING);
537
538             /* System Name */
539             if (chassis->c_name) {
540                 free(chassis->c_name);
541             }
542             chassis->c_name = xstrdup(s->system_name);
543         }
544     }
545
546     ovs_mutex_unlock(&mutex);
547
548     return 0;
549 }
550
551 /* Add a new Auto Attach mapping.
552  */
553 int
554 aa_mapping_register(void *aux, const struct aa_mapping_settings *s)
555 {
556     struct aa_mapping_internal *bridge_m;
557     struct lldp *lldp;
558
559     VLOG_INFO("Adding mapping ISID=%ld, VLAN=%ld, aux=%p", (long int) s->isid,
560               (long int) s->vlan, aux);
561
562     ovs_mutex_lock(&mutex);
563
564     /* TODO These mappings should be stores per bridge.  This is used
565      * When a port is added.  Auto Attach mappings need to be added on this
566      * port.
567      */
568     bridge_m = xzalloc(sizeof *bridge_m);
569     bridge_m->isid = s->isid;
570     bridge_m->vlan = s->vlan;
571     bridge_m->aux = aux;
572     bridge_m->status = AA_STATUS_PENDING;
573     hmap_insert(all_mappings,
574                 &bridge_m->hmap_node_isid,
575                 hash_bytes((const void *) &bridge_m->isid,
576                            sizeof bridge_m->isid,
577                            0));
578
579     /* Update mapping on the all the LLDP instances. */
580     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
581         struct lldpd_hardware *hw;
582         struct aa_mapping_internal *m;
583
584         VLOG_INFO("\t lldp->name=%s", lldp->name);
585
586         if (mapping_find_by_isid(lldp, s->isid)) {
587             continue;
588         }
589
590         m = xzalloc(sizeof *m);
591         m->isid = s->isid;
592         m->vlan = s->vlan;
593         m->status = AA_STATUS_PENDING;
594         m->aux = aux;
595         hmap_insert(&lldp->mappings_by_isid,
596                     &m->hmap_node_isid,
597                     hash_bytes((const void *) &m->isid,
598                                sizeof m->isid,
599                                0));
600         hmap_insert(&lldp->mappings_by_aux,
601                     &m->hmap_node_aux,
602                     hash_pointer(m->aux, 0));
603
604         /* Configure the mapping on each port of the LLDP stack. */
605         LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
606             update_mapping_on_lldp(lldp, hw, m);
607         }
608     }
609
610     ovs_mutex_unlock(&mutex);
611
612     return 0;
613 }
614
615 static void
616 aa_mapping_unregister_mapping(struct lldp *lldp,
617                               struct lldpd_hardware *hw,
618                               struct aa_mapping_internal *m)
619 {
620     struct lldpd_aa_isid_vlan_maps_tlv *lm, *lm_next;
621
622     LIST_FOR_EACH_SAFE (lm,
623                         lm_next,
624                         m_entries,
625                         &hw->h_lport.p_isid_vlan_maps.m_entries) {
626         uint32_t isid = array_to_int(lm->isid_vlan_data.isid,
627                                      sizeof lm->isid_vlan_data.isid);
628
629         if (isid == (uint32_t) m->isid) {
630             VLOG_INFO("\t\t Removing lport, isid=%u, vlan=%u",
631                       isid,
632                       lm->isid_vlan_data.vlan);
633
634             list_remove(&lm->m_entries);
635
636             /* TODO Should be done in the AA SM when a mapping goes
637              * from "pending" to "active".
638              */
639             {
640                 struct bridge_aa_vlan *node = xmalloc(sizeof *node);
641
642                 node->port_name = xstrdup(hw->h_ifname);
643                 node->vlan = (uint32_t) m->vlan;
644                 node->oper = BRIDGE_AA_VLAN_OPER_REMOVE;
645
646                 list_push_back(&lldp->active_mapping_queue, &node->list_node);
647             }
648
649             break;
650         }
651     }
652 }
653
654 /* Remove an existing Auto Attach mapping.
655  */
656 int
657 aa_mapping_unregister(void *aux)
658 {
659     struct lldp *lldp;
660
661     VLOG_INFO("Removing mapping aux=%p", aux);
662
663     ovs_mutex_lock(&mutex);
664
665     HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
666         struct lldpd_hardware *hw;
667         struct aa_mapping_internal *m = mapping_find_by_aux(lldp, aux);
668         int64_t isid_tmp = -1, vlan_tmp = -1;
669
670         /* Remove from internal hash tables. */
671         if (m) {
672             struct aa_mapping_internal *p =
673                 mapping_find_by_isid(lldp, m->isid);
674
675             isid_tmp = m->isid;
676             vlan_tmp = m->vlan;
677             VLOG_INFO("\t Removing mapping ISID=%ld, VLAN=%ld (lldp->name=%s)",
678                       (long int) m->isid, (long int) m->vlan, lldp->name);
679
680             if (p) {
681                 hmap_remove(&lldp->mappings_by_isid, &p->hmap_node_isid);
682             }
683
684             hmap_remove(&lldp->mappings_by_aux, &m->hmap_node_aux);
685             free(m);
686
687             /* Remove from all the lldp instances */
688             LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
689                 if (hw->h_ifname) {
690                     VLOG_INFO("\t\t hardware->h_ifname=%s", hw->h_ifname);
691                 }
692
693                 aa_mapping_unregister_mapping(lldp, hw, m);
694             }
695
696             if (isid_tmp >= 0 && vlan_tmp >= 0) {
697                 /* Remove from the all_mappings */
698                 HMAP_FOR_EACH (m, hmap_node_isid, all_mappings) {
699                     if (m && isid_tmp == m->isid && vlan_tmp == m->vlan) {
700                          hmap_remove(all_mappings, &m->hmap_node_isid);
701                          break;
702                     }
703                 }
704             }
705         }
706     }
707
708     ovs_mutex_unlock(&mutex);
709
710     return 0;
711 }
712
713 void
714 lldp_init(void)
715 {
716     unixctl_command_register("autoattach/status", "[bridge]", 0, 1,
717                              aa_unixctl_status, NULL);
718     unixctl_command_register("autoattach/show-isid", "[bridge]", 0, 1,
719                              aa_unixctl_show_isid, NULL);
720     unixctl_command_register("autoattach/statistics", "[bridge]", 0, 1,
721                              aa_unixctl_statistics, NULL);
722 }
723
724 /* Returns true if 'lldp' should process packets from 'flow'.  Sets
725  * fields in 'wc' that were used to make the determination.
726  */
727 bool
728 lldp_should_process_flow(const struct flow *flow)
729 {
730     return (flow->dl_type == htons(ETH_TYPE_LLDP));
731 }
732
733
734 /* Process an LLDP packet that was received on a bridge port.
735  */
736 void
737 lldp_process_packet(struct lldp *lldp, const struct dp_packet *p)
738 {
739     if (lldp) {
740         lldpd_recv(lldp->lldpd,
741                    (struct lldpd_hardware *)
742                        lldp->lldpd->g_hardware.h_entries.next,
743                    (char *) p->data_,
744                    p->size_);
745     }
746 }
747
748 /* This code is called periodically to check if the LLDP module has an LLDP
749  * message it wishes to send.  It is called several times every second.
750  */
751 bool
752 lldp_should_send_packet(struct lldp *cfg) OVS_EXCLUDED(mutex)
753 {
754     bool ret;
755
756     ovs_mutex_lock(&mutex);
757     ret = timer_expired(&cfg->tx_timer);
758     ovs_mutex_unlock(&mutex);
759
760     return ret;
761 }
762
763 /* Returns the next wake up time.
764  */
765 long long int
766 lldp_wake_time(const struct lldp *lldp) OVS_EXCLUDED(mutex)
767 {
768     long long int retval;
769
770     if (!lldp) {
771         return LLONG_MAX;
772     }
773
774     ovs_mutex_lock(&mutex);
775     retval = lldp->tx_timer.t;
776     ovs_mutex_unlock(&mutex);
777
778     return retval;
779 }
780
781 /* Put the monitor thread to sleep until it's next wake time.
782  */
783 long long int
784 lldp_wait(struct lldp *lldp) OVS_EXCLUDED(mutex)
785 {
786     long long int wake_time = lldp_wake_time(lldp);
787     poll_timer_wait_until(wake_time);
788     return wake_time;
789 }
790
791 /* Prepare the LLDP packet to be sent on a bridge port.
792  */
793 void
794 lldp_put_packet(struct lldp *lldp, struct dp_packet *packet,
795                 uint8_t eth_src[ETH_ADDR_LEN]) OVS_EXCLUDED(mutex)
796 {
797     struct lldpd *mylldpd = lldp->lldpd;
798     struct lldpd_hardware *hw = (struct lldpd_hardware *)
799         mylldpd->g_hardware.h_entries.next;
800     uint32_t lldp_size = 0;
801     static const uint8_t eth_addr_lldp[6] =
802         {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
803
804     ovs_mutex_lock(&mutex);
805
806     eth_compose(packet, eth_addr_lldp, eth_src, ETH_TYPE_LLDP, 0);
807
808     lldp_size = lldpd_send(hw, packet);
809     if (lldp_size + ETH_HEADER_LEN < MINIMUM_ETH_PACKET_SIZE) {
810         lldp_size = MINIMUM_ETH_PACKET_SIZE;
811     }
812
813     timer_set_duration(&lldp->tx_timer, lldp->lldpd->g_config.c_tx_interval);
814     ovs_mutex_unlock(&mutex);
815 }
816
817 /* Configures the LLDP stack.
818  */
819 bool
820 lldp_configure(struct lldp *lldp) OVS_EXCLUDED(mutex)
821 {
822     if (lldp) {
823         ovs_mutex_lock(&mutex);
824         timer_set_expired(&lldp->tx_timer);
825         timer_set_duration(&lldp->tx_timer, LLDP_DEFAULT_TRANSMIT_INTERVAL_MS);
826         lldp->lldpd->g_config.c_tx_interval =
827             LLDP_DEFAULT_TRANSMIT_INTERVAL_MS;
828         ovs_mutex_unlock(&mutex);
829     }
830
831     return true;
832 }
833
834 /* Create an LLDP stack instance.  At the moment there is one per bridge port.
835  */
836 struct lldp *
837 lldp_create(const struct netdev *netdev,
838             const uint32_t mtu,
839             const struct smap *cfg) OVS_EXCLUDED(mutex)
840 {
841     struct lldp *lldp;
842     struct lldpd_chassis *lchassis;
843     struct lldpd_hardware *hw;
844     struct aa_mapping_internal *m;
845
846     if (!cfg || !smap_get_bool(cfg, "enable", false)) {
847         return NULL;
848     }
849
850     lldp = xzalloc(sizeof *lldp);
851     lldp->name = xstrdup(netdev_get_name(netdev));
852     lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
853
854     hmap_init(&lldp->mappings_by_isid);
855     hmap_init(&lldp->mappings_by_aux);
856     list_init(&lldp->active_mapping_queue);
857
858     lchassis = xzalloc(sizeof *lchassis);
859     lchassis->c_cap_available = LLDP_CAP_BRIDGE;
860     lchassis->c_cap_enabled = LLDP_CAP_BRIDGE;
861     lchassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
862     lchassis->c_id_len = ETH_ADDR_LEN;
863     lchassis->c_id = xmalloc(ETH_ADDR_LEN);
864     netdev_get_etheraddr(netdev, (uint8_t *) lchassis->c_id);
865
866     list_init(&lchassis->c_mgmt.m_entries);
867     lchassis->c_ttl = lldp->lldpd->g_config.c_tx_interval *
868                       lldp->lldpd->g_config.c_tx_hold;
869     lchassis->c_ttl = LLDP_CHASSIS_TTL;
870     lldpd_assign_cfg_to_protocols(lldp->lldpd);
871     list_init(&lldp->lldpd->g_chassis.list);
872     list_push_back(&lldp->lldpd->g_chassis.list, &lchassis->list);
873
874     if ((hw = lldpd_alloc_hardware(lldp->lldpd,
875                                    (char *) netdev_get_name(netdev),
876                                    0)) == NULL) {
877         VLOG_WARN("Unable to allocate space for %s",
878                   (char *) netdev_get_name(netdev));
879         out_of_memory();
880     }
881
882     ovs_refcount_init(&lldp->ref_cnt);
883 #ifndef _WIN32
884     hw->h_flags |= IFF_RUNNING;
885 #endif
886     hw->h_mtu = mtu;
887     hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
888     hw->h_lport.p_id = xstrdup(netdev_get_name(netdev));
889
890     /* p_id is not necessarily a null terminated string. */
891     hw->h_lport.p_id_len = strlen(netdev_get_name(netdev));
892
893     /* Auto Attach element tlv */
894     hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
895     hw->h_lport.p_element.mgmt_vlan = 0;
896     memcpy(&hw->h_lport.p_element.system_id.system_mac,
897            lchassis->c_id, lchassis->c_id_len);
898     hw->h_lport.p_element.system_id.conn_type =
899         LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
900
901     hw->h_lport.p_element.system_id.smlt_id = 0;
902     hw->h_lport.p_element.system_id.mlt_id[0] = 0;
903     hw->h_lport.p_element.system_id.mlt_id[1] = 0;
904
905     list_init(&hw->h_lport.p_isid_vlan_maps.m_entries);
906     list_init(&lldp->lldpd->g_hardware.h_entries);
907     list_push_back(&lldp->lldpd->g_hardware.h_entries, &hw->h_entries);
908
909     ovs_mutex_lock(&mutex);
910
911     /* Update port with Auto Attach mappings configured. */
912     HMAP_FOR_EACH (m, hmap_node_isid, all_mappings) {
913         struct aa_mapping_internal *p;
914
915         if (mapping_find_by_isid(lldp, m->isid)) {
916             continue;
917         }
918
919         p = xmemdup(m, sizeof *p);
920         hmap_insert(&lldp->mappings_by_isid,
921                     &p->hmap_node_isid,
922                     hash_bytes((const void *) &p->isid,
923                                sizeof p->isid,
924                                0));
925         hmap_insert(&lldp->mappings_by_aux,
926                     &p->hmap_node_aux,
927                     hash_pointer(p->aux, 0));
928
929         update_mapping_on_lldp(lldp, hw, p);
930     }
931
932     hmap_insert(all_lldps, &lldp->hmap_node,
933                 hash_string(netdev_get_name(netdev), 0));
934
935     ovs_mutex_unlock(&mutex);
936
937     return lldp;
938 }
939
940
941 struct lldp *
942 lldp_create_dummy(void)
943 {
944     struct lldp *lldp;
945     struct lldpd_chassis *lchassis;
946     struct lldpd_hardware *hw;
947
948     lldp = xzalloc(sizeof *lldp);
949     lldp->name = "dummy-lldp";
950     lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
951
952     hmap_init(&lldp->mappings_by_isid);
953     hmap_init(&lldp->mappings_by_aux);
954     list_init(&lldp->active_mapping_queue);
955
956     lchassis = xzalloc(sizeof *lchassis);
957     lchassis->c_cap_available = LLDP_CAP_BRIDGE;
958     lchassis->c_cap_enabled = LLDP_CAP_BRIDGE;
959     lchassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
960     lchassis->c_id_len = ETH_ADDR_LEN;
961     lchassis->c_id = xmalloc(ETH_ADDR_LEN);
962
963     list_init(&lchassis->c_mgmt.m_entries);
964     lchassis->c_ttl = LLDP_CHASSIS_TTL;
965     lldpd_assign_cfg_to_protocols(lldp->lldpd);
966     list_init(&lldp->lldpd->g_chassis.list);
967     list_push_back(&lldp->lldpd->g_chassis.list, &lchassis->list);
968
969     hw = lldpd_alloc_hardware(lldp->lldpd, "dummy-hw", 0);
970
971     ovs_refcount_init(&lldp->ref_cnt);
972 #ifndef _WIN32
973     hw->h_flags |= IFF_RUNNING;
974 #endif
975     hw->h_mtu = 1500;
976     hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
977     hw->h_lport.p_id = "dummy-port";
978
979     /* p_id is not necessarily a null terminated string. */
980     hw->h_lport.p_id_len = strlen(hw->h_lport.p_id);
981
982     /* Auto Attach element tlv */
983     hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
984     hw->h_lport.p_element.mgmt_vlan = 0;
985     memcpy(&hw->h_lport.p_element.system_id.system_mac,
986            lchassis->c_id, lchassis->c_id_len);
987     hw->h_lport.p_element.system_id.conn_type =
988         LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
989     hw->h_lport.p_element.system_id.smlt_id = 0;
990     hw->h_lport.p_element.system_id.mlt_id[0] = 0;
991     hw->h_lport.p_element.system_id.mlt_id[1] = 0;
992
993     list_init(&hw->h_lport.p_isid_vlan_maps.m_entries);
994     list_init(&lldp->lldpd->g_hardware.h_entries);
995     list_push_back(&lldp->lldpd->g_hardware.h_entries, &hw->h_entries);
996
997     return lldp;
998 }
999
1000 /* Unreference a specific LLDP instance.
1001  */
1002 void
1003 lldp_unref(struct lldp *lldp)
1004 {
1005     if (!lldp) {
1006         return;
1007     }
1008
1009     ovs_mutex_lock(&mutex);
1010     if (ovs_refcount_unref_relaxed(&lldp->ref_cnt) != 1) {
1011         ovs_mutex_unlock(&mutex);
1012         return;
1013     }
1014
1015     hmap_remove(all_lldps, &lldp->hmap_node);
1016     ovs_mutex_unlock(&mutex);
1017
1018     lldpd_cleanup(lldp->lldpd);
1019     free(lldp->lldpd);
1020     free(lldp->name);
1021     free(lldp);
1022 }
1023
1024 /* Unreference a specific LLDP instance.
1025  */
1026 struct lldp *
1027 lldp_ref(const struct lldp *lldp_)
1028 {
1029     struct lldp *lldp = CONST_CAST(struct lldp *, lldp_);
1030     if (lldp) {
1031         ovs_refcount_ref(&lldp->ref_cnt);
1032     }
1033     return lldp;
1034 }