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"
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 array to an integer. I-SID are stored in an array of bytes
105 * in the LLDP hardware structrure.
108 array_to_int(uint8_t *array
, size_t len
)
113 ovs_assert(len
<= sizeof(uint32_t));
115 for (i
= 0; i
< len
; i
++) {
116 res
= res
| (array
[len
- i
- 1] << (i
* 8));
122 /* Convert an integer to an array of byte.
125 int_to_array(uint8_t *array
, size_t len
, uint32_t value
)
129 ovs_assert(len
<= sizeof(uint32_t));
131 for (i
= 0; i
< len
; i
++) {
132 array
[len
- i
- 1] = value
>> (8 * i
);
136 /* Convert an LLDP chassis ID to a string.
139 chassisid_to_string(uint8_t *array
, size_t len
, char **str
)
143 *str
= xmalloc(len
* 3);
145 for (i
= 0; i
< len
; i
++) {
146 snprintf(&(*str
)[i
* 3], 4, "%02x:", array
[i
]);
148 (*str
)[(i
* 3) - 1] = '\0';
151 /* Find an Auto Attach mapping keyed by I-SID.
153 static struct aa_mapping_internal
*
154 mapping_find_by_isid(struct lldp
*lldp
, const uint64_t isid
)
157 struct aa_mapping_internal
*m
;
159 HMAP_FOR_EACH_IN_BUCKET (m
,
161 hash_bytes(&isid
, sizeof isid
, 0),
162 &lldp
->mappings_by_isid
) {
163 if (isid
== m
->isid
) {
171 /* Find an Auto Attach mapping keyed by aux. aux is an opaque pointer created
172 * by the bridge that refers to an OVSDB mapping record.
174 static struct aa_mapping_internal
*
175 mapping_find_by_aux(struct lldp
*lldp
, const void *aux
) OVS_REQUIRES(mutex
)
177 struct aa_mapping_internal
*m
;
179 HMAP_FOR_EACH_IN_BUCKET (m
, hmap_node_aux
, hash_pointer(aux
, 0),
180 &lldp
->mappings_by_aux
) {
189 /* Convert an Auto Attach request status to a string.
192 aa_status_to_str(uint8_t status
)
195 #define AA_STATUS(NAME, VALUE, STR) case AA_STATUS_##NAME: return #STR;
198 default: return "Undefined";
202 /* Display LLDP and Auto Attach statistics.
205 aa_print_lldp_and_aa_stats(struct ds
*ds
, struct lldp
*lldp
)
208 struct lldpd_hardware
*hw
;
210 ds_put_format(ds
, "Statistics: %s\n", lldp
->name
);
216 LIST_FOR_EACH (hw
, h_entries
, &lldp
->lldpd
->g_hardware
.h_entries
) {
217 ds_put_format(ds
, "\ttx cnt: %"PRIu64
"\n", hw
->h_tx_cnt
);
218 ds_put_format(ds
, "\trx cnt: %"PRIu64
"\n", hw
->h_rx_cnt
);
219 ds_put_format(ds
, "\trx discarded cnt: %"PRIu64
"\n",
220 hw
->h_rx_discarded_cnt
);
221 ds_put_format(ds
, "\trx unrecognized cnt: %"PRIu64
"\n",
222 hw
->h_rx_unrecognized_cnt
);
223 ds_put_format(ds
, "\tageout cnt: %"PRIu64
"\n", hw
->h_ageout_cnt
);
224 ds_put_format(ds
, "\tinsert cnt: %"PRIu64
"\n", hw
->h_insert_cnt
);
225 ds_put_format(ds
, "\tdelete cnt: %"PRIu64
"\n", hw
->h_delete_cnt
);
226 ds_put_format(ds
, "\tdrop cnt: %"PRIu64
"\n", hw
->h_drop_cnt
);
231 aa_print_element_status_port(struct ds
*ds
, struct lldpd_hardware
*hw
)
233 struct lldpd_port
*port
;
235 LIST_FOR_EACH (port
, p_entries
, &hw
->h_rports
.p_entries
) {
236 if (memcmp(&port
->p_element
.system_id
,
238 sizeof port
->p_element
.system_id
)) {
239 static char *none_str
= "<None>";
240 char *id
= none_str
, *descr
= none_str
, *system
= none_str
;
242 if (port
->p_chassis
) {
243 if (port
->p_chassis
->c_id_len
> 0) {
244 chassisid_to_string((uint8_t *) port
->p_chassis
->c_id
,
245 port
->p_chassis
->c_id_len
, &id
);
248 descr
= port
->p_chassis
->c_descr
249 ? port
->p_chassis
->c_descr
: none_str
;
252 chassisid_to_string((uint8_t *) &port
->p_element
.system_id
,
253 sizeof port
->p_element
.system_id
, &system
);
256 "\tAuto Attach Primary Server Id: %s\n",
259 "\tAuto Attach Primary Server Descr: %s\n",
262 "\tAuto Attach Primary Server System Id: %s\n",
271 /* Auto Attach server broadcast an LLDP message periodically. Display
272 * the discovered server.
275 aa_print_element_status(struct ds
*ds
, struct lldp
*lldp
) OVS_REQUIRES(mutex
)
277 struct lldpd_hardware
*hw
;
279 ds_put_format(ds
, "LLDP: %s\n", lldp
->name
);
285 LIST_FOR_EACH (hw
, h_entries
, &lldp
->lldpd
->g_hardware
.h_entries
) {
286 aa_print_element_status_port(ds
, hw
);
291 aa_print_isid_status_port_isid(struct lldp
*lldp
, struct lldpd_port
*port
)
294 struct lldpd_aa_isid_vlan_maps_tlv
*mapping
;
296 if (list_is_empty(&port
->p_isid_vlan_maps
.m_entries
)) {
300 LIST_FOR_EACH (mapping
, m_entries
, &port
->p_isid_vlan_maps
.m_entries
) {
301 uint32_t isid
= array_to_int(mapping
->isid_vlan_data
.isid
,
302 sizeof mapping
->isid_vlan_data
.isid
);
303 struct aa_mapping_internal
*m
= mapping_find_by_isid(lldp
, isid
);
305 VLOG_INFO("h_rport: isid=%u, vlan=%u, status=%d",
307 mapping
->isid_vlan_data
.vlan
,
308 mapping
->isid_vlan_data
.status
);
310 /* Update the status of our internal state for the mapping.
313 VLOG_INFO("Setting status for ISID=%u to %u",
315 mapping
->isid_vlan_data
.status
);
316 m
->status
= mapping
->isid_vlan_data
.status
;
318 VLOG_WARN("Couldn't find mapping for I-SID=%u", isid
);
324 aa_print_isid_status_port(struct lldp
*lldp
, struct lldpd_hardware
*hw
)
327 struct lldpd_port
*port
;
329 LIST_FOR_EACH (port
, p_entries
, &hw
->h_rports
.p_entries
) {
330 aa_print_isid_status_port_isid(lldp
, port
);
334 /* The Auto Attach server will broadcast the status of the configured mappings
335 * via LLDP. Display the status.
338 aa_print_isid_status(struct ds
*ds
, struct lldp
*lldp
) OVS_REQUIRES(mutex
)
340 struct lldpd_hardware
*hw
;
341 struct aa_mapping_internal
*m
;
347 ds_put_format(ds
, "LLDP: %s\n", lldp
->name
);
349 LIST_FOR_EACH (hw
, h_entries
, &lldp
->lldpd
->g_hardware
.h_entries
) {
350 aa_print_isid_status_port(lldp
, hw
);
353 ds_put_format(ds
, "%-8s %-4s %-11s %-8s\n",
358 ds_put_format(ds
, "-------- ---- ----------- --------\n");
360 HMAP_FOR_EACH (m
, hmap_node_isid
, &lldp
->mappings_by_isid
) {
361 ds_put_format(ds
, "%-8ld %-4ld %-11s %-11s\n",
365 aa_status_to_str(m
->status
));
370 aa_unixctl_status(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
371 const char *argv
[] OVS_UNUSED
, void *aux OVS_UNUSED
)
375 struct ds ds
= DS_EMPTY_INITIALIZER
;
377 ovs_mutex_lock(&mutex
);
379 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
380 aa_print_element_status(&ds
, lldp
);
382 unixctl_command_reply(conn
, ds_cstr(&ds
));
385 ovs_mutex_unlock(&mutex
);
389 aa_unixctl_show_isid(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
390 const char *argv
[] OVS_UNUSED
, void *aux OVS_UNUSED
)
394 struct ds ds
= DS_EMPTY_INITIALIZER
;
396 ovs_mutex_lock(&mutex
);
398 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
399 aa_print_isid_status(&ds
, lldp
);
401 unixctl_command_reply(conn
, ds_cstr(&ds
));
404 ovs_mutex_unlock(&mutex
);
408 aa_unixctl_statistics(struct unixctl_conn
*conn
, int argc OVS_UNUSED
,
409 const char *argv
[] OVS_UNUSED
, void *aux OVS_UNUSED
)
412 struct ds ds
= DS_EMPTY_INITIALIZER
;
415 ovs_mutex_lock(&mutex
);
417 /* Cycle through all ports and dump the stats for each one */
418 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
419 aa_print_lldp_and_aa_stats(&ds
, lldp
);
422 ovs_mutex_unlock(&mutex
);
424 unixctl_command_reply(conn
, ds_cstr(&ds
));
427 /* An Auto Attach mapping was configured. Populate the corresponding
428 * structures in the LLDP hardware.
431 update_mapping_on_lldp(struct lldp
*lldp
, struct lldpd_hardware
*hardware
,
432 struct aa_mapping_internal
*m
)
434 struct lldpd_aa_isid_vlan_maps_tlv
*lm
= xzalloc(sizeof *lm
);
436 if (hardware
->h_ifname
) {
437 VLOG_INFO("\t\t hardware->h_ifname=%s", hardware
->h_ifname
);
440 int_to_array(lm
->isid_vlan_data
.isid
,
441 ARRAY_SIZE(lm
->isid_vlan_data
.isid
),
443 lm
->isid_vlan_data
.vlan
= m
->vlan
;
445 list_push_back(&hardware
->h_lport
.p_isid_vlan_maps
.m_entries
,
448 /* TODO Should be done in the Auto Attach state machine when a mapping goes
449 * from "pending" to "active".
452 struct bridge_aa_vlan
*node
= xmalloc(sizeof *node
);
454 node
->port_name
= xstrdup(hardware
->h_ifname
);
455 node
->vlan
= m
->vlan
;
456 node
->oper
= BRIDGE_AA_VLAN_OPER_ADD
;
458 list_push_back(&lldp
->active_mapping_queue
, &node
->list_node
);
462 /* Bridge will poll the list of VLAN that needs to be auto configure based on
463 * the Auto Attach mappings that have been exchanged with the server.
466 aa_get_vlan_queued(struct ovs_list
*list
)
470 ovs_mutex_lock(&mutex
);
472 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
473 struct bridge_aa_vlan
*node
, *node_next
;
475 LIST_FOR_EACH_SAFE (node
,
478 &lldp
->active_mapping_queue
) {
479 struct bridge_aa_vlan
*copy
;
481 copy
= xmalloc(sizeof *copy
);
482 copy
->port_name
= xstrdup(node
->port_name
);
483 copy
->vlan
= node
->vlan
;
484 copy
->oper
= node
->oper
;
486 list_push_back(list
, ©
->list_node
);
489 list_remove(&node
->list_node
);
490 free(node
->port_name
);
495 ovs_mutex_unlock(&mutex
);
500 /* Bridge will poll whether or not VLAN have been auto-configured.
503 aa_get_vlan_queue_size(void)
506 unsigned int size
= 0;
508 ovs_mutex_lock(&mutex
);
510 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
511 size
+= list_size(&lldp
->active_mapping_queue
);
514 ovs_mutex_unlock(&mutex
);
519 /* Configure Auto Attach.
522 aa_configure(const struct aa_settings
*s
)
526 ovs_mutex_lock(&mutex
);
528 /* TODO Change all instances for now */
529 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
530 struct lldpd_chassis
*chassis
;
532 LIST_FOR_EACH (chassis
, list
, &lldp
->lldpd
->g_chassis
.list
) {
533 /* System Description */
534 if (chassis
->c_descr
) {
535 free(chassis
->c_descr
);
537 chassis
->c_descr
= s
->system_description
[0] ?
538 xstrdup(s
->system_description
) : xstrdup(PACKAGE_STRING
);
541 if (chassis
->c_name
) {
542 free(chassis
->c_name
);
544 chassis
->c_name
= xstrdup(s
->system_name
);
548 ovs_mutex_unlock(&mutex
);
553 /* Add a new Auto Attach mapping.
556 aa_mapping_register(void *aux
, const struct aa_mapping_settings
*s
)
558 struct aa_mapping_internal
*bridge_m
;
561 VLOG_INFO("Adding mapping ISID=%ld, VLAN=%ld, aux=%p", (long int) s
->isid
,
562 (long int) s
->vlan
, aux
);
564 ovs_mutex_lock(&mutex
);
566 /* TODO These mappings should be stores per bridge. This is used
567 * When a port is added. Auto Attach mappings need to be added on this
570 bridge_m
= xzalloc(sizeof *bridge_m
);
571 bridge_m
->isid
= s
->isid
;
572 bridge_m
->vlan
= s
->vlan
;
574 bridge_m
->status
= AA_STATUS_PENDING
;
575 hmap_insert(all_mappings
,
576 &bridge_m
->hmap_node_isid
,
577 hash_bytes((const void *) &bridge_m
->isid
,
578 sizeof bridge_m
->isid
,
581 /* Update mapping on the all the LLDP instances. */
582 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
583 struct lldpd_hardware
*hw
;
584 struct aa_mapping_internal
*m
;
586 VLOG_INFO("\t lldp->name=%s", lldp
->name
);
588 if (mapping_find_by_isid(lldp
, s
->isid
)) {
592 m
= xzalloc(sizeof *m
);
595 m
->status
= AA_STATUS_PENDING
;
597 hmap_insert(&lldp
->mappings_by_isid
,
599 hash_bytes((const void *) &m
->isid
,
602 hmap_insert(&lldp
->mappings_by_aux
,
604 hash_pointer(m
->aux
, 0));
606 /* Configure the mapping on each port of the LLDP stack. */
607 LIST_FOR_EACH (hw
, h_entries
, &lldp
->lldpd
->g_hardware
.h_entries
) {
608 update_mapping_on_lldp(lldp
, hw
, m
);
612 ovs_mutex_unlock(&mutex
);
618 aa_mapping_unregister_mapping(struct lldp
*lldp
,
619 struct lldpd_hardware
*hw
,
620 struct aa_mapping_internal
*m
)
622 struct lldpd_aa_isid_vlan_maps_tlv
*lm
, *lm_next
;
624 LIST_FOR_EACH_SAFE (lm
,
627 &hw
->h_lport
.p_isid_vlan_maps
.m_entries
) {
628 uint32_t isid
= array_to_int(lm
->isid_vlan_data
.isid
,
629 sizeof lm
->isid_vlan_data
.isid
);
631 if (isid
== (uint32_t) m
->isid
) {
632 VLOG_INFO("\t\t Removing lport, isid=%u, vlan=%u",
634 lm
->isid_vlan_data
.vlan
);
636 list_remove(&lm
->m_entries
);
638 /* TODO Should be done in the AA SM when a mapping goes
639 * from "pending" to "active".
642 struct bridge_aa_vlan
*node
= xmalloc(sizeof *node
);
644 node
->port_name
= xstrdup(hw
->h_ifname
);
645 node
->vlan
= (uint32_t) m
->vlan
;
646 node
->oper
= BRIDGE_AA_VLAN_OPER_REMOVE
;
648 list_push_back(&lldp
->active_mapping_queue
, &node
->list_node
);
656 /* Remove an existing Auto Attach mapping.
659 aa_mapping_unregister(void *aux
)
663 VLOG_INFO("Removing mapping aux=%p", aux
);
665 ovs_mutex_lock(&mutex
);
667 HMAP_FOR_EACH (lldp
, hmap_node
, all_lldps
) {
668 struct lldpd_hardware
*hw
;
669 struct aa_mapping_internal
*m
= mapping_find_by_aux(lldp
, aux
);
670 int64_t isid_tmp
= -1, vlan_tmp
= -1;
672 /* Remove from internal hash tables. */
674 struct aa_mapping_internal
*p
=
675 mapping_find_by_isid(lldp
, m
->isid
);
679 VLOG_INFO("\t Removing mapping ISID=%ld, VLAN=%ld (lldp->name=%s)",
680 (long int) m
->isid
, (long int) m
->vlan
, lldp
->name
);
683 hmap_remove(&lldp
->mappings_by_isid
, &p
->hmap_node_isid
);
686 hmap_remove(&lldp
->mappings_by_aux
, &m
->hmap_node_aux
);
689 /* Remove from all the lldp instances */
690 LIST_FOR_EACH (hw
, h_entries
, &lldp
->lldpd
->g_hardware
.h_entries
) {
692 VLOG_INFO("\t\t hardware->h_ifname=%s", hw
->h_ifname
);
695 aa_mapping_unregister_mapping(lldp
, hw
, m
);
698 if (isid_tmp
>= 0 && vlan_tmp
>= 0) {
699 /* Remove from the all_mappings */
700 HMAP_FOR_EACH (m
, hmap_node_isid
, all_mappings
) {
701 if (m
&& isid_tmp
== m
->isid
&& vlan_tmp
== m
->vlan
) {
702 hmap_remove(all_mappings
, &m
->hmap_node_isid
);
710 ovs_mutex_unlock(&mutex
);
718 unixctl_command_register("autoattach/status", "[bridge]", 0, 1,
719 aa_unixctl_status
, NULL
);
720 unixctl_command_register("autoattach/show-isid", "[bridge]", 0, 1,
721 aa_unixctl_show_isid
, NULL
);
722 unixctl_command_register("autoattach/statistics", "[bridge]", 0, 1,
723 aa_unixctl_statistics
, NULL
);
726 /* Returns true if 'lldp' should process packets from 'flow'. Sets
727 * fields in 'wc' that were used to make the determination.
730 lldp_should_process_flow(const struct flow
*flow
)
732 return (flow
->dl_type
== htons(ETH_TYPE_LLDP
));
736 /* Process an LLDP packet that was received on a bridge port.
739 lldp_process_packet(struct lldp
*lldp
, const struct ofpbuf
*p
)
742 lldpd_recv(lldp
->lldpd
,
743 (struct lldpd_hardware
*)
744 lldp
->lldpd
->g_hardware
.h_entries
.next
,
750 /* This code is called periodically to check if the LLDP module has an LLDP
751 * message it wishes to send. It is called several times every second.
754 lldp_should_send_packet(struct lldp
*cfg
) OVS_EXCLUDED(mutex
)
758 ovs_mutex_lock(&mutex
);
759 ret
= timer_expired(&cfg
->tx_timer
);
760 ovs_mutex_unlock(&mutex
);
765 /* Returns the next wake up time.
768 lldp_wake_time(const struct lldp
*lldp
) OVS_EXCLUDED(mutex
)
770 long long int retval
;
776 ovs_mutex_lock(&mutex
);
777 retval
= lldp
->tx_timer
.t
;
778 ovs_mutex_unlock(&mutex
);
783 /* Put the monitor thread to sleep until it's next wake time.
786 lldp_wait(struct lldp
*lldp
) OVS_EXCLUDED(mutex
)
788 long long int wake_time
= lldp_wake_time(lldp
);
789 poll_timer_wait_until(wake_time
);
793 /* Prepare the LLDP packet to be sent on a bridge port.
796 lldp_put_packet(struct lldp
*lldp
, struct ofpbuf
*packet
,
797 uint8_t eth_src
[ETH_ADDR_LEN
]) OVS_EXCLUDED(mutex
)
799 struct lldpd
*mylldpd
= lldp
->lldpd
;
800 struct lldpd_hardware
*hw
= (struct lldpd_hardware
*)
801 mylldpd
->g_hardware
.h_entries
.next
;
802 uint32_t lldp_size
= 0;
803 static const uint8_t eth_addr_lldp
[6] =
804 {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0e};
806 ovs_mutex_lock(&mutex
);
808 eth_compose(packet
, eth_addr_lldp
, eth_src
, ETH_TYPE_LLDP
, 0);
810 lldp_size
= lldpd_send(hw
, packet
);
811 if (lldp_size
+ ETH_HEADER_LEN
< MINIMUM_ETH_PACKET_SIZE
) {
812 lldp_size
= MINIMUM_ETH_PACKET_SIZE
;
815 timer_set_duration(&lldp
->tx_timer
, lldp
->lldpd
->g_config
.c_tx_interval
);
816 ovs_mutex_unlock(&mutex
);
819 /* Configures the LLDP stack.
822 lldp_configure(struct lldp
*lldp
) OVS_EXCLUDED(mutex
)
825 ovs_mutex_lock(&mutex
);
826 timer_set_expired(&lldp
->tx_timer
);
827 timer_set_duration(&lldp
->tx_timer
, LLDP_DEFAULT_TRANSMIT_INTERVAL_MS
);
828 lldp
->lldpd
->g_config
.c_tx_interval
=
829 LLDP_DEFAULT_TRANSMIT_INTERVAL_MS
;
830 ovs_mutex_unlock(&mutex
);
836 /* Create an LLDP stack instance. At the moment there is one per bridge port.
839 lldp_create(const struct netdev
*netdev
,
841 const struct smap
*cfg
) OVS_EXCLUDED(mutex
)
844 struct lldpd_chassis
*lchassis
;
845 struct lldpd_hardware
*hw
;
846 struct aa_mapping_internal
*m
;
848 if (!cfg
|| !smap_get_bool(cfg
, "enable", false)) {
852 lldp
= xzalloc(sizeof *lldp
);
853 lldp
->name
= xstrdup(netdev_get_name(netdev
));
854 lldp
->lldpd
= xzalloc(sizeof *lldp
->lldpd
);
856 hmap_init(&lldp
->mappings_by_isid
);
857 hmap_init(&lldp
->mappings_by_aux
);
858 list_init(&lldp
->active_mapping_queue
);
860 lchassis
= xzalloc(sizeof *lchassis
);
861 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
;
862 lchassis
->c_cap_enabled
= LLDP_CAP_BRIDGE
;
863 lchassis
->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
864 lchassis
->c_id_len
= ETH_ADDR_LEN
;
865 lchassis
->c_id
= xmalloc(ETH_ADDR_LEN
);
866 netdev_get_etheraddr(netdev
, (uint8_t *) lchassis
->c_id
);
868 list_init(&lchassis
->c_mgmt
.m_entries
);
869 lchassis
->c_ttl
= lldp
->lldpd
->g_config
.c_tx_interval
*
870 lldp
->lldpd
->g_config
.c_tx_hold
;
871 lchassis
->c_ttl
= LLDP_CHASSIS_TTL
;
872 lldpd_assign_cfg_to_protocols(lldp
->lldpd
);
873 list_init(&lldp
->lldpd
->g_chassis
.list
);
874 list_push_back(&lldp
->lldpd
->g_chassis
.list
, &lchassis
->list
);
876 if ((hw
= lldpd_alloc_hardware(lldp
->lldpd
,
877 (char *) netdev_get_name(netdev
),
879 VLOG_WARN("Unable to allocate space for %s",
880 (char *) netdev_get_name(netdev
));
884 ovs_refcount_init(&lldp
->ref_cnt
);
886 hw
->h_flags
|= IFF_RUNNING
;
889 hw
->h_lport
.p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
890 hw
->h_lport
.p_id
= xstrdup(netdev_get_name(netdev
));
892 /* p_id is not necessarily a null terminated string. */
893 hw
->h_lport
.p_id_len
= strlen(netdev_get_name(netdev
));
895 /* Auto Attach element tlv */
896 hw
->h_lport
.p_element
.type
= LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT
;
897 hw
->h_lport
.p_element
.mgmt_vlan
= 0;
898 memcpy(&hw
->h_lport
.p_element
.system_id
.system_mac
,
899 lchassis
->c_id
, lchassis
->c_id_len
);
900 hw
->h_lport
.p_element
.system_id
.conn_type
=
901 LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE
;
903 hw
->h_lport
.p_element
.system_id
.smlt_id
= 0;
904 hw
->h_lport
.p_element
.system_id
.mlt_id
[0] = 0;
905 hw
->h_lport
.p_element
.system_id
.mlt_id
[1] = 0;
907 list_init(&hw
->h_lport
.p_isid_vlan_maps
.m_entries
);
908 list_init(&lldp
->lldpd
->g_hardware
.h_entries
);
909 list_push_back(&lldp
->lldpd
->g_hardware
.h_entries
, &hw
->h_entries
);
911 ovs_mutex_lock(&mutex
);
913 /* Update port with Auto Attach mappings configured. */
914 HMAP_FOR_EACH (m
, hmap_node_isid
, all_mappings
) {
915 struct aa_mapping_internal
*p
;
917 if (mapping_find_by_isid(lldp
, m
->isid
)) {
921 p
= xmemdup(m
, sizeof *p
);
922 hmap_insert(&lldp
->mappings_by_isid
,
924 hash_bytes((const void *) &p
->isid
,
927 hmap_insert(&lldp
->mappings_by_aux
,
929 hash_pointer(p
->aux
, 0));
931 update_mapping_on_lldp(lldp
, hw
, p
);
934 hmap_insert(all_lldps
, &lldp
->hmap_node
,
935 hash_string(netdev_get_name(netdev
), 0));
937 ovs_mutex_unlock(&mutex
);
944 lldp_create_dummy(void)
947 struct lldpd_chassis
*lchassis
;
948 struct lldpd_hardware
*hw
;
950 lldp
= xzalloc(sizeof *lldp
);
951 lldp
->name
= "dummy-lldp";
952 lldp
->lldpd
= xzalloc(sizeof *lldp
->lldpd
);
954 hmap_init(&lldp
->mappings_by_isid
);
955 hmap_init(&lldp
->mappings_by_aux
);
956 list_init(&lldp
->active_mapping_queue
);
958 lchassis
= xzalloc(sizeof *lchassis
);
959 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
;
960 lchassis
->c_cap_enabled
= LLDP_CAP_BRIDGE
;
961 lchassis
->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
962 lchassis
->c_id_len
= ETH_ADDR_LEN
;
963 lchassis
->c_id
= xmalloc(ETH_ADDR_LEN
);
965 list_init(&lchassis
->c_mgmt
.m_entries
);
966 lchassis
->c_ttl
= LLDP_CHASSIS_TTL
;
967 lldpd_assign_cfg_to_protocols(lldp
->lldpd
);
968 list_init(&lldp
->lldpd
->g_chassis
.list
);
969 list_push_back(&lldp
->lldpd
->g_chassis
.list
, &lchassis
->list
);
971 if ((hw
= lldpd_alloc_hardware(lldp
->lldpd
,
974 VLOG_WARN("Unable to allocate space for dummy-hw");
978 ovs_refcount_init(&lldp
->ref_cnt
);
980 hw
->h_flags
|= IFF_RUNNING
;
983 hw
->h_lport
.p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
984 hw
->h_lport
.p_id
= "dummy-port";
986 /* p_id is not necessarily a null terminated string. */
987 hw
->h_lport
.p_id_len
= strlen(hw
->h_lport
.p_id
);
989 /* Auto Attach element tlv */
990 hw
->h_lport
.p_element
.type
= LLDP_TLV_AA_ELEM_TYPE_TAG_CLIENT
;
991 hw
->h_lport
.p_element
.mgmt_vlan
= 0;
992 memcpy(&hw
->h_lport
.p_element
.system_id
.system_mac
,
993 lchassis
->c_id
, lchassis
->c_id_len
);
994 hw
->h_lport
.p_element
.system_id
.conn_type
=
995 LLDP_TLV_AA_ELEM_CONN_TYPE_SINGLE
;
996 hw
->h_lport
.p_element
.system_id
.smlt_id
= 0;
997 hw
->h_lport
.p_element
.system_id
.mlt_id
[0] = 0;
998 hw
->h_lport
.p_element
.system_id
.mlt_id
[1] = 0;
1000 list_init(&hw
->h_lport
.p_isid_vlan_maps
.m_entries
);
1001 list_init(&lldp
->lldpd
->g_hardware
.h_entries
);
1002 list_push_back(&lldp
->lldpd
->g_hardware
.h_entries
, &hw
->h_entries
);
1007 /* Unreference a specific LLDP instance.
1010 lldp_unref(struct lldp
*lldp
)
1016 ovs_mutex_lock(&mutex
);
1017 if (ovs_refcount_unref_relaxed(&lldp
->ref_cnt
) != 1) {
1018 ovs_mutex_unlock(&mutex
);
1022 hmap_remove(all_lldps
, &lldp
->hmap_node
);
1023 ovs_mutex_unlock(&mutex
);
1025 lldpd_cleanup(lldp
->lldpd
);
1031 /* Unreference a specific LLDP instance.
1034 lldp_ref(const struct lldp
*lldp_
)
1036 struct lldp
*lldp
= CONST_CAST(struct lldp
*, lldp_
);
1038 ovs_refcount_ref(&lldp
->ref_cnt
);