2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
27 #include <sys/utsname.h>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/select.h>
32 #include <sys/ioctl.h>
33 #include <arpa/inet.h>
34 #include <net/if_arp.h>
36 #if LLDPD_FD_SETSIZE != FD_SETSIZE
37 # warning "FD_SETSIZE is set to an inconsistent value."
41 #include <net-snmp/net-snmp-config.h>
42 #include <net-snmp/net-snmp-includes.h>
43 #include <net-snmp/agent/net-snmp-agent-includes.h>
44 #include <net-snmp/agent/snmp_vars.h>
47 static void usage(void);
49 static struct protocol protos
[] =
51 { LLDPD_MODE_LLDP
, 1, "LLDP", 'l', lldp_send
, lldp_decode
, NULL
,
52 LLDP_MULTICAST_ADDR
},
54 { LLDPD_MODE_CDPV1
, 0, "CDPv1", 'c', cdpv1_send
, cdp_decode
, cdpv1_guess
,
56 { LLDPD_MODE_CDPV2
, 0, "CDPv2", 'c', cdpv2_send
, cdp_decode
, cdpv2_guess
,
60 { LLDPD_MODE_SONMP
, 0, "SONMP", 's', sonmp_send
, sonmp_decode
, NULL
,
61 SONMP_MULTICAST_ADDR
},
64 { LLDPD_MODE_EDP
, 0, "EDP", 'e', edp_send
, edp_decode
, NULL
,
68 { LLDPD_MODE_FDP
, 0, "FDP", 'f', fdp_send
, cdp_decode
, NULL
,
71 { 0, 0, "any", ' ', NULL
, NULL
, NULL
,
75 static void lldpd_update_localchassis(struct lldpd
*);
76 static void lldpd_update_localports(struct lldpd
*);
77 static void lldpd_cleanup(struct lldpd
*);
78 static void lldpd_loop(struct lldpd
*);
79 static void lldpd_shutdown(int);
80 static void lldpd_exit(void);
81 static void lldpd_send_all(struct lldpd
*);
82 static void lldpd_recv_all(struct lldpd
*);
83 static int lldpd_guess_type(struct lldpd
*, char *, int);
84 static void lldpd_decode(struct lldpd
*, char *, int,
85 struct lldpd_hardware
*);
86 static void lldpd_update_chassis(struct lldpd_chassis
*,
87 const struct lldpd_chassis
*);
89 static void lldpd_med(struct lldpd_chassis
*);
92 static char **saved_argv
;
93 #ifdef HAVE___PROGNAME
94 extern const char *__progname
;
96 # define __progname "lldpd"
102 fprintf(stderr
, "Usage: %s [OPTIONS ...]\n", __progname
);
104 fprintf(stderr
, "\n");
106 fprintf(stderr
, "-d Do not daemonize.\n");
107 fprintf(stderr
, "-i Disable LLDP-MED inventory TLV transmission.\n");
108 fprintf(stderr
, "-k Disable advertising of kernel release, version, machine.\n");
109 fprintf(stderr
, "-S descr Override the default system description.\n");
110 fprintf(stderr
, "-m IP Specify the management address of this system.\n");
111 #ifdef ENABLE_LLDPMED
112 fprintf(stderr
, "-M class Enable emission of LLDP-MED frame. 'class' should be one of:\n");
113 fprintf(stderr
, " 1 Generic Endpoint (Class I)\n");
114 fprintf(stderr
, " 2 Media Endpoint (Class II)\n");
115 fprintf(stderr
, " 3 Communication Device Endpoints (Class III)\n");
116 fprintf(stderr
, " 4 Network Connectivity Device\n");
119 fprintf(stderr
, "-x Enable SNMP subagent.\n");
121 fprintf(stderr
, "\n");
123 #if defined ENABLE_CDP || defined ENABLE_EDP || defined ENABLE_FDP || defined ENABLE_SONMP
124 fprintf(stderr
, "Additional protocol support.\n");
126 fprintf(stderr
, "-c Enable the support of CDP protocol. (Cisco)\n");
129 fprintf(stderr
, "-e Enable the support of EDP protocol. (Extreme)\n");
132 fprintf(stderr
, "-f Enable the support of FDP protocol. (Foundry)\n");
135 fprintf(stderr
, "-s Enable the support of SONMP protocol. (Nortel)\n");
138 fprintf(stderr
, "\n");
141 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
145 struct lldpd_hardware
*
146 lldpd_get_hardware(struct lldpd
*cfg
, char *name
, int index
, struct lldpd_ops
*ops
)
148 struct lldpd_hardware
*hardware
;
149 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
150 if ((strcmp(hardware
->h_ifname
, name
) == 0) &&
151 (hardware
->h_ifindex
== index
) &&
152 ((!ops
) || (ops
== hardware
->h_ops
)))
158 struct lldpd_hardware
*
159 lldpd_alloc_hardware(struct lldpd
*cfg
, char *name
)
161 struct lldpd_hardware
*hardware
;
163 if ((hardware
= (struct lldpd_hardware
*)
164 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
167 strlcpy(hardware
->h_ifname
, name
, sizeof(hardware
->h_ifname
));
168 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
169 hardware
->h_lport
.p_chassis
->c_refcount
++;
170 TAILQ_INIT(&hardware
->h_rports
);
172 #ifdef ENABLE_LLDPMED
173 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
174 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
175 if (!cfg
->g_noinventory
)
176 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
180 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
187 lldpd_vlan_cleanup(struct lldpd_port
*port
)
189 struct lldpd_vlan
*vlan
, *vlan_next
;
190 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
194 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
195 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
201 /* If `all' is true, clear all information, including information that
202 are not refreshed periodically. Port should be freed manually. */
204 lldpd_port_cleanup(struct lldpd
*cfg
, struct lldpd_port
*port
, int all
)
206 #ifdef ENABLE_LLDPMED
209 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
210 free(port
->p_med_location
[i
].data
);
213 lldpd_vlan_cleanup(port
);
218 free(port
->p_lastframe
);
219 if (port
->p_chassis
) { /* chassis may not have been attributed, yet */
220 port
->p_chassis
->c_refcount
--;
221 port
->p_chassis
= NULL
;
227 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
229 #ifdef ENABLE_LLDPMED
230 free(chassis
->c_med_hw
);
231 free(chassis
->c_med_sw
);
232 free(chassis
->c_med_fw
);
233 free(chassis
->c_med_sn
);
234 free(chassis
->c_med_manuf
);
235 free(chassis
->c_med_model
);
236 free(chassis
->c_med_asset
);
239 free(chassis
->c_name
);
240 free(chassis
->c_descr
);
246 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
248 struct lldpd_port
*port
, *port_next
;
250 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
253 port_next
= TAILQ_NEXT(port
, p_entries
);
256 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
257 hardware
->h_rx_ageout_cnt
++;
261 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
262 lldpd_port_cleanup(cfg
, port
, 1);
269 lldpd_hardware_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
272 lldpd_port_cleanup(cfg
, &hardware
->h_lport
, 1);
273 /* If we have a dedicated cleanup function, use it. Otherwise,
274 we just free the hardware-dependent data and close all FD
275 in h_recvfds and h_sendfd. */
276 if (hardware
->h_ops
->cleanup
)
277 hardware
->h_ops
->cleanup(cfg
, hardware
);
279 free(hardware
->h_data
);
280 for (i
=0; i
< LLDPD_FD_SETSIZE
; i
++)
281 if (FD_ISSET(i
, &hardware
->h_recvfds
))
283 if (hardware
->h_sendfd
) close(hardware
->h_sendfd
);
289 lldpd_cleanup(struct lldpd
*cfg
)
291 struct lldpd_hardware
*hardware
, *hardware_next
;
292 struct lldpd_chassis
*chassis
, *chassis_next
;
294 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
295 hardware
= hardware_next
) {
296 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
297 if (!hardware
->h_flags
) {
298 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
299 lldpd_remote_cleanup(cfg
, hardware
, 1);
300 lldpd_hardware_cleanup(cfg
, hardware
);
302 lldpd_remote_cleanup(cfg
, hardware
, 0);
305 for (chassis
= TAILQ_FIRST(&cfg
->g_chassis
); chassis
;
306 chassis
= chassis_next
) {
307 chassis_next
= TAILQ_NEXT(chassis
, c_entries
);
308 if (chassis
->c_refcount
== 0) {
309 TAILQ_REMOVE(&cfg
->g_chassis
, chassis
, c_entries
);
310 lldpd_chassis_cleanup(chassis
, 1);
316 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
321 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
322 if (!cfg
->g_protocols
[i
].enabled
)
324 if (cfg
->g_protocols
[i
].guess
== NULL
) {
325 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
326 return cfg
->g_protocols
[i
].mode
;
328 if (cfg
->g_protocols
[i
].guess(frame
, s
))
329 return cfg
->g_protocols
[i
].mode
;
336 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
337 struct lldpd_hardware
*hardware
)
340 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
341 struct lldpd_port
*port
, *oport
= NULL
;
342 int guess
= LLDPD_MODE_LLDP
;
344 /* Discard VLAN frames */
345 if ((s
>= sizeof(struct ethhdr
)) &&
346 (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)))
349 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
350 if ((oport
->p_lastframe
!= NULL
) &&
351 (oport
->p_lastframe
->size
== s
) &&
352 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
353 /* Already received the same frame */
354 oport
->p_lastupdate
= time(NULL
);
359 guess
= lldpd_guess_type(cfg
, frame
, s
);
360 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
361 if (!cfg
->g_protocols
[i
].enabled
)
363 if (cfg
->g_protocols
[i
].mode
== guess
) {
364 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
365 s
, hardware
, &chassis
, &port
)) == -1)
367 chassis
->c_protocol
= port
->p_protocol
=
368 cfg
->g_protocols
[i
].mode
;
372 if (cfg
->g_protocols
[i
].mode
== 0) {
373 LLOG_INFO("unable to guess frame type");
377 /* Do we already have the same MSAP somewhere? */
378 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
379 if ((port
->p_protocol
== oport
->p_protocol
) &&
380 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
381 (port
->p_id_len
== oport
->p_id_len
) &&
382 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
383 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
384 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
385 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
386 chassis
->c_id_len
) == 0)) {
387 ochassis
= oport
->p_chassis
;
391 /* No, but do we already know the system? */
393 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
394 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
395 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
396 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
397 (memcmp(chassis
->c_id
, ochassis
->c_id
,
398 chassis
->c_id_len
) == 0))
404 /* The port is known, remove it before adding it back */
405 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
406 lldpd_port_cleanup(cfg
, oport
, 1);
410 lldpd_update_chassis(ochassis
, chassis
);
414 /* Chassis not known, add it */
415 chassis
->c_index
= ++cfg
->g_lastrid
;
416 chassis
->c_refcount
= 0;
417 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
418 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
419 LLOG_DEBUG("Currently, we know %d different systems", i
);
422 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
423 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
424 sizeof(int))) != NULL
) {
425 port
->p_lastframe
->size
= s
;
426 memcpy(port
->p_lastframe
->frame
, frame
, s
);
428 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
429 port
->p_chassis
= chassis
;
430 port
->p_chassis
->c_refcount
++;
431 /* Several cases are possible :
432 1. chassis is new, its refcount was 0. It is now attached
433 to this port, its refcount is 1.
434 2. chassis already exists and was attached to another
435 port, we increase its refcount accordingly.
436 3. chassis already exists and was attached to the same
437 port, its refcount was decreased with
438 lldpd_port_cleanup() and is now increased again.
440 In all cases, if the port already existed, it has been
441 freed with lldpd_port_cleanup() and therefore, the refcount
442 of the chassis that was attached to it is decreased.
444 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) i
++;
445 LLOG_DEBUG("Currently, %s known %d neighbors",
446 hardware
->h_ifname
, i
);
450 /* Update chassis `ochassis' with values from `chassis'. */
452 lldpd_update_chassis(struct lldpd_chassis
*ochassis
,
453 const struct lldpd_chassis
*chassis
) {
454 TAILQ_ENTRY(lldpd_chassis
) entries
;
455 /* We want to keep refcount, index and list stuff from the current
457 int refcount
= ochassis
->c_refcount
;
458 int index
= ochassis
->c_index
;
459 memcpy(&entries
, &ochassis
->c_entries
,
462 lldpd_chassis_cleanup(ochassis
, 0);
463 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
464 /* Restore saved values */
465 ochassis
->c_refcount
= refcount
;
466 ochassis
->c_index
= index
;
467 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
471 lldpd_callback_add(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
), void *data
)
473 struct lldpd_callback
*callback
;
474 if ((callback
= (struct lldpd_callback
*)
475 malloc(sizeof(struct lldpd_callback
))) == NULL
)
478 callback
->function
= fn
;
479 callback
->data
= data
;
480 TAILQ_INSERT_TAIL(&cfg
->g_callbacks
, callback
, next
);
485 lldpd_callback_del(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
))
487 struct lldpd_callback
*callback
, *callback_next
;
488 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
490 callback
= callback_next
) {
491 callback_next
= TAILQ_NEXT(callback
, next
);
492 if ((callback
->fd
== fd
) &&
493 (callback
->function
= fn
)) {
494 free(callback
->data
);
495 TAILQ_REMOVE(&cfg
->g_callbacks
, callback
, next
);
502 lldpd_recv_all(struct lldpd
*cfg
)
504 struct lldpd_hardware
*hardware
;
505 struct lldpd_callback
*callback
, *callback_next
;
509 struct timeval snmptv
;
516 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
518 tv
.tv_sec
= LLDPD_TX_DELAY
;
519 if (tv
.tv_sec
>= cfg
->g_delay
)
520 tv
.tv_sec
= cfg
->g_delay
;
526 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
527 /* Ignore if interface is down */
528 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
530 /* This is quite expensive but we don't rely on internal
531 * structure of fd_set. */
532 for (n
= 0; n
< LLDPD_FD_SETSIZE
; n
++)
533 if (FD_ISSET(n
, &hardware
->h_recvfds
)) {
539 TAILQ_FOREACH(callback
, &cfg
->g_callbacks
, next
) {
540 FD_SET(callback
->fd
, &rfds
);
541 if (nfds
< callback
->fd
)
548 memcpy(&snmptv
, &tv
, sizeof(struct timeval
));
549 snmp_select_info(&nfds
, &rfds
, &snmptv
, &snmpblock
);
551 memcpy(&tv
, &snmptv
, sizeof(struct timeval
));
553 #endif /* USE_SNMP */
559 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
563 LLOG_WARN("failure on select");
573 #endif /* USE_SNMP */
574 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
575 for (n
= 0; n
< LLDPD_FD_SETSIZE
; n
++)
576 if ((FD_ISSET(n
, &hardware
->h_recvfds
)) &&
577 (FD_ISSET(n
, &rfds
))) break;
578 if (n
== LLDPD_FD_SETSIZE
) continue;
579 if ((buffer
= (char *)malloc(
580 hardware
->h_mtu
)) == NULL
) {
581 LLOG_WARN("failed to alloc reception buffer");
584 if ((n
= hardware
->h_ops
->recv(cfg
, hardware
,
585 n
, buffer
, hardware
->h_mtu
)) == -1) {
589 hardware
->h_rx_cnt
++;
590 lldpd_decode(cfg
, buffer
, n
, hardware
);
594 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
596 callback
= callback_next
) {
597 /* Callback function can use TAILQ_REMOVE */
598 callback_next
= TAILQ_NEXT(callback
, next
);
599 if (FD_ISSET(callback
->fd
, &rfds
))
600 callback
->function(cfg
, callback
);
606 netsnmp_check_outstanding_agent_requests();
608 #endif /* USE_SNMP */
609 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
613 lldpd_send_all(struct lldpd
*cfg
)
615 struct lldpd_hardware
*hardware
;
616 struct lldpd_port
*port
;
619 cfg
->g_lastsent
= time(NULL
);
620 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
621 /* Ignore if interface is down */
622 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
626 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
627 if (!cfg
->g_protocols
[i
].enabled
)
629 /* We send only if we have at least one remote system
630 * speaking this protocol or if the protocol is forced */
631 if (cfg
->g_protocols
[i
].enabled
> 1) {
632 cfg
->g_protocols
[i
].send(cfg
, hardware
);
636 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
637 if (port
->p_protocol
==
638 cfg
->g_protocols
[i
].mode
) {
639 cfg
->g_protocols
[i
].send(cfg
,
648 /* Nothing was sent for this port, let's speak LLDP */
649 cfg
->g_protocols
[0].send(cfg
,
654 #ifdef ENABLE_LLDPMED
656 lldpd_med(struct lldpd_chassis
*chassis
)
658 free(chassis
->c_med_hw
);
659 free(chassis
->c_med_fw
);
660 free(chassis
->c_med_sn
);
661 free(chassis
->c_med_manuf
);
662 free(chassis
->c_med_model
);
663 free(chassis
->c_med_asset
);
664 chassis
->c_med_hw
= dmi_hw();
665 chassis
->c_med_fw
= dmi_fw();
666 chassis
->c_med_sn
= dmi_sn();
667 chassis
->c_med_manuf
= dmi_manuf();
668 chassis
->c_med_model
= dmi_model();
669 chassis
->c_med_asset
= dmi_asset();
674 lldpd_update_localchassis(struct lldpd
*cfg
)
680 struct lldpd_hardware
*hardware
;
682 /* Set system name and description */
684 fatal("failed to get system information");
685 if ((hp
= priv_gethostbyname()) == NULL
)
686 fatal("failed to get system name");
687 free(LOCAL_CHASSIS(cfg
)->c_name
);
688 free(LOCAL_CHASSIS(cfg
)->c_descr
);
689 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
691 if (cfg
->g_descr_override
) {
692 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s",
693 cfg
->g_descr_override
) == -1)
694 fatal("failed to set full system description");
696 if (cfg
->g_advertise_version
) {
697 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s %s %s %s",
698 un
.sysname
, un
.release
, un
.version
, un
.machine
)
700 fatal("failed to set full system description");
702 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s",
704 fatal("failed to set minimal system description");
708 /* Check forwarding */
709 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
710 if ((read(f
, &status
, 1) == 1) && (status
== '1')) {
711 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= LLDP_CAP_ROUTER
;
715 #ifdef ENABLE_LLDPMED
716 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_TELEPHONE
)
717 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
718 lldpd_med(LOCAL_CHASSIS(cfg
));
719 free(LOCAL_CHASSIS(cfg
)->c_med_sw
);
720 if (cfg
->g_advertise_version
)
721 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup(un
.release
);
723 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup("Unknown");
726 /* Set chassis ID if needed */
727 if ((LOCAL_CHASSIS(cfg
)->c_id
== NULL
) &&
728 (hardware
= TAILQ_FIRST(&cfg
->g_hardware
))) {
729 if ((LOCAL_CHASSIS(cfg
)->c_id
=
730 malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
732 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
733 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
734 memcpy(LOCAL_CHASSIS(cfg
)->c_id
,
735 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
740 lldpd_update_localports(struct lldpd
*cfg
)
742 struct ifaddrs
*ifap
;
743 struct lldpd_hardware
*hardware
;
744 lldpd_ifhandlers ifhs
[] = {
745 lldpd_ifh_bond
, /* Handle bond */
746 lldpd_ifh_eth
, /* Handle classic ethernet interfaces */
748 lldpd_ifh_vlan
, /* Handle VLAN */
750 lldpd_ifh_mgmt
, /* Handle management address (if not already handled) */
753 lldpd_ifhandlers
*ifh
;
755 /* h_flags is set to 0 for each port. If the port is updated, h_flags
756 * will be set to a non-zero value. This will allow us to clean up any
757 * non up-to-date port */
758 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
759 hardware
->h_flags
= 0;
761 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
762 if (getifaddrs(&ifap
) != 0)
763 fatal("lldpd_update_localports: failed to get interface list");
765 /* We will run the list of interfaces through a list of interface
766 * handlers. Each handler will create or update some hardware port (and
767 * will set h_flags to a non zero value. The handler can use the list of
768 * interfaces but this is not mandatory. If the interface handler
769 * handles an interface from the list, it should set ifa_flags to 0 to
770 * let know the other handlers that it took care of this interface. This
771 * means that more specific handlers should be before less specific
773 for (ifh
= ifhs
; *ifh
!= NULL
; ifh
++)
779 lldpd_loop(struct lldpd
*cfg
)
783 1. Update local ports information
784 2. Clean unwanted (removed) local ports
785 3. Update local chassis information
789 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
790 lldpd_update_localports(cfg
);
792 lldpd_update_localchassis(cfg
);
798 lldpd_shutdown(int sig
)
800 LLOG_INFO("signal received, exiting");
804 /* For signal handling */
805 static struct lldpd
*gcfg
= NULL
;
810 struct lldpd_hardware
*hardware
, *hardware_next
;
813 for (hardware
= TAILQ_FIRST(&gcfg
->g_hardware
); hardware
!= NULL
;
814 hardware
= hardware_next
) {
815 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
816 lldpd_hardware_cleanup(gcfg
, hardware
);
821 #endif /* USE_SNMP */
825 lldpd_main(int argc
, char *argv
[])
828 struct lldpd_chassis
*lchassis
;
832 char *agentx
= NULL
; /* AgentX socket */
837 int i
, found
, advertise_version
= 1;
838 #ifdef ENABLE_LLDPMED
839 int lldpmed
= 0, noinventory
= 0;
841 char *descr_override
= NULL
;
846 * Get and parse command line options
848 popt
= strchr(opts
, '@');
849 for (i
=0; protos
[i
].mode
!= 0; i
++)
850 *(popt
++) = protos
[i
].arg
;
852 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
864 advertise_version
= 0;
866 #ifdef ENABLE_LLDPMED
868 lldpmed
= atoi(optarg
);
869 if ((lldpmed
< 1) || (lldpmed
> 4)) {
870 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
881 fprintf(stderr
, "LLDP-MED support is not built-in\n");
896 fprintf(stderr
, "SNMP support is not built-in\n");
901 descr_override
= strdup(optarg
);
905 for (i
=0; protos
[i
].mode
!= 0; i
++) {
906 if (ch
== protos
[i
].arg
) {
908 /* When an argument enable
909 several protocols, only the
910 first one can be forced. */
911 if (found
&& protos
[i
].enabled
> 1)
912 protos
[i
].enabled
= 1;
921 log_init(debug
, __progname
);
922 tzset(); /* Get timezone info before chroot */
927 if (daemon(0, 0) != 0)
928 fatal("failed to detach daemon");
929 if ((pid
= open(LLDPD_PID_FILE
,
930 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
931 fatal("unable to open pid file " LLDPD_PID_FILE
);
932 if (asprintf(&spid
, "%d\n", getpid()) == -1)
933 fatal("unable to create pid file " LLDPD_PID_FILE
);
934 if (write(pid
, spid
, strlen(spid
)) == -1)
935 fatal("unable to write pid file " LLDPD_PID_FILE
);
940 priv_init(PRIVSEP_CHROOT
);
942 if ((cfg
= (struct lldpd
*)
943 calloc(1, sizeof(struct lldpd
))) == NULL
)
946 cfg
->g_mgmt_pattern
= mgmtp
;
947 cfg
->g_advertise_version
= advertise_version
;
949 /* Get ioctl socket */
950 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
951 fatal("failed to get ioctl socket");
952 cfg
->g_delay
= LLDPD_TX_DELAY
;
955 cfg
->g_descr_override
= descr_override
;
957 /* Set system capabilities */
958 if ((lchassis
= (struct lldpd_chassis
*)
959 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
961 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
963 #ifdef ENABLE_LLDPMED
965 if (lldpmed
== LLDPMED_CLASS_III
)
966 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
967 lchassis
->c_med_type
= lldpmed
;
968 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
969 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
|
970 LLDPMED_CAP_POLICY
| LLDPMED_CAP_MDI_PSE
| LLDPMED_CAP_MDI_PD
;
971 cfg
->g_noinventory
= noinventory
;
973 cfg
->g_noinventory
= 1;
977 lchassis
->c_ttl
= LLDPD_TTL
;
979 cfg
->g_protocols
= protos
;
980 for (i
=0; protos
[i
].mode
!= 0; i
++)
981 if (protos
[i
].enabled
> 1)
982 LLOG_INFO("protocol %s enabled and forced", protos
[i
].name
);
983 else if (protos
[i
].enabled
)
984 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
986 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
988 TAILQ_INIT(&cfg
->g_hardware
);
989 TAILQ_INIT(&cfg
->g_chassis
);
990 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
991 lchassis
->c_refcount
++; /* We should always keep a reference to local chassis */
993 TAILQ_INIT(&cfg
->g_callbacks
);
998 agent_init(cfg
, agentx
, debug
);
1000 #endif /* USE_SNMP */
1003 if ((cfg
->g_ctl
= priv_ctl_create()) == -1)
1004 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
1005 if (lldpd_callback_add(cfg
, cfg
->g_ctl
, ctl_accept
, NULL
) != 0)
1006 fatalx("unable to add callback for control socket");
1009 if (atexit(lldpd_exit
) != 0) {
1012 fatal("unable to set exit function");
1015 /* Signal handling */
1016 signal(SIGHUP
, lldpd_shutdown
);
1017 signal(SIGINT
, lldpd_shutdown
);
1018 signal(SIGTERM
, lldpd_shutdown
);