2 * Copyright (c) 2015 Nicira, Inc.
3 * Copyright (c) 2014 WindRiver, Inc.
4 * Copyright (c) 2015 Avaya, Inc.
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:
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 /* Implementation of Auto Attach.
20 * Based on sample implementation in 802.1ab. Above copyright and license
21 * applies to all modifications.
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
31 #include <arpa/inet.h>
33 #include <netinet/in.h>
36 #include <sys/types.h>
37 #include "dynamic-string.h"
40 #include "lldp/lldpd.h"
41 #include "lldp/lldpd-structs.h"
43 #include "openvswitch/types.h"
45 #include "poll-loop.h"
49 #include "openvswitch/vlog.h"
51 VLOG_DEFINE_THIS_MODULE(ovs_lldp);
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
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)
70 #define AA_STATUS(NAME, VALUE, STR) AA_STATUS_##NAME = VALUE,
76 /* Internal structure for an Auto Attach mapping.
78 struct aa_mapping_internal {
79 struct hmap_node hmap_node_isid;
80 struct hmap_node hmap_node_aux;
84 enum aa_status status;
87 static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
89 /* Hash map of all LLDP instances keyed by name (port at the moment).
91 static struct hmap all_lldps__ = HMAP_INITIALIZER(&all_lldps__);
92 static struct hmap *const all_lldps OVS_GUARDED_BY(mutex) = &all_lldps__;
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.
99 static struct hmap all_mappings__ = HMAP_INITIALIZER(&all_mappings__);
100 static struct hmap *const all_mappings OVS_GUARDED_BY(mutex) = &all_mappings__;
102 static struct lldp_aa_element_system_id system_id_null;
104 /* Convert an LLDP chassis ID to a string.
107 chassisid_to_string(uint8_t *array, size_t len, char **str)
111 *str = xmalloc(len * 3);
113 for (i = 0; i < len; i++) {
114 snprintf(&(*str)[i * 3], 4, "%02x:", array[i]);
116 (*str)[(i * 3) - 1] = '\0';
119 /* Find an Auto Attach mapping keyed by I-SID.
121 static struct aa_mapping_internal *
122 mapping_find_by_isid(struct lldp *lldp, uint32_t isid)
125 struct aa_mapping_internal *m;
127 HMAP_FOR_EACH_IN_BUCKET (m, hmap_node_isid, hash_int(isid, 0),
128 &lldp->mappings_by_isid) {
129 if (isid == m->isid) {
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.
140 static struct aa_mapping_internal *
141 mapping_find_by_aux(struct lldp *lldp, const void *aux) OVS_REQUIRES(mutex)
143 struct aa_mapping_internal *m;
145 HMAP_FOR_EACH_IN_BUCKET (m, hmap_node_aux, hash_pointer(aux, 0),
146 &lldp->mappings_by_aux) {
155 /* Convert an Auto Attach request status to a string.
158 aa_status_to_str(uint8_t status)
161 #define AA_STATUS(NAME, VALUE, STR) case AA_STATUS_##NAME: return #STR;
164 default: return "Undefined";
168 /* Display LLDP and Auto Attach statistics.
171 aa_print_lldp_and_aa_stats(struct ds *ds, struct lldp *lldp)
174 struct lldpd_hardware *hw;
176 ds_put_format(ds, "Statistics: %s\n", lldp->name);
182 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
183 ds_put_format(ds, "\ttx cnt: %"PRIu64"\n", hw->h_tx_cnt);
184 ds_put_format(ds, "\trx cnt: %"PRIu64"\n", hw->h_rx_cnt);
185 ds_put_format(ds, "\trx discarded cnt: %"PRIu64"\n",
186 hw->h_rx_discarded_cnt);
187 ds_put_format(ds, "\trx unrecognized cnt: %"PRIu64"\n",
188 hw->h_rx_unrecognized_cnt);
189 ds_put_format(ds, "\tageout cnt: %"PRIu64"\n", hw->h_ageout_cnt);
190 ds_put_format(ds, "\tinsert cnt: %"PRIu64"\n", hw->h_insert_cnt);
191 ds_put_format(ds, "\tdelete cnt: %"PRIu64"\n", hw->h_delete_cnt);
192 ds_put_format(ds, "\tdrop cnt: %"PRIu64"\n", hw->h_drop_cnt);
197 aa_print_element_status_port(struct ds *ds, struct lldpd_hardware *hw)
199 struct lldpd_port *port;
201 LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
202 if (memcmp(&port->p_element.system_id,
204 sizeof port->p_element.system_id)) {
205 static char *none_str = "<None>";
206 char *id = none_str, *descr = none_str, *system = none_str;
208 if (port->p_chassis) {
209 if (port->p_chassis->c_id_len > 0) {
210 chassisid_to_string(port->p_chassis->c_id,
211 port->p_chassis->c_id_len, &id);
214 descr = port->p_chassis->c_descr
215 ? port->p_chassis->c_descr : none_str;
218 chassisid_to_string((uint8_t *) &port->p_element.system_id,
219 sizeof port->p_element.system_id, &system);
222 "\tAuto Attach Primary Server Id: %s\n",
225 "\tAuto Attach Primary Server Descr: %s\n",
228 "\tAuto Attach Primary Server System Id: %s\n",
237 /* Auto Attach server broadcast an LLDP message periodically. Display
238 * the discovered server.
241 aa_print_element_status(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex)
243 struct lldpd_hardware *hw;
245 ds_put_format(ds, "LLDP: %s\n", lldp->name);
251 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
252 aa_print_element_status_port(ds, hw);
257 aa_print_isid_status_port_isid(struct lldp *lldp, struct lldpd_port *port)
260 struct lldpd_aa_isid_vlan_maps_tlv *mapping;
262 if (list_is_empty(&port->p_isid_vlan_maps)) {
266 LIST_FOR_EACH (mapping, m_entries, &port->p_isid_vlan_maps) {
267 uint32_t isid = mapping->isid_vlan_data.isid;
268 struct aa_mapping_internal *m = mapping_find_by_isid(lldp, isid);
270 VLOG_INFO("h_rport: isid=%u, vlan=%u, status=%d",
272 mapping->isid_vlan_data.vlan,
273 mapping->isid_vlan_data.status);
275 /* Update the status of our internal state for the mapping. */
277 VLOG_INFO("Setting status for ISID=%"PRIu32" to %"PRIu16,
278 isid, mapping->isid_vlan_data.status);
279 m->status = mapping->isid_vlan_data.status;
281 VLOG_WARN("Couldn't find mapping for I-SID=%"PRIu32, isid);
287 aa_print_isid_status_port(struct lldp *lldp, struct lldpd_hardware *hw)
290 struct lldpd_port *port;
292 LIST_FOR_EACH (port, p_entries, &hw->h_rports) {
293 aa_print_isid_status_port_isid(lldp, port);
297 /* The Auto Attach server will broadcast the status of the configured mappings
298 * via LLDP. Display the status.
301 aa_print_isid_status(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex)
303 struct lldpd_hardware *hw;
304 struct aa_mapping_internal *m;
310 ds_put_format(ds, "LLDP: %s\n", lldp->name);
312 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
313 aa_print_isid_status_port(lldp, hw);
316 ds_put_format(ds, "%-8s %-4s %-11s %-8s\n",
321 ds_put_format(ds, "-------- ---- ----------- --------\n");
323 HMAP_FOR_EACH (m, hmap_node_isid, &lldp->mappings_by_isid) {
324 ds_put_format(ds, "%-8"PRIu32" %-4"PRIu16" %-11s %-11s\n",
325 m->isid, m->vlan, "Switch", aa_status_to_str(m->status));
330 aa_unixctl_status(struct unixctl_conn *conn, int argc OVS_UNUSED,
331 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
335 struct ds ds = DS_EMPTY_INITIALIZER;
337 ovs_mutex_lock(&mutex);
339 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
340 aa_print_element_status(&ds, lldp);
342 unixctl_command_reply(conn, ds_cstr(&ds));
345 ovs_mutex_unlock(&mutex);
349 aa_unixctl_show_isid(struct unixctl_conn *conn, int argc OVS_UNUSED,
350 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
354 struct ds ds = DS_EMPTY_INITIALIZER;
356 ovs_mutex_lock(&mutex);
358 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
359 aa_print_isid_status(&ds, lldp);
361 unixctl_command_reply(conn, ds_cstr(&ds));
364 ovs_mutex_unlock(&mutex);
368 aa_unixctl_statistics(struct unixctl_conn *conn, int argc OVS_UNUSED,
369 const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
372 struct ds ds = DS_EMPTY_INITIALIZER;
375 ovs_mutex_lock(&mutex);
377 /* Cycle through all ports and dump the stats for each one */
378 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
379 aa_print_lldp_and_aa_stats(&ds, lldp);
382 ovs_mutex_unlock(&mutex);
384 unixctl_command_reply(conn, ds_cstr(&ds));
387 /* An Auto Attach mapping was configured. Populate the corresponding
388 * structures in the LLDP hardware.
391 update_mapping_on_lldp(struct lldp *lldp, struct lldpd_hardware *hardware,
392 struct aa_mapping_internal *m)
394 struct lldpd_aa_isid_vlan_maps_tlv *lm = xzalloc(sizeof *lm);
396 if (hardware->h_ifname) {
397 VLOG_INFO("\t\t hardware->h_ifname=%s", hardware->h_ifname);
400 lm->isid_vlan_data.isid = m->isid;
401 lm->isid_vlan_data.vlan = m->vlan;
403 list_push_back(&hardware->h_lport.p_isid_vlan_maps, &lm->m_entries);
405 /* TODO Should be done in the Auto Attach state machine when a mapping goes
406 * from "pending" to "active".
409 struct bridge_aa_vlan *node = xmalloc(sizeof *node);
411 node->port_name = xstrdup(hardware->h_ifname);
412 node->vlan = m->vlan;
413 node->oper = BRIDGE_AA_VLAN_OPER_ADD;
415 list_push_back(&lldp->active_mapping_queue, &node->list_node);
419 /* Bridge will poll the list of VLAN that needs to be auto configure based on
420 * the Auto Attach mappings that have been exchanged with the server.
423 aa_get_vlan_queued(struct ovs_list *list)
427 ovs_mutex_lock(&mutex);
429 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
430 struct bridge_aa_vlan *node, *node_next;
432 LIST_FOR_EACH_SAFE (node,
435 &lldp->active_mapping_queue) {
436 struct bridge_aa_vlan *copy;
438 copy = xmalloc(sizeof *copy);
439 copy->port_name = xstrdup(node->port_name);
440 copy->vlan = node->vlan;
441 copy->oper = node->oper;
443 list_push_back(list, ©->list_node);
446 list_remove(&node->list_node);
447 free(node->port_name);
452 ovs_mutex_unlock(&mutex);
457 /* Bridge will poll whether or not VLAN have been auto-configured.
460 aa_get_vlan_queue_size(void)
463 unsigned int size = 0;
465 ovs_mutex_lock(&mutex);
467 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
468 size += list_size(&lldp->active_mapping_queue);
471 ovs_mutex_unlock(&mutex);
476 /* Configure Auto Attach.
479 aa_configure(const struct aa_settings *s)
483 ovs_mutex_lock(&mutex);
485 /* TODO Change all instances for now */
486 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
487 struct lldpd_chassis *chassis;
489 LIST_FOR_EACH (chassis, list, &lldp->lldpd->g_chassis.list) {
490 /* System Description */
491 if (chassis->c_descr) {
492 free(chassis->c_descr);
494 chassis->c_descr = s->system_description[0] ?
495 xstrdup(s->system_description) : xstrdup(PACKAGE_STRING);
498 if (chassis->c_name) {
499 free(chassis->c_name);
501 chassis->c_name = xstrdup(s->system_name);
505 ovs_mutex_unlock(&mutex);
510 /* Add a new Auto Attach mapping.
513 aa_mapping_register(void *aux, const struct aa_mapping_settings *s)
515 struct aa_mapping_internal *bridge_m;
518 VLOG_INFO("Adding mapping ISID=%"PRIu32", VLAN=%"PRIu16", aux=%p",
519 s->isid, s->vlan, aux);
521 ovs_mutex_lock(&mutex);
523 /* TODO These mappings should be stores per bridge. This is used
524 * When a port is added. Auto Attach mappings need to be added on this
527 bridge_m = xzalloc(sizeof *bridge_m);
528 bridge_m->isid = s->isid;
529 bridge_m->vlan = s->vlan;
531 bridge_m->status = AA_STATUS_PENDING;
532 hmap_insert(all_mappings, &bridge_m->hmap_node_isid,
533 hash_int(bridge_m->isid, 0));
536 /* Update mapping on the all the LLDP instances. */
537 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
538 struct lldpd_hardware *hw;
539 struct aa_mapping_internal *m;
541 VLOG_INFO("\t lldp->name=%s", lldp->name);
543 if (mapping_find_by_isid(lldp, s->isid)) {
547 m = xzalloc(sizeof *m);
550 m->status = AA_STATUS_PENDING;
552 hmap_insert(&lldp->mappings_by_isid, &m->hmap_node_isid,
553 hash_int(m->isid, 0));
554 hmap_insert(&lldp->mappings_by_aux,
556 hash_pointer(m->aux, 0));
558 /* Configure the mapping on each port of the LLDP stack. */
559 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
560 update_mapping_on_lldp(lldp, hw, m);
564 ovs_mutex_unlock(&mutex);
570 aa_mapping_unregister_mapping(struct lldp *lldp,
571 struct lldpd_hardware *hw,
572 struct aa_mapping_internal *m)
574 struct lldpd_aa_isid_vlan_maps_tlv *lm, *lm_next;
576 LIST_FOR_EACH_SAFE (lm, lm_next, m_entries,
577 &hw->h_lport.p_isid_vlan_maps) {
578 uint32_t isid = lm->isid_vlan_data.isid;
580 if (isid == m->isid) {
581 VLOG_INFO("\t\t Removing lport, isid=%u, vlan=%u",
583 lm->isid_vlan_data.vlan);
585 list_remove(&lm->m_entries);
587 /* TODO Should be done in the AA SM when a mapping goes
588 * from "pending" to "active".
591 struct bridge_aa_vlan *node = xmalloc(sizeof *node);
593 node->port_name = xstrdup(hw->h_ifname);
594 node->vlan = (uint32_t) m->vlan;
595 node->oper = BRIDGE_AA_VLAN_OPER_REMOVE;
597 list_push_back(&lldp->active_mapping_queue, &node->list_node);
605 /* Remove an existing Auto Attach mapping.
608 aa_mapping_unregister(void *aux)
612 VLOG_INFO("Removing mapping aux=%p", aux);
614 ovs_mutex_lock(&mutex);
616 HMAP_FOR_EACH (lldp, hmap_node, all_lldps) {
617 struct lldpd_hardware *hw;
618 struct aa_mapping_internal *m = mapping_find_by_aux(lldp, aux);
620 /* Remove from internal hash tables. */
622 uint32_t isid = m->isid;
623 uint16_t vlan = m->vlan;
624 struct aa_mapping_internal *p = mapping_find_by_isid(lldp, isid);
626 VLOG_INFO("\t Removing mapping ISID=%"PRIu32", VLAN=%"PRIu16
627 " (lldp->name=%s)", isid, vlan, lldp->name);
630 hmap_remove(&lldp->mappings_by_isid, &p->hmap_node_isid);
633 hmap_remove(&lldp->mappings_by_aux, &m->hmap_node_aux);
636 /* Remove from all the lldp instances */
637 LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware.h_entries) {
639 VLOG_INFO("\t\t hardware->h_ifname=%s", hw->h_ifname);
642 aa_mapping_unregister_mapping(lldp, hw, m);
645 /* Remove from the all_mappings */
646 HMAP_FOR_EACH (m, hmap_node_isid, all_mappings) {
647 if (m && isid == m->isid && vlan == m->vlan) {
648 hmap_remove(all_mappings, &m->hmap_node_isid);
655 ovs_mutex_unlock(&mutex);
663 unixctl_command_register("autoattach/status", "[bridge]", 0, 1,
664 aa_unixctl_status, NULL);
665 unixctl_command_register("autoattach/show-isid", "[bridge]", 0, 1,
666 aa_unixctl_show_isid, NULL);
667 unixctl_command_register("autoattach/statistics", "[bridge]", 0, 1,
668 aa_unixctl_statistics, NULL);
671 /* Returns true if 'lldp' should process packets from 'flow'. Sets
672 * fields in 'wc' that were used to make the determination.
675 lldp_should_process_flow(const struct flow *flow)
677 return (flow->dl_type == htons(ETH_TYPE_LLDP));
681 /* Process an LLDP packet that was received on a bridge port.
684 lldp_process_packet(struct lldp *lldp, const struct dp_packet *p)
687 lldpd_recv(lldp->lldpd,
688 (struct lldpd_hardware *)
689 lldp->lldpd->g_hardware.h_entries.next,
695 /* This code is called periodically to check if the LLDP module has an LLDP
696 * message it wishes to send. It is called several times every second.
699 lldp_should_send_packet(struct lldp *cfg) OVS_EXCLUDED(mutex)
703 ovs_mutex_lock(&mutex);
704 ret = timer_expired(&cfg->tx_timer);
705 ovs_mutex_unlock(&mutex);
710 /* Returns the next wake up time.
713 lldp_wake_time(const struct lldp *lldp) OVS_EXCLUDED(mutex)
715 long long int retval;
721 ovs_mutex_lock(&mutex);
722 retval = lldp->tx_timer.t;
723 ovs_mutex_unlock(&mutex);
728 /* Put the monitor thread to sleep until it's next wake time.
731 lldp_wait(struct lldp *lldp) OVS_EXCLUDED(mutex)
733 long long int wake_time = lldp_wake_time(lldp);
734 poll_timer_wait_until(wake_time);
738 /* Prepare the LLDP packet to be sent on a bridge port.
741 lldp_put_packet(struct lldp *lldp, struct dp_packet *packet,
742 uint8_t eth_src[ETH_ADDR_LEN]) OVS_EXCLUDED(mutex)
744 struct lldpd *mylldpd = lldp->lldpd;
745 struct lldpd_hardware *hw = (struct lldpd_hardware *)
746 mylldpd->g_hardware.h_entries.next;
747 uint32_t lldp_size = 0;
748 static const uint8_t eth_addr_lldp[6] =
749 {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
751 ovs_mutex_lock(&mutex);
753 eth_compose(packet, eth_addr_lldp, eth_src, ETH_TYPE_LLDP, 0);
755 lldp_size = lldpd_send(hw, packet);
756 if (lldp_size + ETH_HEADER_LEN < MINIMUM_ETH_PACKET_SIZE) {
757 lldp_size = MINIMUM_ETH_PACKET_SIZE;
760 timer_set_duration(&lldp->tx_timer, lldp->lldpd->g_config.c_tx_interval);
761 ovs_mutex_unlock(&mutex);
764 /* Configures the LLDP stack.
767 lldp_configure(struct lldp *lldp) OVS_EXCLUDED(mutex)
770 ovs_mutex_lock(&mutex);
771 timer_set_expired(&lldp->tx_timer);
772 timer_set_duration(&lldp->tx_timer, LLDP_DEFAULT_TRANSMIT_INTERVAL_MS);
773 lldp->lldpd->g_config.c_tx_interval =
774 LLDP_DEFAULT_TRANSMIT_INTERVAL_MS;
775 ovs_mutex_unlock(&mutex);
781 /* Create an LLDP stack instance. At the moment there is one per bridge port.
784 lldp_create(const struct netdev *netdev,
786 const struct smap *cfg) OVS_EXCLUDED(mutex)
789 struct lldpd_chassis *lchassis;
790 struct lldpd_hardware *hw;
791 struct aa_mapping_internal *m;
793 if (!cfg || !smap_get_bool(cfg, "enable", false)) {
797 lldp = xzalloc(sizeof *lldp);
798 lldp->name = xstrdup(netdev_get_name(netdev));
799 lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
801 hmap_init(&lldp->mappings_by_isid);
802 hmap_init(&lldp->mappings_by_aux);
803 list_init(&lldp->active_mapping_queue);
805 lchassis = xzalloc(sizeof *lchassis);
806 lchassis->c_cap_available = LLDP_CAP_BRIDGE;
807 lchassis->c_cap_enabled = LLDP_CAP_BRIDGE;
808 lchassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
809 lchassis->c_id_len = ETH_ADDR_LEN;
810 lchassis->c_id = xmalloc(ETH_ADDR_LEN);
811 netdev_get_etheraddr(netdev, lchassis->c_id);
813 list_init(&lchassis->c_mgmt);
814 lchassis->c_ttl = lldp->lldpd->g_config.c_tx_interval *
815 lldp->lldpd->g_config.c_tx_hold;
816 lchassis->c_ttl = LLDP_CHASSIS_TTL;
817 lldpd_assign_cfg_to_protocols(lldp->lldpd);
818 list_init(&lldp->lldpd->g_chassis.list);
819 list_push_back(&lldp->lldpd->g_chassis.list, &lchassis->list);
821 if ((hw = lldpd_alloc_hardware(lldp->lldpd,
822 (char *) netdev_get_name(netdev),
824 VLOG_WARN("Unable to allocate space for %s",
825 (char *) netdev_get_name(netdev));
829 ovs_refcount_init(&lldp->ref_cnt);
831 hw->h_flags |= IFF_RUNNING;
834 hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
835 hw->h_lport.p_id = xstrdup(netdev_get_name(netdev));
837 /* p_id is not necessarily a null terminated string. */
838 hw->h_lport.p_id_len = strlen(netdev_get_name(netdev));
840 /* Auto Attach element tlv */
841 hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
842 hw->h_lport.p_element.mgmt_vlan = 0;
843 memcpy(&hw->h_lport.p_element.system_id.system_mac,
844 lchassis->c_id, lchassis->c_id_len);
845 hw->h_lport.p_element.system_id.conn_type =
846 LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
848 hw->h_lport.p_element.system_id.smlt_id = 0;
849 hw->h_lport.p_element.system_id.mlt_id[0] = 0;
850 hw->h_lport.p_element.system_id.mlt_id[1] = 0;
852 list_init(&hw->h_lport.p_isid_vlan_maps);
853 list_init(&lldp->lldpd->g_hardware.h_entries);
854 list_push_back(&lldp->lldpd->g_hardware.h_entries, &hw->h_entries);
856 ovs_mutex_lock(&mutex);
858 /* Update port with Auto Attach mappings configured. */
859 HMAP_FOR_EACH (m, hmap_node_isid, all_mappings) {
860 struct aa_mapping_internal *p;
862 if (mapping_find_by_isid(lldp, m->isid)) {
866 p = xmemdup(m, sizeof *p);
867 hmap_insert(&lldp->mappings_by_isid, &p->hmap_node_isid,
868 hash_int(p->isid, 0));
869 hmap_insert(&lldp->mappings_by_aux,
871 hash_pointer(p->aux, 0));
873 update_mapping_on_lldp(lldp, hw, p);
876 hmap_insert(all_lldps, &lldp->hmap_node,
877 hash_string(netdev_get_name(netdev), 0));
879 ovs_mutex_unlock(&mutex);
886 lldp_create_dummy(void)
889 struct lldpd_chassis *lchassis;
890 struct lldpd_hardware *hw;
892 lldp = xzalloc(sizeof *lldp);
893 lldp->name = "dummy-lldp";
894 lldp->lldpd = xzalloc(sizeof *lldp->lldpd);
896 hmap_init(&lldp->mappings_by_isid);
897 hmap_init(&lldp->mappings_by_aux);
898 list_init(&lldp->active_mapping_queue);
900 lchassis = xzalloc(sizeof *lchassis);
901 lchassis->c_cap_available = LLDP_CAP_BRIDGE;
902 lchassis->c_cap_enabled = LLDP_CAP_BRIDGE;
903 lchassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
904 lchassis->c_id_len = ETH_ADDR_LEN;
905 lchassis->c_id = xmalloc(ETH_ADDR_LEN);
907 list_init(&lchassis->c_mgmt);
908 lchassis->c_ttl = LLDP_CHASSIS_TTL;
909 lldpd_assign_cfg_to_protocols(lldp->lldpd);
910 list_init(&lldp->lldpd->g_chassis.list);
911 list_push_back(&lldp->lldpd->g_chassis.list, &lchassis->list);
913 hw = lldpd_alloc_hardware(lldp->lldpd, "dummy-hw", 0);
915 ovs_refcount_init(&lldp->ref_cnt);
917 hw->h_flags |= IFF_RUNNING;
920 hw->h_lport.p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
921 hw->h_lport.p_id = "dummy-port";
923 /* p_id is not necessarily a null terminated string. */
924 hw->h_lport.p_id_len = strlen(hw->h_lport.p_id);
926 /* Auto Attach element tlv */
927 hw->h_lport.p_element.type = LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT;
928 hw->h_lport.p_element.mgmt_vlan = 0;
929 memcpy(&hw->h_lport.p_element.system_id.system_mac,
930 lchassis->c_id, lchassis->c_id_len);
931 hw->h_lport.p_element.system_id.conn_type =
932 LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE;
933 hw->h_lport.p_element.system_id.smlt_id = 0;
934 hw->h_lport.p_element.system_id.mlt_id[0] = 0;
935 hw->h_lport.p_element.system_id.mlt_id[1] = 0;
937 list_init(&hw->h_lport.p_isid_vlan_maps);
938 list_init(&lldp->lldpd->g_hardware.h_entries);
939 list_push_back(&lldp->lldpd->g_hardware.h_entries, &hw->h_entries);
944 /* Unreference a specific LLDP instance.
947 lldp_unref(struct lldp *lldp)
953 ovs_mutex_lock(&mutex);
954 if (ovs_refcount_unref_relaxed(&lldp->ref_cnt) != 1) {
955 ovs_mutex_unlock(&mutex);
959 hmap_remove(all_lldps, &lldp->hmap_node);
960 ovs_mutex_unlock(&mutex);
962 lldpd_cleanup(lldp->lldpd);
968 /* Unreference a specific LLDP instance.
971 lldp_ref(const struct lldp *lldp_)
973 struct lldp *lldp = CONST_CAST(struct lldp *, lldp_);
975 ovs_refcount_ref(&lldp->ref_cnt);