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
) {
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 const char *none_str
= "<None>";
206 const char *descr
= NULL
;
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
);
216 descr
= port
->p_chassis
->c_descr
;
219 chassisid_to_string((uint8_t *) &port
->p_element
.system_id
,
220 sizeof port
->p_element
.system_id
, &system
);
222 ds_put_format(ds
, "\tAuto Attach Primary Server Id: %s\n",
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",
235 /* Auto Attach server broadcast an LLDP message periodically. Display
236 * the discovered server.
239 aa_print_element_status(struct ds
*ds
, struct lldp
*lldp
) OVS_REQUIRES(mutex
)
241 struct lldpd_hardware
*hw
;
243 ds_put_format(ds
, "LLDP: %s\n", lldp
->name
);
249 LIST_FOR_EACH (hw
, h_entries
, &lldp
->lldpd
->g_hardware
) {
250 aa_print_element_status_port(ds
, hw
);
255 aa_print_isid_status_port_isid(struct lldp
*lldp
, struct lldpd_port
*port
)
258 struct lldpd_aa_isid_vlan_maps_tlv
*mapping
;
260 if (list_is_empty(&port
->p_isid_vlan_maps
)) {
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
);
268 VLOG_INFO("h_rport: isid=%u, vlan=%u, status=%d",
270 mapping
->isid_vlan_data
.vlan
,
271 mapping
->isid_vlan_data
.status
);
273 /* Update the status of our internal state for the mapping. */
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
;
279 VLOG_WARN("Couldn't find mapping for I-SID=%"PRIu32
, isid
);
285 aa_print_isid_status_port(struct lldp
*lldp
, struct lldpd_hardware
*hw
)
288 struct lldpd_port
*port
;
290 LIST_FOR_EACH (port
, p_entries
, &hw
->h_rports
) {
291 aa_print_isid_status_port_isid(lldp
, port
);
295 /* The Auto Attach server will broadcast the status of the configured mappings
296 * via LLDP. Display the status.
299 aa_print_isid_status(struct ds
*ds
, struct lldp
*lldp
) OVS_REQUIRES(mutex
)
301 struct lldpd_hardware
*hw
;
302 struct aa_mapping_internal
*m
;
308 ds_put_format(ds
, "LLDP: %s\n", lldp
->name
);
310 LIST_FOR_EACH (hw
, h_entries
, &lldp
->lldpd
->g_hardware
) {
311 aa_print_isid_status_port(lldp
, hw
);
314 ds_put_format(ds
, "%-8s %-4s %-11s %-8s\n",
319 ds_put_format(ds
, "-------- ---- ----------- --------\n");
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
));
328 aa_unixctl_status(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
329 const char *argv
[] OVS_UNUSED
, void *aux OVS_UNUSED
)
333 struct ds ds
= DS_EMPTY_INITIALIZER
;
335 ovs_mutex_lock(&mutex
);
337 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
338 aa_print_element_status(&ds
, lldp
);
340 unixctl_command_reply(conn
, ds_cstr(&ds
));
343 ovs_mutex_unlock(&mutex
);
347 aa_unixctl_show_isid(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
348 const char *argv
[] OVS_UNUSED
, void *aux OVS_UNUSED
)
352 struct ds ds
= DS_EMPTY_INITIALIZER
;
354 ovs_mutex_lock(&mutex
);
356 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
357 aa_print_isid_status(&ds
, lldp
);
359 unixctl_command_reply(conn
, ds_cstr(&ds
));
362 ovs_mutex_unlock(&mutex
);
366 aa_unixctl_statistics(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
367 const char *argv
[] OVS_UNUSED
, void *aux OVS_UNUSED
)
370 struct ds ds
= DS_EMPTY_INITIALIZER
;
373 ovs_mutex_lock(&mutex
);
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
);
380 ovs_mutex_unlock(&mutex
);
382 unixctl_command_reply(conn
, ds_cstr(&ds
));
385 /* An Auto Attach mapping was configured. Populate the corresponding
386 * structures in the LLDP hardware.
389 update_mapping_on_lldp(struct lldp
*lldp
, struct lldpd_hardware
*hardware
,
390 struct aa_mapping_internal
*m
)
392 struct lldpd_aa_isid_vlan_maps_tlv
*lm
= xzalloc(sizeof *lm
);
394 if (hardware
->h_ifname
) {
395 VLOG_INFO("\t\t hardware->h_ifname=%s", hardware
->h_ifname
);
398 lm
->isid_vlan_data
.isid
= m
->isid
;
399 lm
->isid_vlan_data
.vlan
= m
->vlan
;
401 list_push_back(&hardware
->h_lport
.p_isid_vlan_maps
, &lm
->m_entries
);
403 /* TODO Should be done in the Auto Attach state machine when a mapping goes
404 * from "pending" to "active".
406 struct bridge_aa_vlan
*node
= xmalloc(sizeof *node
);
408 node
->port_name
= xstrdup(hardware
->h_ifname
);
409 node
->vlan
= m
->vlan
;
410 node
->oper
= BRIDGE_AA_VLAN_OPER_ADD
;
412 list_push_back(&lldp
->active_mapping_queue
, &node
->list_node
);
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.
419 aa_get_vlan_queued(struct ovs_list
*list
)
423 ovs_mutex_lock(&mutex
);
425 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
426 struct bridge_aa_vlan
*node
;
428 LIST_FOR_EACH_POP (node
, list_node
, &lldp
->active_mapping_queue
) {
429 struct bridge_aa_vlan
*copy
;
431 copy
= xmalloc(sizeof *copy
);
432 copy
->port_name
= xstrdup(node
->port_name
);
433 copy
->vlan
= node
->vlan
;
434 copy
->oper
= node
->oper
;
436 list_push_back(list
, ©
->list_node
);
439 free(node
->port_name
);
444 ovs_mutex_unlock(&mutex
);
449 /* Bridge will poll whether or not VLAN have been auto-configured.
452 aa_get_vlan_queue_size(void)
455 unsigned int size
= 0;
457 ovs_mutex_lock(&mutex
);
459 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
460 size
+= list_size(&lldp
->active_mapping_queue
);
463 ovs_mutex_unlock(&mutex
);
468 /* Configure Auto Attach.
471 aa_configure(const struct aa_settings
*s
)
475 ovs_mutex_lock(&mutex
);
477 /* TODO Change all instances for now */
478 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
479 struct lldpd_chassis
*chassis
;
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
);
489 free(chassis
->c_name
);
490 chassis
->c_name
= xstrdup(s
->system_name
);
495 ovs_mutex_unlock(&mutex
);
500 /* Add a new Auto Attach mapping.
503 aa_mapping_register(void *aux
, const struct aa_mapping_settings
*s
)
505 struct aa_mapping_internal
*bridge_m
;
508 VLOG_INFO("Adding mapping ISID=%"PRIu32
", VLAN=%"PRIu16
", aux=%p",
509 s
->isid
, s
->vlan
, aux
);
511 ovs_mutex_lock(&mutex
);
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
517 bridge_m
= xzalloc(sizeof *bridge_m
);
518 bridge_m
->isid
= s
->isid
;
519 bridge_m
->vlan
= s
->vlan
;
521 bridge_m
->status
= AA_STATUS_PENDING
;
522 hmap_insert(all_mappings
, &bridge_m
->hmap_node_isid
,
523 hash_int(bridge_m
->isid
, 0));
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
;
531 VLOG_INFO("\t lldp->name=%s", lldp
->name
);
533 if (mapping_find_by_isid(lldp
, s
->isid
)) {
537 m
= xzalloc(sizeof *m
);
540 m
->status
= AA_STATUS_PENDING
;
542 hmap_insert(&lldp
->mappings_by_isid
, &m
->hmap_node_isid
,
543 hash_int(m
->isid
, 0));
544 hmap_insert(&lldp
->mappings_by_aux
,
546 hash_pointer(m
->aux
, 0));
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
);
554 ovs_mutex_unlock(&mutex
);
560 aa_mapping_unregister_mapping(struct lldp
*lldp
,
561 struct lldpd_hardware
*hw
,
562 struct aa_mapping_internal
*m
)
564 struct lldpd_aa_isid_vlan_maps_tlv
*lm
, *lm_next
;
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
;
570 if (isid
== m
->isid
) {
571 VLOG_INFO("\t\t Removing lport, isid=%u, vlan=%u",
573 lm
->isid_vlan_data
.vlan
);
575 list_remove(&lm
->m_entries
);
577 /* TODO Should be done in the AA SM when a mapping goes
578 * from "pending" to "active".
580 struct bridge_aa_vlan
*node
= xmalloc(sizeof *node
);
582 node
->port_name
= xstrdup(hw
->h_ifname
);
583 node
->vlan
= m
->vlan
;
584 node
->oper
= BRIDGE_AA_VLAN_OPER_REMOVE
;
586 list_push_back(&lldp
->active_mapping_queue
, &node
->list_node
);
593 /* Remove an existing Auto Attach mapping.
596 aa_mapping_unregister(void *aux
)
600 VLOG_INFO("Removing mapping aux=%p", aux
);
602 ovs_mutex_lock(&mutex
);
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
);
608 /* Remove from internal hash tables. */
610 uint32_t isid
= m
->isid
;
611 uint16_t vlan
= m
->vlan
;
612 struct aa_mapping_internal
*p
= mapping_find_by_isid(lldp
, isid
);
614 VLOG_INFO("\t Removing mapping ISID=%"PRIu32
", VLAN=%"PRIu16
615 " (lldp->name=%s)", isid
, vlan
, lldp
->name
);
618 hmap_remove(&lldp
->mappings_by_isid
, &p
->hmap_node_isid
);
621 hmap_remove(&lldp
->mappings_by_aux
, &m
->hmap_node_aux
);
623 /* Remove from all the lldp instances */
624 LIST_FOR_EACH (hw
, h_entries
, &lldp
->lldpd
->g_hardware
) {
626 VLOG_INFO("\t\t hardware->h_ifname=%s", hw
->h_ifname
);
629 aa_mapping_unregister_mapping(lldp
, hw
, m
);
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
);
643 ovs_mutex_unlock(&mutex
);
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
);
659 /* Returns true if 'lldp' should process packets from 'flow'. Sets
660 * fields in 'wc' that were used to make the determination.
663 lldp_should_process_flow(struct lldp
*lldp
, const struct flow
*flow
)
665 return (flow
->dl_type
== htons(ETH_TYPE_LLDP
) && lldp
->enabled
);
669 /* Process an LLDP packet that was received on a bridge port.
672 lldp_process_packet(struct lldp
*lldp
, const struct dp_packet
*p
)
675 lldpd_recv(lldp
->lldpd
, lldpd_first_hardware(lldp
->lldpd
),
676 (char *) dp_packet_data(p
), dp_packet_size(p
));
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.
684 lldp_should_send_packet(struct lldp
*cfg
) OVS_EXCLUDED(mutex
)
688 ovs_mutex_lock(&mutex
);
689 ret
= timer_expired(&cfg
->tx_timer
);
690 ovs_mutex_unlock(&mutex
);
692 /* LLDP must be enabled */
698 /* Returns the next wake up time.
701 lldp_wake_time(const struct lldp
*lldp
) OVS_EXCLUDED(mutex
)
703 long long int retval
;
705 if (!lldp
|| !lldp
->enabled
) {
709 ovs_mutex_lock(&mutex
);
710 retval
= lldp
->tx_timer
.t
;
711 ovs_mutex_unlock(&mutex
);
716 /* Put the monitor thread to sleep until it's next wake time.
719 lldp_wait(struct lldp
*lldp
) OVS_EXCLUDED(mutex
)
721 long long int wake_time
= lldp_wake_time(lldp
);
722 poll_timer_wait_until(wake_time
);
726 /* Prepare the LLDP packet to be sent on a bridge port.
729 lldp_put_packet(struct lldp
*lldp
, struct dp_packet
*packet
,
730 uint8_t eth_src
[ETH_ADDR_LEN
]) OVS_EXCLUDED(mutex
)
732 struct lldpd
*mylldpd
= lldp
->lldpd
;
733 struct lldpd_hardware
*hw
= lldpd_first_hardware(mylldpd
);
734 static const uint8_t eth_addr_lldp
[6] =
735 {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
737 ovs_mutex_lock(&mutex
);
739 eth_compose(packet
, eth_addr_lldp
, eth_src
, ETH_TYPE_LLDP
, 0);
741 lldpd_send(hw
, packet
);
743 timer_set_duration(&lldp
->tx_timer
, lldp
->lldpd
->g_config
.c_tx_interval
);
744 ovs_mutex_unlock(&mutex
);
747 /* Configures the LLDP stack.
750 lldp_configure(struct lldp
*lldp
, const struct smap
*cfg
) OVS_EXCLUDED(mutex
)
753 if (cfg
&& smap_get_bool(cfg
, "enable", false)) {
754 lldp
->enabled
= true;
756 lldp
->enabled
= false;
759 ovs_mutex_lock(&mutex
);
760 timer_set_expired(&lldp
->tx_timer
);
761 timer_set_duration(&lldp
->tx_timer
, LLDP_DEFAULT_TRANSMIT_INTERVAL_MS
);
762 lldp
->lldpd
->g_config
.c_tx_interval
=
763 LLDP_DEFAULT_TRANSMIT_INTERVAL_MS
;
764 ovs_mutex_unlock(&mutex
);
770 /* Create an LLDP stack instance. At the moment there is one per bridge port.
773 lldp_create(const struct netdev
*netdev
,
775 const struct smap
*cfg
) OVS_EXCLUDED(mutex
)
778 struct lldpd_chassis
*lchassis
;
779 struct lldpd_hardware
*hw
;
780 struct aa_mapping_internal
*m
;
782 if (!cfg
|| !smap_get_bool(cfg
, "enable", false)) {
786 lldp
= xzalloc(sizeof *lldp
);
787 lldp
->name
= xstrdup(netdev_get_name(netdev
));
788 lldp
->lldpd
= xzalloc(sizeof *lldp
->lldpd
);
790 hmap_init(&lldp
->mappings_by_isid
);
791 hmap_init(&lldp
->mappings_by_aux
);
792 list_init(&lldp
->active_mapping_queue
);
794 lchassis
= xzalloc(sizeof *lchassis
);
795 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
;
796 lchassis
->c_cap_enabled
= LLDP_CAP_BRIDGE
;
797 lchassis
->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
798 lchassis
->c_id_len
= ETH_ADDR_LEN
;
799 lchassis
->c_id
= xmalloc(ETH_ADDR_LEN
);
800 netdev_get_etheraddr(netdev
, lchassis
->c_id
);
802 list_init(&lchassis
->c_mgmt
);
803 lchassis
->c_ttl
= lldp
->lldpd
->g_config
.c_tx_interval
*
804 lldp
->lldpd
->g_config
.c_tx_hold
;
805 lchassis
->c_ttl
= LLDP_CHASSIS_TTL
;
806 lldpd_assign_cfg_to_protocols(lldp
->lldpd
);
807 list_init(&lldp
->lldpd
->g_chassis
);
808 list_push_back(&lldp
->lldpd
->g_chassis
, &lchassis
->list
);
810 if ((hw
= lldpd_alloc_hardware(lldp
->lldpd
,
811 (char *) netdev_get_name(netdev
),
813 VLOG_WARN("Unable to allocate space for %s",
814 (char *) netdev_get_name(netdev
));
818 ovs_refcount_init(&lldp
->ref_cnt
);
820 hw
->h_flags
|= IFF_RUNNING
;
823 hw
->h_lport
.p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
824 hw
->h_lport
.p_id
= xstrdup(netdev_get_name(netdev
));
826 /* p_id is not necessarily a null terminated string. */
827 hw
->h_lport
.p_id_len
= strlen(netdev_get_name(netdev
));
829 /* Auto Attach element tlv */
830 hw
->h_lport
.p_element
.type
= LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH
;
831 hw
->h_lport
.p_element
.mgmt_vlan
= 0;
832 memcpy(&hw
->h_lport
.p_element
.system_id
.system_mac
,
833 lchassis
->c_id
, lchassis
->c_id_len
);
834 hw
->h_lport
.p_element
.system_id
.conn_type
=
835 LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE
;
836 hw
->h_lport
.p_element
.system_id
.rsvd
= 0;
837 hw
->h_lport
.p_element
.system_id
.rsvd2
[0] = 0;
838 hw
->h_lport
.p_element
.system_id
.rsvd2
[1] = 0;
840 list_init(&hw
->h_lport
.p_isid_vlan_maps
);
841 list_init(&lldp
->lldpd
->g_hardware
);
842 list_push_back(&lldp
->lldpd
->g_hardware
, &hw
->h_entries
);
844 ovs_mutex_lock(&mutex
);
846 /* Update port with Auto Attach mappings configured. */
847 HMAP_FOR_EACH (m
, hmap_node_isid
, all_mappings
) {
848 struct aa_mapping_internal
*p
;
850 if (mapping_find_by_isid(lldp
, m
->isid
)) {
854 p
= xmemdup(m
, sizeof *p
);
855 hmap_insert(&lldp
->mappings_by_isid
, &p
->hmap_node_isid
,
856 hash_int(p
->isid
, 0));
857 hmap_insert(&lldp
->mappings_by_aux
,
859 hash_pointer(p
->aux
, 0));
861 update_mapping_on_lldp(lldp
, hw
, p
);
864 hmap_insert(all_lldps
, &lldp
->hmap_node
,
865 hash_string(netdev_get_name(netdev
), 0));
867 ovs_mutex_unlock(&mutex
);
874 lldp_create_dummy(void)
877 struct lldpd_chassis
*lchassis
;
878 struct lldpd_hardware
*hw
;
880 lldp
= xzalloc(sizeof *lldp
);
881 lldp
->name
= "dummy-lldp";
882 lldp
->lldpd
= xzalloc(sizeof *lldp
->lldpd
);
884 hmap_init(&lldp
->mappings_by_isid
);
885 hmap_init(&lldp
->mappings_by_aux
);
886 list_init(&lldp
->active_mapping_queue
);
888 lchassis
= xzalloc(sizeof *lchassis
);
889 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
;
890 lchassis
->c_cap_enabled
= LLDP_CAP_BRIDGE
;
891 lchassis
->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
892 lchassis
->c_id_len
= ETH_ADDR_LEN
;
893 lchassis
->c_id
= xmalloc(ETH_ADDR_LEN
);
895 list_init(&lchassis
->c_mgmt
);
896 lchassis
->c_ttl
= LLDP_CHASSIS_TTL
;
897 lldpd_assign_cfg_to_protocols(lldp
->lldpd
);
898 list_init(&lldp
->lldpd
->g_chassis
);
899 list_push_back(&lldp
->lldpd
->g_chassis
, &lchassis
->list
);
901 hw
= lldpd_alloc_hardware(lldp
->lldpd
, "dummy-hw", 0);
903 ovs_refcount_init(&lldp
->ref_cnt
);
905 hw
->h_flags
|= IFF_RUNNING
;
908 hw
->h_lport
.p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
909 hw
->h_lport
.p_id
= "dummy-port";
911 /* p_id is not necessarily a null terminated string. */
912 hw
->h_lport
.p_id_len
= strlen(hw
->h_lport
.p_id
);
914 /* Auto Attach element tlv */
915 hw
->h_lport
.p_element
.type
= LLDP_TLV_AA_ELEM_TYPE_CLIENT_VIRTUAL_SWITCH
;
916 hw
->h_lport
.p_element
.mgmt_vlan
= 0;
917 memcpy(&hw
->h_lport
.p_element
.system_id
.system_mac
,
918 lchassis
->c_id
, lchassis
->c_id_len
);
919 hw
->h_lport
.p_element
.system_id
.conn_type
=
920 LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE
;
921 hw
->h_lport
.p_element
.system_id
.rsvd
= 0;
922 hw
->h_lport
.p_element
.system_id
.rsvd2
[0] = 0;
923 hw
->h_lport
.p_element
.system_id
.rsvd2
[1] = 0;
925 list_init(&hw
->h_lport
.p_isid_vlan_maps
);
926 list_init(&lldp
->lldpd
->g_hardware
);
927 list_push_back(&lldp
->lldpd
->g_hardware
, &hw
->h_entries
);
932 /* Unreference a specific LLDP instance.
935 lldp_unref(struct lldp
*lldp
)
941 ovs_mutex_lock(&mutex
);
942 if (ovs_refcount_unref_relaxed(&lldp
->ref_cnt
) != 1) {
943 ovs_mutex_unlock(&mutex
);
947 hmap_remove(all_lldps
, &lldp
->hmap_node
);
948 ovs_mutex_unlock(&mutex
);
950 lldpd_cleanup(lldp
->lldpd
);
956 /* Unreference a specific LLDP instance.
959 lldp_ref(const struct lldp
*lldp_
)
961 struct lldp
*lldp
= CONST_CAST(struct lldp
*, lldp_
);
963 ovs_refcount_ref(&lldp
->ref_cnt
);