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