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