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>
30 #include <sys/socket.h>
31 #include <sys/select.h>
33 #include <sys/ioctl.h>
34 #include <arpa/inet.h>
35 #include <net/if_arp.h>
37 #if LLDPD_FD_SETSIZE != FD_SETSIZE
38 # warning "FD_SETSIZE is set to an inconsistent value."
42 #include <net-snmp/net-snmp-config.h>
43 #include <net-snmp/net-snmp-includes.h>
44 #include <net-snmp/agent/net-snmp-agent-includes.h>
45 #include <net-snmp/agent/snmp_vars.h>
48 static void usage(void);
50 static struct protocol protos
[] =
52 { LLDPD_MODE_LLDP
, 1, "LLDP", 'l', lldp_send
, lldp_decode
, NULL
,
53 LLDP_MULTICAST_ADDR
},
55 { LLDPD_MODE_CDPV1
, 0, "CDPv1", 'c', cdpv1_send
, cdp_decode
, cdpv1_guess
,
57 { LLDPD_MODE_CDPV2
, 0, "CDPv2", 'c', cdpv2_send
, cdp_decode
, cdpv2_guess
,
61 { LLDPD_MODE_SONMP
, 0, "SONMP", 's', sonmp_send
, sonmp_decode
, NULL
,
62 SONMP_MULTICAST_ADDR
},
65 { LLDPD_MODE_EDP
, 0, "EDP", 'e', edp_send
, edp_decode
, NULL
,
69 { LLDPD_MODE_FDP
, 0, "FDP", 'f', fdp_send
, cdp_decode
, NULL
,
72 { 0, 0, "any", ' ', NULL
, NULL
, NULL
,
76 static void lldpd_update_localchassis(struct lldpd
*);
77 static void lldpd_update_localports(struct lldpd
*);
78 static void lldpd_cleanup(struct lldpd
*);
79 static void lldpd_loop(struct lldpd
*);
80 static void lldpd_shutdown(int);
81 static void lldpd_exit(void);
82 static void lldpd_send_all(struct lldpd
*);
83 static void lldpd_recv_all(struct lldpd
*);
84 static void lldpd_hide_all(struct lldpd
*);
85 static void lldpd_hide_ports(struct lldpd
*, struct lldpd_hardware
*, int);
86 static int lldpd_guess_type(struct lldpd
*, char *, int);
87 static void lldpd_decode(struct lldpd
*, char *, int,
88 struct lldpd_hardware
*);
89 static void lldpd_update_chassis(struct lldpd_chassis
*,
90 const struct lldpd_chassis
*);
91 static char *lldpd_get_lsb_release(void);
93 static void lldpd_med(struct lldpd_chassis
*);
96 static char **saved_argv
;
97 #ifdef HAVE___PROGNAME
98 extern const char *__progname
;
100 # define __progname "lldpd"
106 fprintf(stderr
, "Usage: %s [OPTIONS ...]\n", __progname
);
108 fprintf(stderr
, "\n");
110 fprintf(stderr
, "-d Do not daemonize.\n");
111 fprintf(stderr
, "-r Receive-only mode\n");
112 fprintf(stderr
, "-i Disable LLDP-MED inventory TLV transmission.\n");
113 fprintf(stderr
, "-k Disable advertising of kernel release, version, machine.\n");
114 fprintf(stderr
, "-S descr Override the default system description.\n");
115 fprintf(stderr
, "-m IP Specify the management address of this system.\n");
116 fprintf(stderr
, "-H mode Specify the behaviour when detecting multiple neighbors.\n");
117 #ifdef ENABLE_LLDPMED
118 fprintf(stderr
, "-M class Enable emission of LLDP-MED frame. 'class' should be one of:\n");
119 fprintf(stderr
, " 1 Generic Endpoint (Class I)\n");
120 fprintf(stderr
, " 2 Media Endpoint (Class II)\n");
121 fprintf(stderr
, " 3 Communication Device Endpoints (Class III)\n");
122 fprintf(stderr
, " 4 Network Connectivity Device\n");
125 fprintf(stderr
, "-x Enable SNMP subagent.\n");
127 fprintf(stderr
, "\n");
129 #if defined ENABLE_CDP || defined ENABLE_EDP || defined ENABLE_FDP || defined ENABLE_SONMP
130 fprintf(stderr
, "Additional protocol support.\n");
132 fprintf(stderr
, "-c Enable the support of CDP protocol. (Cisco)\n");
135 fprintf(stderr
, "-e Enable the support of EDP protocol. (Extreme)\n");
138 fprintf(stderr
, "-f Enable the support of FDP protocol. (Foundry)\n");
141 fprintf(stderr
, "-s Enable the support of SONMP protocol. (Nortel)\n");
144 fprintf(stderr
, "\n");
147 fprintf(stderr
, "see manual page lldpd(8) for more information\n");
151 struct lldpd_hardware
*
152 lldpd_get_hardware(struct lldpd
*cfg
, char *name
, int index
, struct lldpd_ops
*ops
)
154 struct lldpd_hardware
*hardware
;
155 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
156 if ((strcmp(hardware
->h_ifname
, name
) == 0) &&
157 (hardware
->h_ifindex
== index
) &&
158 ((!ops
) || (ops
== hardware
->h_ops
)))
164 struct lldpd_hardware
*
165 lldpd_alloc_hardware(struct lldpd
*cfg
, char *name
)
167 struct lldpd_hardware
*hardware
;
169 if ((hardware
= (struct lldpd_hardware
*)
170 calloc(1, sizeof(struct lldpd_hardware
))) == NULL
)
173 strlcpy(hardware
->h_ifname
, name
, sizeof(hardware
->h_ifname
));
174 hardware
->h_lport
.p_chassis
= LOCAL_CHASSIS(cfg
);
175 hardware
->h_lport
.p_chassis
->c_refcount
++;
176 TAILQ_INIT(&hardware
->h_rports
);
178 #ifdef ENABLE_LLDPMED
179 if (LOCAL_CHASSIS(cfg
)->c_med_cap_available
) {
180 hardware
->h_lport
.p_med_cap_enabled
= LLDPMED_CAP_CAP
;
181 if (!cfg
->g_noinventory
)
182 hardware
->h_lport
.p_med_cap_enabled
|= LLDPMED_CAP_IV
;
186 TAILQ_INIT(&hardware
->h_lport
.p_vlans
);
193 lldpd_vlan_cleanup(struct lldpd_port
*port
)
195 struct lldpd_vlan
*vlan
, *vlan_next
;
196 for (vlan
= TAILQ_FIRST(&port
->p_vlans
);
200 vlan_next
= TAILQ_NEXT(vlan
, v_entries
);
201 TAILQ_REMOVE(&port
->p_vlans
, vlan
, v_entries
);
207 /* If `all' is true, clear all information, including information that
208 are not refreshed periodically. Port should be freed manually. */
210 lldpd_port_cleanup(struct lldpd
*cfg
, struct lldpd_port
*port
, int all
)
212 #ifdef ENABLE_LLDPMED
215 for (i
=0; i
< LLDPMED_LOCFORMAT_LAST
; i
++)
216 free(port
->p_med_location
[i
].data
);
219 lldpd_vlan_cleanup(port
);
224 free(port
->p_lastframe
);
225 if (port
->p_chassis
) { /* chassis may not have been attributed, yet */
226 port
->p_chassis
->c_refcount
--;
227 port
->p_chassis
= NULL
;
233 lldpd_chassis_cleanup(struct lldpd_chassis
*chassis
, int all
)
235 #ifdef ENABLE_LLDPMED
236 free(chassis
->c_med_hw
);
237 free(chassis
->c_med_sw
);
238 free(chassis
->c_med_fw
);
239 free(chassis
->c_med_sn
);
240 free(chassis
->c_med_manuf
);
241 free(chassis
->c_med_model
);
242 free(chassis
->c_med_asset
);
245 free(chassis
->c_name
);
246 free(chassis
->c_descr
);
252 lldpd_remote_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int all
)
254 struct lldpd_port
*port
, *port_next
;
256 for (port
= TAILQ_FIRST(&hardware
->h_rports
);
259 port_next
= TAILQ_NEXT(port
, p_entries
);
262 (time(NULL
) - port
->p_lastupdate
> port
->p_chassis
->c_ttl
)) {
263 hardware
->h_rx_ageout_cnt
++;
267 TAILQ_REMOVE(&hardware
->h_rports
, port
, p_entries
);
268 lldpd_port_cleanup(cfg
, port
, 1);
275 lldpd_hardware_cleanup(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
278 lldpd_port_cleanup(cfg
, &hardware
->h_lport
, 1);
279 /* If we have a dedicated cleanup function, use it. Otherwise,
280 we just free the hardware-dependent data and close all FD
281 in h_recvfds and h_sendfd. */
282 if (hardware
->h_ops
->cleanup
)
283 hardware
->h_ops
->cleanup(cfg
, hardware
);
285 free(hardware
->h_data
);
286 for (i
=0; i
< LLDPD_FD_SETSIZE
; i
++)
287 if (FD_ISSET(i
, &hardware
->h_recvfds
))
289 if (hardware
->h_sendfd
) close(hardware
->h_sendfd
);
295 lldpd_cleanup(struct lldpd
*cfg
)
297 struct lldpd_hardware
*hardware
, *hardware_next
;
298 struct lldpd_chassis
*chassis
, *chassis_next
;
300 for (hardware
= TAILQ_FIRST(&cfg
->g_hardware
); hardware
!= NULL
;
301 hardware
= hardware_next
) {
302 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
303 if (!hardware
->h_flags
) {
304 TAILQ_REMOVE(&cfg
->g_hardware
, hardware
, h_entries
);
305 lldpd_remote_cleanup(cfg
, hardware
, 1);
306 lldpd_hardware_cleanup(cfg
, hardware
);
308 lldpd_remote_cleanup(cfg
, hardware
, 0);
311 for (chassis
= TAILQ_FIRST(&cfg
->g_chassis
); chassis
;
312 chassis
= chassis_next
) {
313 chassis_next
= TAILQ_NEXT(chassis
, c_entries
);
314 if (chassis
->c_refcount
== 0) {
315 TAILQ_REMOVE(&cfg
->g_chassis
, chassis
, c_entries
);
316 lldpd_chassis_cleanup(chassis
, 1);
322 lldpd_guess_type(struct lldpd
*cfg
, char *frame
, int s
)
327 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
328 if (!cfg
->g_protocols
[i
].enabled
)
330 if (cfg
->g_protocols
[i
].guess
== NULL
) {
331 if (memcmp(frame
, cfg
->g_protocols
[i
].mac
, ETH_ALEN
) == 0)
332 return cfg
->g_protocols
[i
].mode
;
334 if (cfg
->g_protocols
[i
].guess(frame
, s
))
335 return cfg
->g_protocols
[i
].mode
;
342 lldpd_decode(struct lldpd
*cfg
, char *frame
, int s
,
343 struct lldpd_hardware
*hardware
)
346 struct lldpd_chassis
*chassis
, *ochassis
= NULL
;
347 struct lldpd_port
*port
, *oport
= NULL
;
348 int guess
= LLDPD_MODE_LLDP
;
350 if (s
< sizeof(struct ethhdr
) + 4)
351 /* Too short, just discard it */
353 /* Decapsulate VLAN frames */
354 if (((struct ethhdr
*)frame
)->h_proto
== htons(ETHERTYPE_VLAN
)) {
355 /* VLAN decapsulation means to shift 4 bytes left the frame from
356 * offset 2*ETH_ALEN */
357 memmove(frame
+ 2*ETH_ALEN
, frame
+ 2*ETH_ALEN
+ 4, s
- 2*ETH_ALEN
);
361 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
362 if ((oport
->p_lastframe
!= NULL
) &&
363 (oport
->p_lastframe
->size
== s
) &&
364 (memcmp(oport
->p_lastframe
->frame
, frame
, s
) == 0)) {
365 /* Already received the same frame */
366 oport
->p_lastupdate
= time(NULL
);
371 guess
= lldpd_guess_type(cfg
, frame
, s
);
372 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
373 if (!cfg
->g_protocols
[i
].enabled
)
375 if (cfg
->g_protocols
[i
].mode
== guess
) {
376 if ((result
= cfg
->g_protocols
[i
].decode(cfg
, frame
,
377 s
, hardware
, &chassis
, &port
)) == -1)
379 chassis
->c_protocol
= port
->p_protocol
=
380 cfg
->g_protocols
[i
].mode
;
384 if (cfg
->g_protocols
[i
].mode
== 0) {
385 LLOG_INFO("unable to guess frame type");
389 /* Do we already have the same MSAP somewhere? */
390 TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
) {
391 if ((port
->p_protocol
== oport
->p_protocol
) &&
392 (port
->p_id_subtype
== oport
->p_id_subtype
) &&
393 (port
->p_id_len
== oport
->p_id_len
) &&
394 (memcmp(port
->p_id
, oport
->p_id
, port
->p_id_len
) == 0) &&
395 (chassis
->c_id_subtype
== oport
->p_chassis
->c_id_subtype
) &&
396 (chassis
->c_id_len
== oport
->p_chassis
->c_id_len
) &&
397 (memcmp(chassis
->c_id
, oport
->p_chassis
->c_id
,
398 chassis
->c_id_len
) == 0)) {
399 ochassis
= oport
->p_chassis
;
403 /* No, but do we already know the system? */
405 TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) {
406 if ((chassis
->c_protocol
== ochassis
->c_protocol
) &&
407 (chassis
->c_id_subtype
== ochassis
->c_id_subtype
) &&
408 (chassis
->c_id_len
== ochassis
->c_id_len
) &&
409 (memcmp(chassis
->c_id
, ochassis
->c_id
,
410 chassis
->c_id_len
) == 0))
416 /* The port is known, remove it before adding it back */
417 TAILQ_REMOVE(&hardware
->h_rports
, oport
, p_entries
);
418 lldpd_port_cleanup(cfg
, oport
, 1);
422 lldpd_update_chassis(ochassis
, chassis
);
426 /* Chassis not known, add it */
427 chassis
->c_index
= ++cfg
->g_lastrid
;
428 chassis
->c_refcount
= 0;
429 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, chassis
, c_entries
);
430 i
= 0; TAILQ_FOREACH(ochassis
, &cfg
->g_chassis
, c_entries
) i
++;
431 LLOG_DEBUG("Currently, we know %d different systems", i
);
434 port
->p_lastchange
= port
->p_lastupdate
= time(NULL
);
435 if ((port
->p_lastframe
= (struct lldpd_frame
*)malloc(s
+
436 sizeof(int))) != NULL
) {
437 port
->p_lastframe
->size
= s
;
438 memcpy(port
->p_lastframe
->frame
, frame
, s
);
440 TAILQ_INSERT_TAIL(&hardware
->h_rports
, port
, p_entries
);
441 port
->p_chassis
= chassis
;
442 port
->p_chassis
->c_refcount
++;
443 /* Several cases are possible :
444 1. chassis is new, its refcount was 0. It is now attached
445 to this port, its refcount is 1.
446 2. chassis already exists and was attached to another
447 port, we increase its refcount accordingly.
448 3. chassis already exists and was attached to the same
449 port, its refcount was decreased with
450 lldpd_port_cleanup() and is now increased again.
452 In all cases, if the port already existed, it has been
453 freed with lldpd_port_cleanup() and therefore, the refcount
454 of the chassis that was attached to it is decreased.
456 i
= 0; TAILQ_FOREACH(oport
, &hardware
->h_rports
, p_entries
)
458 LLOG_DEBUG("Currently, %s knows %d neighbors",
459 hardware
->h_ifname
, i
);
463 /* Update chassis `ochassis' with values from `chassis'. */
465 lldpd_update_chassis(struct lldpd_chassis
*ochassis
,
466 const struct lldpd_chassis
*chassis
) {
467 TAILQ_ENTRY(lldpd_chassis
) entries
;
468 /* We want to keep refcount, index and list stuff from the current
470 int refcount
= ochassis
->c_refcount
;
471 int index
= ochassis
->c_index
;
472 memcpy(&entries
, &ochassis
->c_entries
,
475 lldpd_chassis_cleanup(ochassis
, 0);
476 memcpy(ochassis
, chassis
, sizeof(struct lldpd_chassis
));
477 /* Restore saved values */
478 ochassis
->c_refcount
= refcount
;
479 ochassis
->c_index
= index
;
480 memcpy(&ochassis
->c_entries
, &entries
, sizeof(entries
));
483 /* Get the output of lsb_release -s -d. This is a slow function. It should be
484 called once. It return NULL if any problem happens. Otherwise, this is a
485 statically allocated buffer. The result includes the trailing \n */
487 lldpd_get_lsb_release() {
488 static char release
[1024];
489 char *const command
[] = { "lsb_release", "-s", "-d", NULL
};
490 int pid
, status
, devnull
, count
;
494 LLOG_WARN("unable to get a pair of pipes");
498 if ((pid
= fork()) < 0) {
499 LLOG_WARN("unable to fork");
504 /* Child, exec lsb_release */
506 if ((devnull
= open("/dev/null", O_RDWR
, 0)) != -1) {
507 dup2(devnull
, STDIN_FILENO
);
508 dup2(devnull
, STDERR_FILENO
);
509 dup2(pipefd
[1], STDOUT_FILENO
);
510 if (devnull
> 2) close(devnull
);
511 if (pipefd
[1] > 2) close(pipefd
[1]);
512 execvp("lsb_release", command
);
517 /* Father, read the output from the children */
521 status
= read(pipefd
[0], release
+count
, sizeof(release
)-count
);
522 if ((status
== -1) && (errno
== EINTR
)) continue;
525 } while (count
< sizeof(release
) && (status
> 0));
527 LLOG_WARN("unable to read from lsb_release");
529 waitpid(pid
, &status
, 0);
533 if (count
>= sizeof(release
)) {
534 LLOG_INFO("output of lsb_release is too large");
535 waitpid(pid
, &status
, 0);
539 if (waitpid(pid
, &status
, 0) != pid
)
541 if (!WIFEXITED(status
) || (WEXITSTATUS(status
) != 0)) {
542 LLOG_INFO("lsb_release information not available");
546 LLOG_INFO("lsb_release returned an empty string");
549 release
[count
] = '\0';
552 /* Should not be here */
557 lldpd_callback_add(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
), void *data
)
559 struct lldpd_callback
*callback
;
560 if ((callback
= (struct lldpd_callback
*)
561 malloc(sizeof(struct lldpd_callback
))) == NULL
)
564 callback
->function
= fn
;
565 callback
->data
= data
;
566 TAILQ_INSERT_TAIL(&cfg
->g_callbacks
, callback
, next
);
571 lldpd_callback_del(struct lldpd
*cfg
, int fd
, void(*fn
)(CALLBACK_SIG
))
573 struct lldpd_callback
*callback
, *callback_next
;
574 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
576 callback
= callback_next
) {
577 callback_next
= TAILQ_NEXT(callback
, next
);
578 if ((callback
->fd
== fd
) &&
579 (callback
->function
= fn
)) {
580 free(callback
->data
);
581 TAILQ_REMOVE(&cfg
->g_callbacks
, callback
, next
);
587 /* Hide unwanted ports depending on smart mode set by the user */
589 lldpd_hide_all(struct lldpd
*cfg
)
591 struct lldpd_hardware
*hardware
;
595 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
596 if (cfg
->g_smart
& SMART_INCOMING_FILTER
)
597 lldpd_hide_ports(cfg
, hardware
, SMART_INCOMING
);
598 if (cfg
->g_smart
& SMART_OUTGOING_FILTER
)
599 lldpd_hide_ports(cfg
, hardware
, SMART_OUTGOING
);
604 lldpd_hide_ports(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
, int mask
) {
605 struct lldpd_port
*port
;
606 int protocols
[LLDPD_MODE_MAX
+1];
611 /* Compute the number of occurrences of each protocol */
612 for (i
= 0; i
<= LLDPD_MODE_MAX
; i
++) protocols
[i
] = 0;
613 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
)
614 protocols
[port
->p_protocol
]++;
616 /* Turn the protocols[] array into an array of
617 enabled/disabled protocols. 1 means enabled, 0
619 min
= (unsigned int)-1;
620 for (i
= 0; i
<= LLDPD_MODE_MAX
; i
++)
621 if (protocols
[i
] && (protocols
[i
] < min
))
624 for (i
= 0; i
<= LLDPD_MODE_MAX
; i
++)
625 if ((protocols
[i
] == min
) && !found
) {
626 /* If we need a tie breaker, we take
627 the first protocol only */
628 if (cfg
->g_smart
& mask
&
629 (SMART_OUTGOING_ONE_PROTO
| SMART_INCOMING_ONE_PROTO
))
632 } else protocols
[i
] = 0;
634 /* We set the p_hidden flag to 1 if the protocol is disabled */
635 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
636 if (mask
== SMART_OUTGOING
)
637 port
->p_hidden_out
= protocols
[port
->p_protocol
]?0:1;
639 port
->p_hidden_in
= protocols
[port
->p_protocol
]?0:1;
642 /* If we want only one neighbor, we take the first one */
643 if (cfg
->g_smart
& mask
&
644 (SMART_OUTGOING_ONE_NEIGH
| SMART_INCOMING_ONE_NEIGH
)) {
646 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
647 if (mask
== SMART_OUTGOING
) {
648 if (found
) port
->p_hidden_out
= 1;
649 if (!port
->p_hidden_out
)
652 if (mask
== SMART_INCOMING
) {
653 if (found
) port
->p_hidden_in
= 1;
654 if (!port
->p_hidden_in
)
660 /* Print a debug message summarizing the operation */
661 for (i
= 0; i
<= LLDPD_MODE_MAX
; i
++) protocols
[i
] = 0;
663 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
664 if (!(((mask
== SMART_OUTGOING
) && port
->p_hidden_out
) ||
665 ((mask
== SMART_INCOMING
) && port
->p_hidden_in
))) {
667 protocols
[port
->p_protocol
] = 1;
672 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
673 if (cfg
->g_protocols
[i
].enabled
&& protocols
[cfg
->g_protocols
[i
].mode
]) {
675 strlen(cfg
->g_protocols
[i
].name
) + 3 > sizeof(buffer
)) {
676 /* Unlikely, our buffer is too small */
677 memcpy(buffer
+ sizeof(buffer
) - 4, "...", 4);
681 strcat(buffer
, ", ");
682 strcat(buffer
, cfg
->g_protocols
[i
].name
);
685 LLOG_DEBUG("[%s] %s: %d visible neigh / %d. Protocols: %s.",
686 (mask
== SMART_OUTGOING
)?"out filter":"in filter",
687 hardware
->h_ifname
, k
, j
, buffer
[0]?buffer
:"(none)");
691 lldpd_recv_all(struct lldpd
*cfg
)
693 struct lldpd_hardware
*hardware
;
694 struct lldpd_callback
*callback
, *callback_next
;
698 struct timeval snmptv
;
705 tv
.tv_sec
= cfg
->g_delay
- (time(NULL
) - cfg
->g_lastsent
);
707 tv
.tv_sec
= LLDPD_TX_DELAY
;
708 if (tv
.tv_sec
>= cfg
->g_delay
)
709 tv
.tv_sec
= cfg
->g_delay
;
715 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
716 /* Ignore if interface is down */
717 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
719 /* This is quite expensive but we don't rely on internal
720 * structure of fd_set. */
721 for (n
= 0; n
< LLDPD_FD_SETSIZE
; n
++)
722 if (FD_ISSET(n
, &hardware
->h_recvfds
)) {
728 TAILQ_FOREACH(callback
, &cfg
->g_callbacks
, next
) {
729 FD_SET(callback
->fd
, &rfds
);
730 if (nfds
< callback
->fd
)
737 memcpy(&snmptv
, &tv
, sizeof(struct timeval
));
738 snmp_select_info(&nfds
, &rfds
, &snmptv
, &snmpblock
);
740 memcpy(&tv
, &snmptv
, sizeof(struct timeval
));
742 #endif /* USE_SNMP */
748 rc
= select(nfds
+ 1, &rfds
, NULL
, NULL
, &tv
);
752 LLOG_WARN("failure on select");
762 #endif /* USE_SNMP */
763 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
764 for (n
= 0; n
< LLDPD_FD_SETSIZE
; n
++)
765 if ((FD_ISSET(n
, &hardware
->h_recvfds
)) &&
766 (FD_ISSET(n
, &rfds
))) break;
767 if (n
== LLDPD_FD_SETSIZE
) continue;
768 if ((buffer
= (char *)malloc(
769 hardware
->h_mtu
)) == NULL
) {
770 LLOG_WARN("failed to alloc reception buffer");
773 if ((n
= hardware
->h_ops
->recv(cfg
, hardware
,
774 n
, buffer
, hardware
->h_mtu
)) == -1) {
778 hardware
->h_rx_cnt
++;
779 lldpd_decode(cfg
, buffer
, n
, hardware
);
780 lldpd_hide_all(cfg
); /* Immediatly hide */
784 for (callback
= TAILQ_FIRST(&cfg
->g_callbacks
);
786 callback
= callback_next
) {
787 /* Callback function can use TAILQ_REMOVE */
788 callback_next
= TAILQ_NEXT(callback
, next
);
789 if (FD_ISSET(callback
->fd
, &rfds
))
790 callback
->function(cfg
, callback
);
796 netsnmp_check_outstanding_agent_requests();
798 #endif /* USE_SNMP */
799 } while ((rc
!= 0) || (time(NULL
) - cfg
->g_lastsent
< cfg
->g_delay
));
803 lldpd_send_all(struct lldpd
*cfg
)
805 struct lldpd_hardware
*hardware
;
806 struct lldpd_port
*port
;
809 cfg
->g_lastsent
= time(NULL
);
810 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
811 /* Ignore if interface is down */
812 if ((hardware
->h_flags
& IFF_RUNNING
) == 0)
816 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
817 if (!cfg
->g_protocols
[i
].enabled
)
819 /* We send only if we have at least one remote system
820 * speaking this protocol or if the protocol is forced */
821 if (cfg
->g_protocols
[i
].enabled
> 1) {
822 cfg
->g_protocols
[i
].send(cfg
, hardware
);
826 TAILQ_FOREACH(port
, &hardware
->h_rports
, p_entries
) {
827 /* If this remote port is disabled, we don't
829 if (port
->p_hidden_out
&&
830 (cfg
->g_smart
& SMART_OUTGOING_FILTER
))
832 if (port
->p_protocol
==
833 cfg
->g_protocols
[i
].mode
) {
834 cfg
->g_protocols
[i
].send(cfg
,
843 /* Nothing was sent for this port, let's speak LLDP */
844 cfg
->g_protocols
[0].send(cfg
,
849 #ifdef ENABLE_LLDPMED
851 lldpd_med(struct lldpd_chassis
*chassis
)
853 free(chassis
->c_med_hw
);
854 free(chassis
->c_med_fw
);
855 free(chassis
->c_med_sn
);
856 free(chassis
->c_med_manuf
);
857 free(chassis
->c_med_model
);
858 free(chassis
->c_med_asset
);
859 chassis
->c_med_hw
= dmi_hw();
860 chassis
->c_med_fw
= dmi_fw();
861 chassis
->c_med_sn
= dmi_sn();
862 chassis
->c_med_manuf
= dmi_manuf();
863 chassis
->c_med_model
= dmi_model();
864 chassis
->c_med_asset
= dmi_asset();
869 lldpd_update_localchassis(struct lldpd
*cfg
)
875 struct lldpd_hardware
*hardware
;
877 /* Set system name and description */
879 fatal("failed to get system information");
880 if ((hp
= priv_gethostbyname()) == NULL
)
881 fatal("failed to get system name");
882 free(LOCAL_CHASSIS(cfg
)->c_name
);
883 free(LOCAL_CHASSIS(cfg
)->c_descr
);
884 if ((LOCAL_CHASSIS(cfg
)->c_name
= strdup(hp
)) == NULL
)
886 if (cfg
->g_descr_override
) {
887 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s",
888 cfg
->g_descr_override
) == -1)
889 fatal("failed to set full system description");
891 if (cfg
->g_advertise_version
) {
892 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s%s %s %s",
893 cfg
->g_lsb_release
?cfg
->g_lsb_release
:"",
894 un
.sysname
, un
.release
, un
.machine
)
896 fatal("failed to set full system description");
898 if (asprintf(&LOCAL_CHASSIS(cfg
)->c_descr
, "%s",
899 cfg
->g_lsb_release
?cfg
->g_lsb_release
:un
.sysname
) == -1)
900 fatal("failed to set minimal system description");
904 /* Check forwarding */
905 if ((f
= priv_open("/proc/sys/net/ipv4/ip_forward")) >= 0) {
906 if ((read(f
, &status
, 1) == 1) && (status
== '1'))
907 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_ROUTER
;
909 LOCAL_CHASSIS(cfg
)->c_cap_enabled
&= ~LLDP_CAP_ROUTER
;
912 #ifdef ENABLE_LLDPMED
913 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_TELEPHONE
)
914 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_TELEPHONE
;
915 lldpd_med(LOCAL_CHASSIS(cfg
));
916 free(LOCAL_CHASSIS(cfg
)->c_med_sw
);
917 if (cfg
->g_advertise_version
)
918 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup(un
.release
);
920 LOCAL_CHASSIS(cfg
)->c_med_sw
= strdup("Unknown");
923 /* Set chassis ID if needed */
924 if ((LOCAL_CHASSIS(cfg
)->c_id
== NULL
) &&
925 (hardware
= TAILQ_FIRST(&cfg
->g_hardware
))) {
926 if ((LOCAL_CHASSIS(cfg
)->c_id
=
927 malloc(sizeof(hardware
->h_lladdr
))) == NULL
)
929 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
930 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
931 memcpy(LOCAL_CHASSIS(cfg
)->c_id
,
932 hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
937 lldpd_update_localports(struct lldpd
*cfg
)
939 struct ifaddrs
*ifap
;
940 struct lldpd_hardware
*hardware
;
941 lldpd_ifhandlers ifhs
[] = {
942 lldpd_ifh_bond
, /* Handle bond */
943 lldpd_ifh_eth
, /* Handle classic ethernet interfaces */
945 lldpd_ifh_vlan
, /* Handle VLAN */
947 lldpd_ifh_mgmt
, /* Handle management address (if not already handled) */
950 lldpd_ifhandlers
*ifh
;
952 /* h_flags is set to 0 for each port. If the port is updated, h_flags
953 * will be set to a non-zero value. This will allow us to clean up any
954 * non up-to-date port */
955 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
)
956 hardware
->h_flags
= 0;
958 LOCAL_CHASSIS(cfg
)->c_mgmt
.s_addr
= INADDR_ANY
;
959 if (getifaddrs(&ifap
) != 0)
960 fatal("lldpd_update_localports: failed to get interface list");
962 /* We will run the list of interfaces through a list of interface
963 * handlers. Each handler will create or update some hardware port (and
964 * will set h_flags to a non zero value. The handler can use the list of
965 * interfaces but this is not mandatory. If the interface handler
966 * handles an interface from the list, it should set ifa_flags to 0 to
967 * let know the other handlers that it took care of this interface. This
968 * means that more specific handlers should be before less specific
970 for (ifh
= ifhs
; *ifh
!= NULL
; ifh
++)
976 lldpd_loop(struct lldpd
*cfg
)
980 1. Update local ports information
981 2. Clean unwanted (removed) local ports
982 3. Update local chassis information
987 LOCAL_CHASSIS(cfg
)->c_cap_enabled
= 0;
988 lldpd_update_localports(cfg
);
990 lldpd_update_localchassis(cfg
);
991 if (!cfg
->g_receiveonly
)
997 lldpd_shutdown(int sig
)
999 LLOG_INFO("signal received, exiting");
1003 /* For signal handling */
1004 static struct lldpd
*gcfg
= NULL
;
1009 struct lldpd_hardware
*hardware
, *hardware_next
;
1012 for (hardware
= TAILQ_FIRST(&gcfg
->g_hardware
); hardware
!= NULL
;
1013 hardware
= hardware_next
) {
1014 hardware_next
= TAILQ_NEXT(hardware
, h_entries
);
1015 lldpd_hardware_cleanup(gcfg
, hardware
);
1020 #endif /* USE_SNMP */
1023 struct intint
{ int a
; int b
; };
1024 static const struct intint filters
[] = {
1026 { 1, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_PROTO
|
1027 SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_PROTO
},
1028 { 2, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_PROTO
},
1029 { 3, SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_PROTO
},
1030 { 4, SMART_INCOMING_FILTER
| SMART_OUTGOING_FILTER
},
1031 { 5, SMART_INCOMING_FILTER
},
1032 { 6, SMART_OUTGOING_FILTER
},
1033 { 7, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_PROTO
| SMART_INCOMING_ONE_NEIGH
|
1034 SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_PROTO
},
1035 { 8, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_PROTO
| SMART_INCOMING_ONE_NEIGH
},
1036 { 9, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_NEIGH
|
1037 SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_PROTO
},
1038 { 10, SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_NEIGH
},
1039 { 11, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_NEIGH
},
1040 { 12, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_NEIGH
|
1041 SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_NEIGH
},
1042 { 13, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_NEIGH
|
1043 SMART_OUTGOING_FILTER
},
1044 { 14, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_PROTO
|
1045 SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_NEIGH
},
1046 { 15, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_PROTO
|
1047 SMART_OUTGOING_FILTER
},
1048 { 16, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_PROTO
| SMART_INCOMING_ONE_NEIGH
|
1049 SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_NEIGH
},
1050 { 17, SMART_INCOMING_FILTER
| SMART_INCOMING_ONE_PROTO
| SMART_INCOMING_ONE_NEIGH
|
1051 SMART_OUTGOING_FILTER
},
1052 { 18, SMART_INCOMING_FILTER
|
1053 SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_NEIGH
},
1054 { 19, SMART_INCOMING_FILTER
|
1055 SMART_OUTGOING_FILTER
| SMART_OUTGOING_ONE_PROTO
},
1060 lldpd_main(int argc
, char *argv
[])
1063 struct lldpd_chassis
*lchassis
;
1067 char *agentx
= NULL
; /* AgentX socket */
1070 char *popt
, opts
[] =
1071 "H:hkrdxX:m:p:M:S:i@ ";
1072 int i
, found
, advertise_version
= 1;
1073 #ifdef ENABLE_LLDPMED
1074 int lldpmed
= 0, noinventory
= 0;
1076 char *descr_override
= NULL
;
1077 char *lsb_release
= NULL
;
1079 int receiveonly
= 0;
1084 * Get and parse command line options
1086 popt
= strchr(opts
, '@');
1087 for (i
=0; protos
[i
].mode
!= 0; i
++)
1088 *(popt
++) = protos
[i
].arg
;
1090 while ((ch
= getopt(argc
, argv
, opts
)) != -1) {
1105 advertise_version
= 0;
1107 #ifdef ENABLE_LLDPMED
1109 lldpmed
= atoi(optarg
);
1110 if ((lldpmed
< 1) || (lldpmed
> 4)) {
1111 fprintf(stderr
, "-M requires an argument between 1 and 4\n");
1122 fprintf(stderr
, "LLDP-MED support is not built-in\n");
1137 fprintf(stderr
, "SNMP support is not built-in\n");
1142 descr_override
= strdup(optarg
);
1145 smart
= atoi(optarg
);
1149 for (i
=0; protos
[i
].mode
!= 0; i
++) {
1150 if (ch
== protos
[i
].arg
) {
1151 protos
[i
].enabled
++;
1152 /* When an argument enable
1153 several protocols, only the
1154 first one can be forced. */
1155 if (found
&& protos
[i
].enabled
> 1)
1156 protos
[i
].enabled
= 1;
1165 /* Set correct smart mode */
1166 for (i
=0; (filters
[i
].a
!= -1) && (filters
[i
].a
!= smart
); i
++);
1167 if (filters
[i
].a
== -1) {
1168 fprintf(stderr
, "Incorrect mode for -H\n");
1171 smart
= filters
[i
].b
;
1173 log_init(debug
, __progname
);
1174 tzset(); /* Get timezone info before chroot */
1179 if (daemon(0, 0) != 0)
1180 fatal("failed to detach daemon");
1181 if ((pid
= open(LLDPD_PID_FILE
,
1182 O_TRUNC
| O_CREAT
| O_WRONLY
, 0644)) == -1)
1183 fatal("unable to open pid file " LLDPD_PID_FILE
);
1184 if (asprintf(&spid
, "%d\n", getpid()) == -1)
1185 fatal("unable to create pid file " LLDPD_PID_FILE
);
1186 if (write(pid
, spid
, strlen(spid
)) == -1)
1187 fatal("unable to write pid file " LLDPD_PID_FILE
);
1192 lsb_release
= lldpd_get_lsb_release();
1194 priv_init(PRIVSEP_CHROOT
);
1196 if ((cfg
= (struct lldpd
*)
1197 calloc(1, sizeof(struct lldpd
))) == NULL
)
1200 cfg
->g_mgmt_pattern
= mgmtp
;
1201 cfg
->g_smart
= smart
;
1202 cfg
->g_receiveonly
= receiveonly
;
1204 /* Get ioctl socket */
1205 if ((cfg
->g_sock
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1)
1206 fatal("failed to get ioctl socket");
1207 cfg
->g_delay
= LLDPD_TX_DELAY
;
1210 if (!(cfg
->g_advertise_version
= advertise_version
))
1212 lsb_release
[strlen(lsb_release
) - 1] = '\0';
1213 cfg
->g_lsb_release
= lsb_release
;
1215 cfg
->g_descr_override
= descr_override
;
1217 /* Set system capabilities */
1218 if ((lchassis
= (struct lldpd_chassis
*)
1219 calloc(1, sizeof(struct lldpd_chassis
))) == NULL
)
1221 lchassis
->c_cap_available
= LLDP_CAP_BRIDGE
| LLDP_CAP_WLAN
|
1223 #ifdef ENABLE_LLDPMED
1225 if (lldpmed
== LLDPMED_CLASS_III
)
1226 lchassis
->c_cap_available
|= LLDP_CAP_TELEPHONE
;
1227 lchassis
->c_med_type
= lldpmed
;
1228 lchassis
->c_med_cap_available
= LLDPMED_CAP_CAP
|
1229 LLDPMED_CAP_IV
| LLDPMED_CAP_LOCATION
|
1230 LLDPMED_CAP_POLICY
| LLDPMED_CAP_MDI_PSE
| LLDPMED_CAP_MDI_PD
;
1231 cfg
->g_noinventory
= noinventory
;
1233 cfg
->g_noinventory
= 1;
1237 lchassis
->c_ttl
= LLDPD_TTL
;
1239 cfg
->g_protocols
= protos
;
1240 for (i
=0; protos
[i
].mode
!= 0; i
++)
1241 if (protos
[i
].enabled
> 1)
1242 LLOG_INFO("protocol %s enabled and forced", protos
[i
].name
);
1243 else if (protos
[i
].enabled
)
1244 LLOG_INFO("protocol %s enabled", protos
[i
].name
);
1246 LLOG_INFO("protocol %s disabled", protos
[i
].name
);
1248 TAILQ_INIT(&cfg
->g_hardware
);
1249 TAILQ_INIT(&cfg
->g_chassis
);
1250 TAILQ_INSERT_TAIL(&cfg
->g_chassis
, lchassis
, c_entries
);
1251 lchassis
->c_refcount
++; /* We should always keep a reference to local chassis */
1253 TAILQ_INIT(&cfg
->g_callbacks
);
1258 agent_init(cfg
, agentx
, debug
);
1260 #endif /* USE_SNMP */
1263 if ((cfg
->g_ctl
= priv_ctl_create()) == -1)
1264 fatalx("unable to create control socket " LLDPD_CTL_SOCKET
);
1265 if (lldpd_callback_add(cfg
, cfg
->g_ctl
, ctl_accept
, NULL
) != 0)
1266 fatalx("unable to add callback for control socket");
1269 if (atexit(lldpd_exit
) != 0) {
1272 fatal("unable to set exit function");
1275 /* Signal handling */
1276 signal(SIGHUP
, lldpd_shutdown
);
1277 signal(SIGINT
, lldpd_shutdown
);
1278 signal(SIGTERM
, lldpd_shutdown
);