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