2 * Copyright (c) 2014 WindRiver, Inc.
3 * Copyright (c) 2015 Avaya, Inc.
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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 /* Implementation of Auto Attach.
19 * Based on sample implementation in 802.1ab. Above copyright and license
20 * applies to all modifications.
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
30 #include <arpa/inet.h>
32 #include <netinet/in.h>
35 #include <sys/types.h>
36 #include "dynamic-string.h"
39 #include "lldp/lldpd.h"
40 #include "lldp/lldpd-structs.h"
42 #include "openvswitch/types.h"
44 #include "poll-loop.h"
48 #include "openvswitch/vlog.h"
50 VLOG_DEFINE_THIS_MODULE(ovs_lldp);
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
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)
69 #define AA_STATUS(NAME, VALUE, STR) AA_STATUS_##NAME = VALUE,
75 /* Internal structure for an Auto Attach mapping.
77 struct aa_mapping_internal {
78 struct hmap_node hmap_node_isid;
79 struct hmap_node hmap_node_aux;
83 enum aa_status status;
86 static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
88 /* Hash map of all LLDP instances keyed by name (port at the moment).
90 static struct hmap all_lldps__ = HMAP_INITIALIZER(&all_lldps__);
91 static struct hmap *const all_lldps OVS_GUARDED_BY(mutex) = &all_lldps__;
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.
98 static struct hmap all_mappings__ = HMAP_INITIALIZER(&all_mappings__);
99 static struct hmap *const all_mappings OVS_GUARDED_BY(mutex) = &all_mappings__;
101 static struct lldp_aa_element_system_id system_id_null;
103 /* Convert an array to an integer. I-SID are stored in an array of bytes
104 * in the LLDP hardware structrure.
107 array_to_int(uint8_t *array, size_t len)
112 ovs_assert(len <= sizeof(uint32_t));
114 for (i = 0; i < len; i++) {
115 res = res | (array[len - i - 1] << (i * 8));
121 /* Convert an integer to an array of byte.
124 int_to_array(uint8_t *array, size_t len, uint32_t value)
128 ovs_assert(len <= sizeof(uint32_t));
130 for (i = 0; i < len; i++) {
131 array[len - i - 1] = value >> (8 * i);
135 /* Convert an LLDP chassis ID to a string.
138 chassisid_to_string(uint8_t *array, size_t len, char **str)
142 *str = xmalloc(len * 3);
144 for (i = 0; i < len; i++) {
145 snprintf(&(*str)[i * 3], 4, "%02x:", array[i]);
147 (*str)[(i * 3) - 1] = '\0';
150 /* Find an Auto Attach mapping keyed by I-SID.
152 static struct aa_mapping_internal *
153 mapping_find_by_isid(struct lldp *lldp, const uint64_t isid)
156 struct aa_mapping_internal *m;
158 HMAP_FOR_EACH_IN_BUCKET (m,
160 hash_bytes(&isid, sizeof isid, 0),
161 &lldp->mappings_by_isid) {
162 if (isid == m->isid) {
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.
173 static struct aa_mapping_internal *
174 mapping_find_by_aux(struct lldp *lldp, const void *aux) OVS_REQUIRES(mutex)
176 struct aa_mapping_internal *m;
178 HMAP_FOR_EACH_IN_BUCKET (m, hmap_node_aux, hash_pointer(aux, 0),
179 &lldp->mappings_by_aux) {
188 /* Convert an Auto Attach request status to a string.
191 aa_status_to_str(uint8_t status)
194 #define AA_STATUS(NAME, VALUE, STR) case AA_STATUS_##NAME: return #STR;
197 default: return "Undefined";
201 /* Display LLDP and Auto Attach statistics.
204 aa_print_lldp_and_aa_stats(struct ds *ds, struct lldp *lldp)
207 struct lldpd_hardware *hw;
209 ds_put_format(ds, "Statistics: %s\n", lldp->name);
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);
230 aa_print_element_status_port(struct ds *ds, struct lldpd_hardware *hw)
232 struct lldpd_port *port;
234 LIST_FOR_EACH (port, p_entries, &hw->h_rports.p_entries) {
235 if (memcmp(&port->p_element.system_id,
237 sizeof port->p_element.system_id)) {
238 static char *none_str = "<None>";
239 char *id = none_str, *descr = none_str, *system = none_str;
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);
247 descr = port->p_chassis->c_descr
248 ? port->p_chassis->c_descr : none_str;
251 chassisid_to_string((uint8_t *) &port->p_element.system_id,
252 sizeof port->p_element.system_id, &system);
255 "\tAuto Attach Primary Server Id: %s\n",
258 "\tAuto Attach Primary Server Descr: %s\n",
261 "\tAuto Attach Primary Server System Id: %s\n",
270 /* Auto Attach server broadcast an LLDP message periodically. Display
271 * the discovered server.
274 aa_print_element_status(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex)
276 struct lldpd_hardware *hw;
278 ds_put_format(ds, "LLDP: %s\n", lldp->name);
284 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
285 aa_print_element_status_port(ds, hw);
290 aa_print_isid_status_port_isid(struct lldp *lldp, struct lldpd_port *port)
293 struct lldpd_aa_isid_vlan_maps_tlv *mapping;
295 if (list_is_empty(&port->p_isid_vlan_maps.m_entries)) {
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);
304 VLOG_INFO("h_rport: isid=%u, vlan=%u, status=%d",
306 mapping->isid_vlan_data.vlan,
307 mapping->isid_vlan_data.status);
309 /* Update the status of our internal state for the mapping.
312 VLOG_INFO("Setting status for ISID=%u to %u",
314 mapping->isid_vlan_data.status);
315 m->status = mapping->isid_vlan_data.status;
317 VLOG_WARN("Couldn't find mapping for I-SID=%u", isid);
323 aa_print_isid_status_port(struct lldp *lldp, struct lldpd_hardware *hw)
326 struct lldpd_port *port;
328 LIST_FOR_EACH (port, p_entries, &hw->h_rports.p_entries) {
329 aa_print_isid_status_port_isid(lldp, port);
333 /* The Auto Attach server will broadcast the status of the configured mappings
334 * via LLDP. Display the status.
337 aa_print_isid_status(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex)
339 struct lldpd_hardware *hw;
340 struct aa_mapping_internal *m;
346 ds_put_format(ds, "LLDP: %s\n", lldp->name);
348 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
349 aa_print_isid_status_port(lldp, hw);
352 ds_put_format(ds, "%-8s %-4s %-11s %-8s\n",
357 ds_put_format(ds, "-------- ---- ----------- --------\n");
359 HMAP_FOR_EACH (m, hmap_node_isid, &lldp->mappings_by_isid) {
360 ds_put_format(ds, "%-8ld %-4ld %-11s %-11s\n",
364 aa_status_to_str(m->status));
369 aa_unixctl_status(struct unixctl_conn *conn, int argc OVS_UNUSED,
370 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
374 struct ds ds = DS_EMPTY_INITIALIZER;
376 ovs_mutex_lock(&mutex);
378 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
379 aa_print_element_status(&ds, lldp);
381 unixctl_command_reply(conn, ds_cstr(&ds));
384 ovs_mutex_unlock(&mutex);
388 aa_unixctl_show_isid(struct unixctl_conn *conn, int argc OVS_UNUSED,
389 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
393 struct ds ds = DS_EMPTY_INITIALIZER;
395 ovs_mutex_lock(&mutex);
397 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
398 aa_print_isid_status(&ds, lldp);
400 unixctl_command_reply(conn, ds_cstr(&ds));
403 ovs_mutex_unlock(&mutex);
407 aa_unixctl_statistics(struct unixctl_conn *conn, int argc OVS_UNUSED,
408 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
411 struct ds ds = DS_EMPTY_INITIALIZER;
414 ovs_mutex_lock(&mutex);
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);
421 ovs_mutex_unlock(&mutex);
423 unixctl_command_reply(conn, ds_cstr(&ds));
426 /* An Auto Attach mapping was configured. Populate the corresponding
427 * structures in the LLDP hardware.
430 update_mapping_on_lldp(struct lldp *lldp, struct lldpd_hardware *hardware,
431 struct aa_mapping_internal *m)
433 struct lldpd_aa_isid_vlan_maps_tlv *lm = xzalloc(sizeof *lm);
435 if (hardware->h_ifname) {
436 VLOG_INFO("\t\t hardware->h_ifname=%s", hardware->h_ifname);
439 int_to_array(lm->isid_vlan_data.isid,
440 ARRAY_SIZE(lm->isid_vlan_data.isid),
442 lm->isid_vlan_data.vlan = m->vlan;
444 list_push_back(&hardware->h_lport.p_isid_vlan_maps.m_entries,
447 /* TODO Should be done in the Auto Attach state machine when a mapping goes
448 * from "pending" to "active".
451 struct bridge_aa_vlan *node = xmalloc(sizeof *node);
453 node->port_name = xstrdup(hardware->h_ifname);
454 node->vlan = m->vlan;
455 node->oper = BRIDGE_AA_VLAN_OPER_ADD;
457 list_push_back(&lldp->active_mapping_queue, &node->list_node);
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.
465 aa_get_vlan_queued(struct ovs_list *list)
469 ovs_mutex_lock(&mutex);
471 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
472 struct bridge_aa_vlan *node, *node_next;
474 LIST_FOR_EACH_SAFE (node,
477 &lldp->active_mapping_queue) {
478 struct bridge_aa_vlan *copy;
480 copy = xmalloc(sizeof *copy);
481 copy->port_name = xstrdup(node->port_name);
482 copy->vlan = node->vlan;
483 copy->oper = node->oper;
485 list_push_back(list, ©->list_node);
488 list_remove(&node->list_node);
489 free(node->port_name);
494 ovs_mutex_unlock(&mutex);
499 /* Bridge will poll whether or not VLAN have been auto-configured.
502 aa_get_vlan_queue_size(void)
505 unsigned int size = 0;
507 ovs_mutex_lock(&mutex);
509 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
510 size += list_size(&lldp->active_mapping_queue);
513 ovs_mutex_unlock(&mutex);
518 /* Configure Auto Attach.
521 aa_configure(const struct aa_settings *s)
525 ovs_mutex_lock(&mutex);
527 /* TODO Change all instances for now */
528 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
529 struct lldpd_chassis *chassis;
531 LIST_FOR_EACH (chassis, list, &lldp->lldpd->g_chassis.list) {
532 /* System Description */
533 if (chassis->c_descr) {
534 free(chassis->c_descr);
536 chassis->c_descr = s->system_description[0] ?
537 xstrdup(s->system_description) : xstrdup(PACKAGE_STRING);
540 if (chassis->c_name) {
541 free(chassis->c_name);
543 chassis->c_name = xstrdup(s->system_name);
547 ovs_mutex_unlock(&mutex);
552 /* Add a new Auto Attach mapping.
555 aa_mapping_register(void *aux, const struct aa_mapping_settings *s)
557 struct aa_mapping_internal *bridge_m;
560 VLOG_INFO("Adding mapping ISID=%ld, VLAN=%ld, aux=%p", (long int) s->isid,
561 (long int) s->vlan, aux);
563 ovs_mutex_lock(&mutex);
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
569 bridge_m = xzalloc(sizeof *bridge_m);
570 bridge_m->isid = s->isid;
571 bridge_m->vlan = s->vlan;
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,
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;
585 VLOG_INFO("\t lldp->name=%s", lldp->name);
587 if (mapping_find_by_isid(lldp, s->isid)) {
591 m = xzalloc(sizeof *m);
594 m->status = AA_STATUS_PENDING;
596 hmap_insert(&lldp->mappings_by_isid,
598 hash_bytes((const void *) &m->isid,
601 hmap_insert(&lldp->mappings_by_aux,
603 hash_pointer(m->aux, 0));
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);
611 ovs_mutex_unlock(&mutex);
617 aa_mapping_unregister_mapping(struct lldp *lldp,
618 struct lldpd_hardware *hw,
619 struct aa_mapping_internal *m)
621 struct lldpd_aa_isid_vlan_maps_tlv *lm, *lm_next;
623 LIST_FOR_EACH_SAFE (lm,
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);
630 if (isid == (uint32_t) m->isid) {
631 VLOG_INFO("\t\t Removing lport, isid=%u, vlan=%u",
633 lm->isid_vlan_data.vlan);
635 list_remove(&lm->m_entries);
637 /* TODO Should be done in the AA SM when a mapping goes
638 * from "pending" to "active".
641 struct bridge_aa_vlan *node = xmalloc(sizeof *node);
643 node->port_name = xstrdup(hw->h_ifname);
644 node->vlan = (uint32_t) m->vlan;
645 node->oper = BRIDGE_AA_VLAN_OPER_REMOVE;
647 list_push_back(&lldp->active_mapping_queue, &node->list_node);
655 /* Remove an existing Auto Attach mapping.
658 aa_mapping_unregister(void *aux)
662 VLOG_INFO("Removing mapping aux=%p", aux);
664 ovs_mutex_lock(&mutex);
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;
671 /* Remove from internal hash tables. */
673 struct aa_mapping_internal *p =
674 mapping_find_by_isid(lldp, m->isid);
678 VLOG_INFO("\t Removing mapping ISID=%ld, VLAN=%ld (lldp->name=%s)",
679 (long int) m->isid, (long int) m->vlan, lldp->name);
682 hmap_remove(&lldp->mappings_by_isid, &p->hmap_node_isid);
685 hmap_remove(&lldp->mappings_by_aux, &m->hmap_node_aux);
688 /* Remove from all the lldp instances */
689 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
691 VLOG_INFO("\t\t hardware->h_ifname=%s", hw->h_ifname);
694 aa_mapping_unregister_mapping(lldp, hw, m);
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);
709 ovs_mutex_unlock(&mutex);
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);
725 /* Returns true if 'lldp' should process packets from 'flow'. Sets
726 * fields in 'wc' that were used to make the determination.
729 lldp_should_process_flow(const struct flow *flow)
731 return (flow->dl_type == htons(ETH_TYPE_LLDP));
735 /* Process an LLDP packet that was received on a bridge port.
738 lldp_process_packet(struct lldp *lldp, const struct dp_packet *p)
741 lldpd_recv(lldp->lldpd,
742 (struct lldpd_hardware *)
743 lldp->lldpd->g_hardware.h_entries.next,
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.
753 lldp_should_send_packet(struct lldp *cfg) OVS_EXCLUDED(mutex)
757 ovs_mutex_lock(&mutex);
758 ret = timer_expired(&cfg->tx_timer);
759 ovs_mutex_unlock(&mutex);
764 /* Returns the next wake up time.
767 lldp_wake_time(const struct lldp *lldp) OVS_EXCLUDED(mutex)
769 long long int retval;
775 ovs_mutex_lock(&mutex);
776 retval = lldp->tx_timer.t;
777 ovs_mutex_unlock(&mutex);
782 /* Put the monitor thread to sleep until it's next wake time.
785 lldp_wait(struct lldp *lldp) OVS_EXCLUDED(mutex)
787 long long int wake_time = lldp_wake_time(lldp);
788 poll_timer_wait_until(wake_time);
792 /* Prepare the LLDP packet to be sent on a bridge port.
795 lldp_put_packet(struct lldp *lldp, struct dp_packet *packet,
796 uint8_t eth_src[ETH_ADDR_LEN]) OVS_EXCLUDED(mutex)
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};
805 ovs_mutex_lock(&mutex);
807 eth_compose(packet, eth_addr_lldp, eth_src, ETH_TYPE_LLDP, 0);
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;
814 timer_set_duration(&lldp->tx_timer, lldp->lldpd->g_config.c_tx_interval);
815 ovs_mutex_unlock(&mutex);
818 /* Configures the LLDP stack.
821 lldp_configure(struct lldp *lldp) OVS_EXCLUDED(mutex)
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);
835 /* Create an LLDP stack instance. At the moment there is one per bridge port.
838 lldp_create(const struct netdev *netdev,
840 const struct smap *cfg) OVS_EXCLUDED(mutex)
843 struct lldpd_chassis *lchassis;
844 struct lldpd_hardware *hw;
845 struct aa_mapping_internal *m;
847 if (!cfg || !smap_get_bool(cfg, "enable", false)) {
851 lldp = xzalloc(sizeof *lldp);
852 lldp->name = xstrdup(netdev_get_name(netdev));
853 lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
855 hmap_init(&lldp->mappings_by_isid);
856 hmap_init(&lldp->mappings_by_aux);
857 list_init(&lldp->active_mapping_queue);
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);
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);
875 if ((hw = lldpd_alloc_hardware(lldp->lldpd,
876 (char *) netdev_get_name(netdev),
878 VLOG_WARN("Unable to allocate space for %s",
879 (char *) netdev_get_name(netdev));
883 ovs_refcount_init(&lldp->ref_cnt);
885 hw->h_flags |= IFF_RUNNING;
888 hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
889 hw->h_lport.p_id = xstrdup(netdev_get_name(netdev));
891 /* p_id is not necessarily a null terminated string. */
892 hw->h_lport.p_id_len = strlen(netdev_get_name(netdev));
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;
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;
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);
910 ovs_mutex_lock(&mutex);
912 /* Update port with Auto Attach mappings configured. */
913 HMAP_FOR_EACH (m, hmap_node_isid, all_mappings) {
914 struct aa_mapping_internal *p;
916 if (mapping_find_by_isid(lldp, m->isid)) {
920 p = xmemdup(m, sizeof *p);
921 hmap_insert(&lldp->mappings_by_isid,
923 hash_bytes((const void *) &p->isid,
926 hmap_insert(&lldp->mappings_by_aux,
928 hash_pointer(p->aux, 0));
930 update_mapping_on_lldp(lldp, hw, p);
933 hmap_insert(all_lldps, &lldp->hmap_node,
934 hash_string(netdev_get_name(netdev), 0));
936 ovs_mutex_unlock(&mutex);
943 lldp_create_dummy(void)
946 struct lldpd_chassis *lchassis;
947 struct lldpd_hardware *hw;
949 lldp = xzalloc(sizeof *lldp);
950 lldp->name = "dummy-lldp";
951 lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
953 hmap_init(&lldp->mappings_by_isid);
954 hmap_init(&lldp->mappings_by_aux);
955 list_init(&lldp->active_mapping_queue);
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);
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);
970 if ((hw = lldpd_alloc_hardware(lldp->lldpd,
973 VLOG_WARN("Unable to allocate space for dummy-hw");
977 ovs_refcount_init(&lldp->ref_cnt);
979 hw->h_flags |= IFF_RUNNING;
982 hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
983 hw->h_lport.p_id = "dummy-port";
985 /* p_id is not necessarily a null terminated string. */
986 hw->h_lport.p_id_len = strlen(hw->h_lport.p_id);
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;
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);
1006 /* Unreference a specific LLDP instance.
1009 lldp_unref(struct lldp *lldp)
1015 ovs_mutex_lock(&mutex);
1016 if (ovs_refcount_unref_relaxed(&lldp->ref_cnt) != 1) {
1017 ovs_mutex_unlock(&mutex);
1021 hmap_remove(all_lldps, &lldp->hmap_node);
1022 ovs_mutex_unlock(&mutex);
1024 lldpd_cleanup(lldp->lldpd);
1030 /* Unreference a specific LLDP instance.
1033 lldp_ref(const struct lldp *lldp_)
1035 struct lldp *lldp = CONST_CAST(struct lldp *, lldp_);
1037 ovs_refcount_ref(&lldp->ref_cnt);