]> git.proxmox.com Git - mirror_ovs.git/blob - lib/ovs-lldp.c
ovs-lldp: Remove unused variable 'lldp_size'.
[mirror_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) {
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 const char *none_str = "<None>";
206 const char *descr = NULL;
207 char *id = NULL;
208 char *system;
209
210 if (port->p_chassis) {
211 if (port->p_chassis->c_id_len > 0) {
212 chassisid_to_string(port->p_chassis->c_id,
213 port->p_chassis->c_id_len, &id);
214 }
215
216 descr = port->p_chassis->c_descr;
217 }
218
219 chassisid_to_string((uint8_t *) &port->p_element.system_id,
220 sizeof port->p_element.system_id, &system);
221
222 ds_put_format(ds, "\tAuto Attach Primary Server Id: %s\n",
223 id ? id : none_str);
224 ds_put_format(ds, "\tAuto Attach Primary Server Descr: %s\n",
225 descr ? descr : none_str);
226 ds_put_format(ds, "\tAuto Attach Primary Server System Id: %s\n",
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 */
238 static void
239 aa_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
249 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware) {
250 aa_print_element_status_port(ds, hw);
251 }
252 }
253
254 static void
255 aa_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
260 if (list_is_empty(&port->p_isid_vlan_maps)) {
261 return;
262 }
263
264 LIST_FOR_EACH (mapping, m_entries, &port->p_isid_vlan_maps) {
265 uint32_t isid = mapping->isid_vlan_data.isid;
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
273 /* Update the status of our internal state for the mapping. */
274 if (m) {
275 VLOG_INFO("Setting status for ISID=%"PRIu32" to %"PRIu16,
276 isid, mapping->isid_vlan_data.status);
277 m->status = mapping->isid_vlan_data.status;
278 } else {
279 VLOG_WARN("Couldn't find mapping for I-SID=%"PRIu32, isid);
280 }
281 }
282 }
283
284 static void
285 aa_print_isid_status_port(struct lldp *lldp, struct lldpd_hardware *hw)
286 OVS_REQUIRES(mutex)
287 {
288 struct lldpd_port *port;
289
290 LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
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 */
298 static void
299 aa_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
310 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware) {
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) {
322 ds_put_format(ds, "%-8"PRIu32" %-4"PRIu16" %-11s %-11s\n",
323 m->isid, m->vlan, "Switch", aa_status_to_str(m->status));
324 }
325 }
326
327 static void
328 aa_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
346 static void
347 aa_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
365 static void
366 aa_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 */
388 static void
389 update_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
394 if (hardware->h_ifname) {
395 VLOG_INFO("\t\t hardware->h_ifname=%s", hardware->h_ifname);
396 }
397
398 lm->isid_vlan_data.isid = m->isid;
399 lm->isid_vlan_data.vlan = m->vlan;
400
401 list_push_back(&hardware->h_lport.p_isid_vlan_maps, &lm->m_entries);
402
403 /* TODO Should be done in the Auto Attach state machine when a mapping goes
404 * from "pending" to "active".
405 */
406 struct bridge_aa_vlan *node = xmalloc(sizeof *node);
407
408 node->port_name = xstrdup(hardware->h_ifname);
409 node->vlan = m->vlan;
410 node->oper = BRIDGE_AA_VLAN_OPER_ADD;
411
412 list_push_back(&lldp->active_mapping_queue, &node->list_node);
413 }
414
415 /* Bridge will poll the list of VLAN that needs to be auto configure based on
416 * the Auto Attach mappings that have been exchanged with the server.
417 */
418 int
419 aa_get_vlan_queued(struct ovs_list *list)
420 {
421 struct lldp *lldp;
422
423 ovs_mutex_lock(&mutex);
424
425 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
426 struct bridge_aa_vlan *node;
427
428 LIST_FOR_EACH_POP (node, list_node, &lldp->active_mapping_queue) {
429 struct bridge_aa_vlan *copy;
430
431 copy = xmalloc(sizeof *copy);
432 copy->port_name = xstrdup(node->port_name);
433 copy->vlan = node->vlan;
434 copy->oper = node->oper;
435
436 list_push_back(list, &copy->list_node);
437
438 /* Cleanup */
439 free(node->port_name);
440 free(node);
441 }
442 }
443
444 ovs_mutex_unlock(&mutex);
445
446 return 0;
447 }
448
449 /* Bridge will poll whether or not VLAN have been auto-configured.
450 */
451 unsigned int
452 aa_get_vlan_queue_size(void)
453 {
454 struct lldp *lldp;
455 unsigned int size = 0;
456
457 ovs_mutex_lock(&mutex);
458
459 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
460 size += list_size(&lldp->active_mapping_queue);
461 }
462
463 ovs_mutex_unlock(&mutex);
464
465 return size;
466 }
467
468 /* Configure Auto Attach.
469 */
470 int
471 aa_configure(const struct aa_settings *s)
472 {
473 struct lldp *lldp;
474
475 ovs_mutex_lock(&mutex);
476
477 /* TODO Change all instances for now */
478 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
479 struct lldpd_chassis *chassis;
480
481 LIST_FOR_EACH (chassis, list, &lldp->lldpd->g_chassis) {
482 /* System Description */
483 free(chassis->c_descr);
484 chassis->c_descr = s && s->system_description[0] ?
485 xstrdup(s->system_description) : xstrdup(PACKAGE_STRING);
486
487 /* System Name */
488 if (s) {
489 free(chassis->c_name);
490 chassis->c_name = xstrdup(s->system_name);
491 }
492 }
493 }
494
495 ovs_mutex_unlock(&mutex);
496
497 return 0;
498 }
499
500 /* Add a new Auto Attach mapping.
501 */
502 int
503 aa_mapping_register(void *aux, const struct aa_mapping_settings *s)
504 {
505 struct aa_mapping_internal *bridge_m;
506 struct lldp *lldp;
507
508 VLOG_INFO("Adding mapping ISID=%"PRIu32", VLAN=%"PRIu16", aux=%p",
509 s->isid, s->vlan, aux);
510
511 ovs_mutex_lock(&mutex);
512
513 /* TODO These mappings should be stores per bridge. This is used
514 * When a port is added. Auto Attach mappings need to be added on this
515 * port.
516 */
517 bridge_m = xzalloc(sizeof *bridge_m);
518 bridge_m->isid = s->isid;
519 bridge_m->vlan = s->vlan;
520 bridge_m->aux = aux;
521 bridge_m->status = AA_STATUS_PENDING;
522 hmap_insert(all_mappings, &bridge_m->hmap_node_isid,
523 hash_int(bridge_m->isid, 0));
524
525
526 /* Update mapping on the all the LLDP instances. */
527 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
528 struct lldpd_hardware *hw;
529 struct aa_mapping_internal *m;
530
531 VLOG_INFO("\t lldp->name=%s", lldp->name);
532
533 if (mapping_find_by_isid(lldp, s->isid)) {
534 continue;
535 }
536
537 m = xzalloc(sizeof *m);
538 m->isid = s->isid;
539 m->vlan = s->vlan;
540 m->status = AA_STATUS_PENDING;
541 m->aux = aux;
542 hmap_insert(&lldp->mappings_by_isid, &m->hmap_node_isid,
543 hash_int(m->isid, 0));
544 hmap_insert(&lldp->mappings_by_aux,
545 &m->hmap_node_aux,
546 hash_pointer(m->aux, 0));
547
548 /* Configure the mapping on each port of the LLDP stack. */
549 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware) {
550 update_mapping_on_lldp(lldp, hw, m);
551 }
552 }
553
554 ovs_mutex_unlock(&mutex);
555
556 return 0;
557 }
558
559 static void
560 aa_mapping_unregister_mapping(struct lldp *lldp,
561 struct lldpd_hardware *hw,
562 struct aa_mapping_internal *m)
563 {
564 struct lldpd_aa_isid_vlan_maps_tlv *lm, *lm_next;
565
566 LIST_FOR_EACH_SAFE (lm, lm_next, m_entries,
567 &hw->h_lport.p_isid_vlan_maps) {
568 uint32_t isid = lm->isid_vlan_data.isid;
569
570 if (isid == m->isid) {
571 VLOG_INFO("\t\t Removing lport, isid=%u, vlan=%u",
572 isid,
573 lm->isid_vlan_data.vlan);
574
575 list_remove(&lm->m_entries);
576
577 /* TODO Should be done in the AA SM when a mapping goes
578 * from "pending" to "active".
579 */
580 struct bridge_aa_vlan *node = xmalloc(sizeof *node);
581
582 node->port_name = xstrdup(hw->h_ifname);
583 node->vlan = m->vlan;
584 node->oper = BRIDGE_AA_VLAN_OPER_REMOVE;
585
586 list_push_back(&lldp->active_mapping_queue, &node->list_node);
587
588 break;
589 }
590 }
591 }
592
593 /* Remove an existing Auto Attach mapping.
594 */
595 int
596 aa_mapping_unregister(void *aux)
597 {
598 struct lldp *lldp;
599
600 VLOG_INFO("Removing mapping aux=%p", aux);
601
602 ovs_mutex_lock(&mutex);
603
604 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
605 struct lldpd_hardware *hw;
606 struct aa_mapping_internal *m = mapping_find_by_aux(lldp, aux);
607
608 /* Remove from internal hash tables. */
609 if (m) {
610 uint32_t isid = m->isid;
611 uint16_t vlan = m->vlan;
612 struct aa_mapping_internal *p = mapping_find_by_isid(lldp, isid);
613
614 VLOG_INFO("\t Removing mapping ISID=%"PRIu32", VLAN=%"PRIu16
615 " (lldp->name=%s)", isid, vlan, lldp->name);
616
617 if (p) {
618 hmap_remove(&lldp->mappings_by_isid, &p->hmap_node_isid);
619 }
620
621 hmap_remove(&lldp->mappings_by_aux, &m->hmap_node_aux);
622 free(m);
623
624 /* Remove from all the lldp instances */
625 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware) {
626 if (hw->h_ifname) {
627 VLOG_INFO("\t\t hardware->h_ifname=%s", hw->h_ifname);
628 }
629
630 aa_mapping_unregister_mapping(lldp, hw, m);
631 }
632
633 /* Remove from the all_mappings */
634 HMAP_FOR_EACH (m, hmap_node_isid, all_mappings) {
635 if (m && isid == m->isid && vlan == m->vlan) {
636 hmap_remove(all_mappings, &m->hmap_node_isid);
637 break;
638 }
639 }
640 }
641 }
642
643 ovs_mutex_unlock(&mutex);
644
645 return 0;
646 }
647
648 void
649 lldp_init(void)
650 {
651 unixctl_command_register("autoattach/status", "[bridge]", 0, 1,
652 aa_unixctl_status, NULL);
653 unixctl_command_register("autoattach/show-isid", "[bridge]", 0, 1,
654 aa_unixctl_show_isid, NULL);
655 unixctl_command_register("autoattach/statistics", "[bridge]", 0, 1,
656 aa_unixctl_statistics, NULL);
657 }
658
659 /* Returns true if 'lldp' should process packets from 'flow'. Sets
660 * fields in 'wc' that were used to make the determination.
661 */
662 bool
663 lldp_should_process_flow(const struct flow *flow)
664 {
665 return (flow->dl_type == htons(ETH_TYPE_LLDP));
666 }
667
668
669 /* Process an LLDP packet that was received on a bridge port.
670 */
671 void
672 lldp_process_packet(struct lldp *lldp, const struct dp_packet *p)
673 {
674 if (lldp) {
675 lldpd_recv(lldp->lldpd, lldpd_first_hardware(lldp->lldpd),
676 (char *) dp_packet_data(p), dp_packet_size(p));
677 }
678 }
679
680 /* This code is called periodically to check if the LLDP module has an LLDP
681 * message it wishes to send. It is called several times every second.
682 */
683 bool
684 lldp_should_send_packet(struct lldp *cfg) OVS_EXCLUDED(mutex)
685 {
686 bool ret;
687
688 ovs_mutex_lock(&mutex);
689 ret = timer_expired(&cfg->tx_timer);
690 ovs_mutex_unlock(&mutex);
691
692 return ret;
693 }
694
695 /* Returns the next wake up time.
696 */
697 long long int
698 lldp_wake_time(const struct lldp *lldp) OVS_EXCLUDED(mutex)
699 {
700 long long int retval;
701
702 if (!lldp) {
703 return LLONG_MAX;
704 }
705
706 ovs_mutex_lock(&mutex);
707 retval = lldp->tx_timer.t;
708 ovs_mutex_unlock(&mutex);
709
710 return retval;
711 }
712
713 /* Put the monitor thread to sleep until it's next wake time.
714 */
715 long long int
716 lldp_wait(struct lldp *lldp) OVS_EXCLUDED(mutex)
717 {
718 long long int wake_time = lldp_wake_time(lldp);
719 poll_timer_wait_until(wake_time);
720 return wake_time;
721 }
722
723 /* Prepare the LLDP packet to be sent on a bridge port.
724 */
725 void
726 lldp_put_packet(struct lldp *lldp, struct dp_packet *packet,
727 uint8_t eth_src[ETH_ADDR_LEN]) OVS_EXCLUDED(mutex)
728 {
729 struct lldpd *mylldpd = lldp->lldpd;
730 struct lldpd_hardware *hw = lldpd_first_hardware(mylldpd);
731 static const uint8_t eth_addr_lldp[6] =
732 {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
733
734 ovs_mutex_lock(&mutex);
735
736 eth_compose(packet, eth_addr_lldp, eth_src, ETH_TYPE_LLDP, 0);
737
738 lldpd_send(hw, packet);
739
740 timer_set_duration(&lldp->tx_timer, lldp->lldpd->g_config.c_tx_interval);
741 ovs_mutex_unlock(&mutex);
742 }
743
744 /* Configures the LLDP stack.
745 */
746 bool
747 lldp_configure(struct lldp *lldp) OVS_EXCLUDED(mutex)
748 {
749 if (lldp) {
750 ovs_mutex_lock(&mutex);
751 timer_set_expired(&lldp->tx_timer);
752 timer_set_duration(&lldp->tx_timer, LLDP_DEFAULT_TRANSMIT_INTERVAL_MS);
753 lldp->lldpd->g_config.c_tx_interval =
754 LLDP_DEFAULT_TRANSMIT_INTERVAL_MS;
755 ovs_mutex_unlock(&mutex);
756 }
757
758 return true;
759 }
760
761 /* Create an LLDP stack instance. At the moment there is one per bridge port.
762 */
763 struct lldp *
764 lldp_create(const struct netdev *netdev,
765 const uint32_t mtu,
766 const struct smap *cfg) OVS_EXCLUDED(mutex)
767 {
768 struct lldp *lldp;
769 struct lldpd_chassis *lchassis;
770 struct lldpd_hardware *hw;
771 struct aa_mapping_internal *m;
772
773 if (!cfg || !smap_get_bool(cfg, "enable", false)) {
774 return NULL;
775 }
776
777 lldp = xzalloc(sizeof *lldp);
778 lldp->name = xstrdup(netdev_get_name(netdev));
779 lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
780
781 hmap_init(&lldp->mappings_by_isid);
782 hmap_init(&lldp->mappings_by_aux);
783 list_init(&lldp->active_mapping_queue);
784
785 lchassis = xzalloc(sizeof *lchassis);
786 lchassis->c_cap_available = LLDP_CAP_BRIDGE;
787 lchassis->c_cap_enabled = LLDP_CAP_BRIDGE;
788 lchassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
789 lchassis->c_id_len = ETH_ADDR_LEN;
790 lchassis->c_id = xmalloc(ETH_ADDR_LEN);
791 netdev_get_etheraddr(netdev, lchassis->c_id);
792
793 list_init(&lchassis->c_mgmt);
794 lchassis->c_ttl = lldp->lldpd->g_config.c_tx_interval *
795 lldp->lldpd->g_config.c_tx_hold;
796 lchassis->c_ttl = LLDP_CHASSIS_TTL;
797 lldpd_assign_cfg_to_protocols(lldp->lldpd);
798 list_init(&lldp->lldpd->g_chassis);
799 list_push_back(&lldp->lldpd->g_chassis, &lchassis->list);
800
801 if ((hw = lldpd_alloc_hardware(lldp->lldpd,
802 (char *) netdev_get_name(netdev),
803 0)) == NULL) {
804 VLOG_WARN("Unable to allocate space for %s",
805 (char *) netdev_get_name(netdev));
806 out_of_memory();
807 }
808
809 ovs_refcount_init(&lldp->ref_cnt);
810 #ifndef _WIN32
811 hw->h_flags |= IFF_RUNNING;
812 #endif
813 hw->h_mtu = mtu;
814 hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
815 hw->h_lport.p_id = xstrdup(netdev_get_name(netdev));
816
817 /* p_id is not necessarily a null terminated string. */
818 hw->h_lport.p_id_len = strlen(netdev_get_name(netdev));
819
820 /* Auto Attach element tlv */
821 hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH;
822 hw->h_lport.p_element.mgmt_vlan = 0;
823 memcpy(&hw->h_lport.p_element.system_id.system_mac,
824 lchassis->c_id, lchassis->c_id_len);
825 hw->h_lport.p_element.system_id.conn_type =
826 LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
827 hw->h_lport.p_element.system_id.rsvd = 0;
828 hw->h_lport.p_element.system_id.rsvd2[0] = 0;
829 hw->h_lport.p_element.system_id.rsvd2[1] = 0;
830
831 list_init(&hw->h_lport.p_isid_vlan_maps);
832 list_init(&lldp->lldpd->g_hardware);
833 list_push_back(&lldp->lldpd->g_hardware, &hw->h_entries);
834
835 ovs_mutex_lock(&mutex);
836
837 /* Update port with Auto Attach mappings configured. */
838 HMAP_FOR_EACH (m, hmap_node_isid, all_mappings) {
839 struct aa_mapping_internal *p;
840
841 if (mapping_find_by_isid(lldp, m->isid)) {
842 continue;
843 }
844
845 p = xmemdup(m, sizeof *p);
846 hmap_insert(&lldp->mappings_by_isid, &p->hmap_node_isid,
847 hash_int(p->isid, 0));
848 hmap_insert(&lldp->mappings_by_aux,
849 &p->hmap_node_aux,
850 hash_pointer(p->aux, 0));
851
852 update_mapping_on_lldp(lldp, hw, p);
853 }
854
855 hmap_insert(all_lldps, &lldp->hmap_node,
856 hash_string(netdev_get_name(netdev), 0));
857
858 ovs_mutex_unlock(&mutex);
859
860 return lldp;
861 }
862
863
864 struct lldp *
865 lldp_create_dummy(void)
866 {
867 struct lldp *lldp;
868 struct lldpd_chassis *lchassis;
869 struct lldpd_hardware *hw;
870
871 lldp = xzalloc(sizeof *lldp);
872 lldp->name = "dummy-lldp";
873 lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
874
875 hmap_init(&lldp->mappings_by_isid);
876 hmap_init(&lldp->mappings_by_aux);
877 list_init(&lldp->active_mapping_queue);
878
879 lchassis = xzalloc(sizeof *lchassis);
880 lchassis->c_cap_available = LLDP_CAP_BRIDGE;
881 lchassis->c_cap_enabled = LLDP_CAP_BRIDGE;
882 lchassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
883 lchassis->c_id_len = ETH_ADDR_LEN;
884 lchassis->c_id = xmalloc(ETH_ADDR_LEN);
885
886 list_init(&lchassis->c_mgmt);
887 lchassis->c_ttl = LLDP_CHASSIS_TTL;
888 lldpd_assign_cfg_to_protocols(lldp->lldpd);
889 list_init(&lldp->lldpd->g_chassis);
890 list_push_back(&lldp->lldpd->g_chassis, &lchassis->list);
891
892 hw = lldpd_alloc_hardware(lldp->lldpd, "dummy-hw", 0);
893
894 ovs_refcount_init(&lldp->ref_cnt);
895 #ifndef _WIN32
896 hw->h_flags |= IFF_RUNNING;
897 #endif
898 hw->h_mtu = 1500;
899 hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
900 hw->h_lport.p_id = "dummy-port";
901
902 /* p_id is not necessarily a null terminated string. */
903 hw->h_lport.p_id_len = strlen(hw->h_lport.p_id);
904
905 /* Auto Attach element tlv */
906 hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH;
907 hw->h_lport.p_element.mgmt_vlan = 0;
908 memcpy(&hw->h_lport.p_element.system_id.system_mac,
909 lchassis->c_id, lchassis->c_id_len);
910 hw->h_lport.p_element.system_id.conn_type =
911 LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
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;
915
916 list_init(&hw->h_lport.p_isid_vlan_maps);
917 list_init(&lldp->lldpd->g_hardware);
918 list_push_back(&lldp->lldpd->g_hardware, &hw->h_entries);
919
920 return lldp;
921 }
922
923 /* Unreference a specific LLDP instance.
924 */
925 void
926 lldp_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
947 /* Unreference a specific LLDP instance.
948 */
949 struct lldp *
950 lldp_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 }