2 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
4 * Permission to use, copy, modify, and/or 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.
17 #define INCLUDE_LINUX_IF_H
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
30 #include <arpa/inet.h>
31 #include <net/if_arp.h>
32 #include <linux/if_vlan.h>
33 #include <linux/if_bonding.h>
34 #include <linux/if_bridge.h>
35 #include <linux/wireless.h>
36 #include <linux/sockios.h>
37 #include <linux/filter.h>
38 #include <linux/if_packet.h>
40 #define SYSFS_PATH_MAX 256
41 #define MAX_PORTS 1024
42 #define MAX_BRIDGES 1024
44 /* BPF filter to get revelant information from interfaces */
45 /* LLDP: "ether proto 0x88cc and ether dst 01:80:c2:00:00:0e" */
46 /* FDP: "ether dst 01:e0:52:cc:cc:cc" */
47 /* CDP: "ether dst 01:00:0c:cc:cc:cc" */
48 /* SONMP: "ether dst 01:00:81:00:01:00" */
49 /* EDP: "ether dst 00:e0:2b:00:00:00" */
50 /* For optimization purpose, we first check if the first bit of the
51 first byte is 1. if not, this can only be an EDP packet:
53 tcpdump -dd "(ether[0] & 1 = 1 and
54 ((ether proto 0x88cc and ether dst 01:80:c2:00:00:0e) or
55 (ether dst 01:e0:52:cc:cc:cc) or
56 (ether dst 01:00:0c:cc:cc:cc) or
57 (ether dst 01:00:81:00:01:00))) or
58 (ether dst 00:e0:2b:00:00:00)"
61 #define LLDPD_FILTER_F \
62 { 0x30, 0, 0, 0x00000000 }, \
63 { 0x54, 0, 0, 0x00000001 }, \
64 { 0x15, 0, 14, 0x00000001 }, \
65 { 0x28, 0, 0, 0x0000000c }, \
66 { 0x15, 0, 4, 0x000088cc }, \
67 { 0x20, 0, 0, 0x00000002 }, \
68 { 0x15, 0, 2, 0xc200000e }, \
69 { 0x28, 0, 0, 0x00000000 }, \
70 { 0x15, 12, 13, 0x00000180 }, \
71 { 0x20, 0, 0, 0x00000002 }, \
72 { 0x15, 0, 2, 0x52cccccc }, \
73 { 0x28, 0, 0, 0x00000000 }, \
74 { 0x15, 8, 9, 0x000001e0 }, \
75 { 0x15, 1, 0, 0x0ccccccc }, \
76 { 0x15, 0, 2, 0x81000100 }, \
77 { 0x28, 0, 0, 0x00000000 }, \
78 { 0x15, 4, 5, 0x00000100 }, \
79 { 0x20, 0, 0, 0x00000002 }, \
80 { 0x15, 0, 3, 0x2b000000 }, \
81 { 0x28, 0, 0, 0x00000000 }, \
82 { 0x15, 0, 1, 0x000000e0 }, \
83 { 0x6, 0, 0, 0x0000ffff }, \
84 { 0x6, 0, 0, 0x00000000 },
86 static struct sock_filter lldpd_filter_f
[] = { LLDPD_FILTER_F
};
89 extern unsigned int if_nametoindex (__const
char *__ifname
) __THROW
;
90 extern char *if_indextoname (unsigned int __ifindex
, char *__ifname
) __THROW
;
92 struct lldpd_ops eth_ops
;
93 struct lldpd_ops bond_ops
;
96 pattern_match(char *iface
, char *list
, int found
)
98 char *interfaces
= NULL
;
101 if ((interfaces
= strdup(list
)) == NULL
) {
102 LLOG_WARNX("unable to allocate memory");
106 for (pattern
= strtok(interfaces
, ",");
108 pattern
= strtok(NULL
, ",")) {
109 if ((pattern
[0] == '!') &&
110 ((fnmatch(pattern
+ 1, iface
, 0) == 0))) {
111 /* Blacklisted. No need to search further. */
115 if (fnmatch(pattern
, iface
, 0) == 0)
124 old_iface_is_bridge(struct lldpd
*cfg
, const char *name
)
126 int ifindices
[MAX_BRIDGES
];
127 char ifname
[IFNAMSIZ
];
129 unsigned long args
[3] = { BRCTL_GET_BRIDGES
,
130 (unsigned long)ifindices
, MAX_BRIDGES
};
131 if ((num
= ioctl(cfg
->g_sock
, SIOCGIFBR
, args
)) < 0)
132 /* This can happen with a 64bit kernel and 32bit
133 userland, don't output anything about this to avoid
136 for (i
= 0; i
< num
; i
++) {
137 if (if_indextoname(ifindices
[i
], ifname
) == NULL
)
138 LLOG_INFO("unable to get name of interface %d",
140 else if (strncmp(name
, ifname
, IFNAMSIZ
) == 0)
147 iface_is_bridge(struct lldpd
*cfg
, const char *name
)
149 #ifdef SYSFS_BRIDGE_FDB
150 char path
[SYSFS_PATH_MAX
];
153 if ((snprintf(path
, SYSFS_PATH_MAX
,
154 SYSFS_CLASS_NET
"%s/" SYSFS_BRIDGE_FDB
, name
)) >= SYSFS_PATH_MAX
)
155 LLOG_WARNX("path truncated");
156 if ((f
= priv_open(path
)) < 0) {
157 return old_iface_is_bridge(cfg
, name
);
162 return old_iface_is_bridge(cfg
, name
);
168 old_iface_is_bridged_to(struct lldpd
*cfg
, const char *slave
, const char *master
)
170 int j
, index
= if_nametoindex(slave
);
171 int ifptindices
[MAX_PORTS
];
172 unsigned long args2
[4] = { BRCTL_GET_PORT_LIST
,
173 (unsigned long)ifptindices
, MAX_PORTS
, 0 };
176 strncpy(ifr
.ifr_name
, master
, IFNAMSIZ
);
177 memset(ifptindices
, 0, sizeof(ifptindices
));
178 ifr
.ifr_data
= (char *)&args2
;
180 if (ioctl(cfg
->g_sock
, SIOCDEVPRIVATE
, &ifr
) < 0)
181 /* This can happen with a 64bit kernel and 32bit
182 userland, don't output anything about this to avoid
186 for (j
= 0; j
< MAX_PORTS
; j
++) {
187 if (ifptindices
[j
] == index
)
195 iface_is_bridged_to(struct lldpd
*cfg
, const char *slave
, const char *master
)
197 #ifdef SYSFS_BRIDGE_PORT_SUBDIR
198 char path
[SYSFS_PATH_MAX
];
201 /* Master should be a bridge, first */
202 if (!iface_is_bridge(cfg
, master
)) return 0;
204 if (snprintf(path
, SYSFS_PATH_MAX
,
205 SYSFS_CLASS_NET
"%s/" SYSFS_BRIDGE_PORT_SUBDIR
"/%s/port_no",
206 master
, slave
) >= SYSFS_PATH_MAX
)
207 LLOG_WARNX("path truncated");
208 if ((f
= priv_open(path
)) < 0) {
209 return old_iface_is_bridged_to(cfg
, slave
, master
);
214 return old_iface_is_bridged_to(cfg
, slave
, master
);
220 iface_is_vlan(struct lldpd
*cfg
, const char *name
)
222 struct vlan_ioctl_args ifv
;
223 memset(&ifv
, 0, sizeof(ifv
));
224 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
225 if ((strlcpy(ifv
.device1
, name
, sizeof(ifv
.device1
))) >=
227 LLOG_WARNX("device name truncated");
228 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0)
234 iface_is_wireless(struct lldpd
*cfg
, const char *name
)
237 strlcpy(iwr
.ifr_name
, name
, IFNAMSIZ
);
238 if (ioctl(cfg
->g_sock
, SIOCGIWNAME
, &iwr
) >= 0)
244 iface_is_bond(struct lldpd
*cfg
, const char *name
)
248 memset(&ifr
, 0, sizeof(ifr
));
249 memset(&ifb
, 0, sizeof(ifb
));
250 strlcpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
251 ifr
.ifr_data
= (char *)&ifb
;
252 if (ioctl(cfg
->g_sock
, SIOCBONDINFOQUERY
, &ifr
) >= 0)
258 iface_is_bond_slave(struct lldpd
*cfg
, const char *slave
, const char *master
,
264 memset(&ifr
, 0, sizeof(ifr
));
265 memset(&ifb
, 0, sizeof(ifb
));
266 strlcpy(ifr
.ifr_name
, master
, sizeof(ifr
.ifr_name
));
267 ifr
.ifr_data
= (char *)&ifb
;
268 if (ioctl(cfg
->g_sock
, SIOCBONDINFOQUERY
, &ifr
) >= 0) {
269 while (ifb
.num_slaves
--) {
270 memset(&ifr
, 0, sizeof(ifr
));
271 memset(&ifs
, 0, sizeof(ifs
));
272 strlcpy(ifr
.ifr_name
, master
, sizeof(ifr
.ifr_name
));
273 ifr
.ifr_data
= (char *)&ifs
;
274 ifs
.slave_id
= ifb
.num_slaves
;
275 if ((ioctl(cfg
->g_sock
, SIOCBONDSLAVEINFOQUERY
, &ifr
) >= 0) &&
276 (strncmp(ifs
.slave_name
, slave
, sizeof(ifs
.slave_name
)) == 0)) {
287 iface_is_enslaved(struct lldpd
*cfg
, const char *name
)
289 struct ifaddrs
*ifap
, *ifa
;
292 if (getifaddrs(&ifap
) != 0) {
293 LLOG_WARN("unable to get interface list");
296 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
297 if (iface_is_bond_slave(cfg
, name
, ifa
->ifa_name
, NULL
)) {
298 master
= if_nametoindex(ifa
->ifa_name
);
308 iface_get_permanent_mac(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
310 int master
, f
, state
= 0;
312 const char *slaveif
= "Slave Interface: ";
313 const char *hwaddr
= "Permanent HW addr: ";
314 u_int8_t mac
[ETHER_ADDR_LEN
];
316 char path
[SYSFS_PATH_MAX
];
318 if ((master
= iface_is_enslaved(cfg
, hardware
->h_ifname
)) == -1)
320 /* We have a bond, we need to query it to get real MAC addresses */
321 if ((if_indextoname(master
, bond
)) == NULL
) {
322 LLOG_WARNX("unable to get bond name");
326 if (snprintf(path
, SYSFS_PATH_MAX
, "/proc/net/bonding/%s",
327 bond
) >= SYSFS_PATH_MAX
) {
328 LLOG_WARNX("path truncated");
331 if ((f
= priv_open(path
)) < 0) {
332 if (snprintf(path
, SYSFS_PATH_MAX
, "/proc/self/net/bonding/%s",
333 bond
) >= SYSFS_PATH_MAX
) {
334 LLOG_WARNX("path truncated");
340 LLOG_WARNX("unable to find %s in /proc/net/bonding or /proc/self/net/bonding",
344 if ((netbond
= fdopen(f
, "r")) == NULL
) {
345 LLOG_WARN("unable to read stream from %s", path
);
350 We parse the file to search "Slave Interface: ". If found, go to
353 We parse the file to search "Permanent HW addr: ". If found, we get
356 while (fgets(line
, sizeof(line
), netbond
)) {
359 if (strncmp(line
, slaveif
, strlen(slaveif
)) == 0) {
360 if (line
[strlen(line
)-1] == '\n')
361 line
[strlen(line
)-1] = '\0';
362 if (strncmp(hardware
->h_ifname
,
363 line
+ strlen(slaveif
),
364 sizeof(hardware
->h_ifname
)) == 0)
369 if (strncmp(line
, hwaddr
, strlen(hwaddr
)) == 0) {
370 if (line
[strlen(line
)-1] == '\n')
371 line
[strlen(line
)-1] = '\0';
372 if (sscanf(line
+ strlen(hwaddr
),
373 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
374 &mac
[0], &mac
[1], &mac
[2],
375 &mac
[3], &mac
[4], &mac
[5]) !=
377 LLOG_WARN("unable to parse %s",
378 line
+ strlen(hwaddr
));
382 memcpy(hardware
->h_lladdr
, mac
,
390 LLOG_WARNX("unable to find real mac address for %s",
395 /* Generic minimal checks to handle a given interface. */
397 iface_minimal_checks(struct lldpd
*cfg
, struct ifaddrs
*ifa
)
399 struct sockaddr_ll sdl
;
401 struct ethtool_drvinfo ethc
;
402 const char * const *rif
;
404 /* White-list some drivers */
405 const char * const regular_interfaces
[] = {
411 int is_bridge
= iface_is_bridge(cfg
, ifa
->ifa_name
);
413 if (!(LOCAL_CHASSIS(cfg
)->c_cap_enabled
& LLDP_CAP_BRIDGE
) &&
415 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_BRIDGE
;
419 if (!(LOCAL_CHASSIS(cfg
)->c_cap_enabled
& LLDP_CAP_WLAN
) &&
420 iface_is_wireless(cfg
, ifa
->ifa_name
))
421 LOCAL_CHASSIS(cfg
)->c_cap_enabled
|= LLDP_CAP_WLAN
;
423 /* First, check if this interface has already been handled */
427 if (ifa
->ifa_addr
== NULL
||
428 ifa
->ifa_addr
->sa_family
!= PF_PACKET
)
431 memcpy(&sdl
, ifa
->ifa_addr
, sizeof(struct sockaddr_ll
));
432 if (sdl
.sll_hatype
!= ARPHRD_ETHER
|| !sdl
.sll_halen
)
435 /* We request that the interface is able to do either multicast
436 * or broadcast to be able to send discovery frames. */
437 if (!(ifa
->ifa_flags
& (IFF_MULTICAST
|IFF_BROADCAST
)))
440 /* Check if the driver is whitelisted */
441 memset(&ifr
, 0, sizeof(ifr
));
442 strcpy(ifr
.ifr_name
, ifa
->ifa_name
);
443 memset(ðc
, 0, sizeof(ethc
));
444 ifr
.ifr_data
= (caddr_t
) ðc
;
445 ethc
.cmd
= ETHTOOL_GDRVINFO
;
446 if (ioctl(cfg
->g_sock
, SIOCETHTOOL
, &ifr
) == 0) {
447 for (rif
= regular_interfaces
; *rif
; rif
++) {
448 if (strcmp(ethc
.driver
, *rif
) == 0) {
455 /* Check queue len. If no queue, this usually means that this
456 is not a "real" interface. */
457 memset(&ifr
, 0, sizeof(ifr
));
458 strcpy(ifr
.ifr_name
, ifa
->ifa_name
);
459 if ((ioctl(cfg
->g_sock
, SIOCGIFTXQLEN
, &ifr
) < 0) || !ifr
.ifr_qlen
)
462 /* Don't handle bond and VLAN, nor bridge */
463 if ((iface_is_vlan(cfg
, ifa
->ifa_name
)) ||
464 (iface_is_bond(cfg
, ifa
->ifa_name
)) ||
472 iface_set_filter(const char *name
, int fd
)
474 struct sock_fprog prog
;
475 memset(&prog
, 0, sizeof(struct sock_fprog
));
476 prog
.filter
= lldpd_filter_f
;
477 prog
.len
= sizeof(lldpd_filter_f
) / sizeof(struct sock_filter
);
479 if (setsockopt(fd
, SOL_SOCKET
, SO_ATTACH_FILTER
,
480 &prog
, sizeof(prog
)) < 0) {
481 LLOG_WARN("unable to change filter for %s", name
);
487 /* Fill up port name and description */
489 iface_port_name_desc(struct lldpd_hardware
*hardware
)
491 struct lldpd_port
*port
= &hardware
->h_lport
;
492 char buffer
[256]; /* 256 = IFALIASZ */
493 char path
[SYSFS_PATH_MAX
];
496 /* There are two cases:
498 1. We have a kernel recent enough to support ifAlias
499 _and_ a non empty ifAlias, then we will use it for
500 description and use ifname for port ID.
502 2. Otherwise, we will use the MAC address as ID and the
503 port name in description.
506 if ((snprintf(path
, SYSFS_PATH_MAX
,
507 SYSFS_CLASS_NET
"%s/ifalias", hardware
->h_ifname
)) >= SYSFS_PATH_MAX
)
508 LLOG_WARNX("path truncated");
509 memset(buffer
, 0, sizeof(buffer
));
510 if (((f
= priv_open(path
)) < 0) || (read(f
, buffer
, sizeof(buffer
)-1) < 1)) {
511 /* Case 2: MAC address and port name */
513 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_LLADDR
;
515 calloc(1, sizeof(hardware
->h_lladdr
))) == NULL
)
517 memcpy(port
->p_id
, hardware
->h_lladdr
,
518 sizeof(hardware
->h_lladdr
));
519 port
->p_id_len
= sizeof(hardware
->h_lladdr
);
520 port
->p_descr
= strdup(hardware
->h_ifname
);
523 /* Case 1: port name and port description */
525 port
->p_id_subtype
= LLDP_PORTID_SUBTYPE_IFNAME
;
526 port
->p_id_len
= strlen(hardware
->h_ifname
);
528 calloc(1, port
->p_id_len
)) == NULL
)
530 memcpy(port
->p_id
, hardware
->h_ifname
, port
->p_id_len
);
531 if (buffer
[strlen(buffer
) - 1] == '\n')
532 buffer
[strlen(buffer
) - 1] = '\0';
533 port
->p_descr
= strdup(buffer
);
536 /* Fill up MAC/PHY for a given hardware port */
538 iface_macphy(struct lldpd_hardware
*hardware
)
541 struct ethtool_cmd ethc
;
542 struct lldpd_port
*port
= &hardware
->h_lport
;
544 int advertised_ethtool_to_rfc3636
[][2] = {
545 {ADVERTISED_10baseT_Half
, LLDP_DOT3_LINK_AUTONEG_10BASE_T
},
546 {ADVERTISED_10baseT_Full
, LLDP_DOT3_LINK_AUTONEG_10BASET_FD
},
547 {ADVERTISED_100baseT_Half
, LLDP_DOT3_LINK_AUTONEG_100BASE_TX
},
548 {ADVERTISED_100baseT_Full
, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
},
549 {ADVERTISED_1000baseT_Half
, LLDP_DOT3_LINK_AUTONEG_1000BASE_T
},
550 {ADVERTISED_1000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
},
551 {ADVERTISED_10000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
552 {ADVERTISED_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE
},
553 {ADVERTISED_Asym_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE
},
554 {ADVERTISED_2500baseX_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
557 if (priv_ethtool(hardware
->h_ifname
, ðc
) == 0) {
558 port
->p_macphy
.autoneg_support
= (ethc
.supported
& SUPPORTED_Autoneg
) ? 1 : 0;
559 port
->p_macphy
.autoneg_enabled
= (ethc
.autoneg
== AUTONEG_DISABLE
) ? 0 : 1;
560 for (j
=0; advertised_ethtool_to_rfc3636
[j
][0]; j
++) {
561 if (ethc
.advertising
& advertised_ethtool_to_rfc3636
[j
][0])
562 port
->p_macphy
.autoneg_advertised
|=
563 advertised_ethtool_to_rfc3636
[j
][1];
565 switch (ethc
.speed
) {
567 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
568 LLDP_DOT3_MAU_10BASETFD
: LLDP_DOT3_MAU_10BASETHD
;
569 if (ethc
.port
== PORT_BNC
) port
->p_macphy
.mau_type
= LLDP_DOT3_MAU_10BASE2
;
570 if (ethc
.port
== PORT_FIBRE
)
571 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
572 LLDP_DOT3_MAU_10BASEFLDF
: LLDP_DOT3_MAU_10BASEFLHD
;
575 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
576 LLDP_DOT3_MAU_100BASETXFD
: LLDP_DOT3_MAU_100BASETXHD
;
577 if (ethc
.port
== PORT_BNC
)
578 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
579 LLDP_DOT3_MAU_100BASET2DF
: LLDP_DOT3_MAU_100BASET2HD
;
580 if (ethc
.port
== PORT_FIBRE
)
581 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
582 LLDP_DOT3_MAU_100BASEFXFD
: LLDP_DOT3_MAU_100BASEFXHD
;
585 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
586 LLDP_DOT3_MAU_1000BASETFD
: LLDP_DOT3_MAU_1000BASETHD
;
587 if (ethc
.port
== PORT_FIBRE
)
588 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
589 LLDP_DOT3_MAU_1000BASEXFD
: LLDP_DOT3_MAU_1000BASEXHD
;
592 port
->p_macphy
.mau_type
= (ethc
.port
== PORT_FIBRE
) ? \
593 LLDP_DOT3_MAU_10GIGBASEX
: LLDP_DOT3_MAU_10GIGBASER
;
596 if (ethc
.port
== PORT_AUI
) port
->p_macphy
.mau_type
= LLDP_DOT3_MAU_AUI
;
602 iface_mtu(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
607 memset(&ifr
, 0, sizeof(ifr
));
608 strlcpy(ifr
.ifr_name
, hardware
->h_ifname
, sizeof(ifr
.ifr_name
));
609 if (ioctl(cfg
->g_sock
, SIOCGIFMTU
, (char*)&ifr
) == -1) {
610 LLOG_WARN("unable to get MTU of %s, using 1500", hardware
->h_ifname
);
611 hardware
->h_mtu
= 1500;
613 hardware
->h_mtu
= ifr
.ifr_mtu
;
617 iface_multicast(struct lldpd
*cfg
, const char *name
, int remove
)
621 for (i
=0; cfg
->g_protocols
[i
].mode
!= 0; i
++) {
622 if (!cfg
->g_protocols
[i
].enabled
) continue;
623 if ((rc
= priv_iface_multicast(name
,
624 cfg
->g_protocols
[i
].mac
, !remove
)) != 0) {
627 LLOG_INFO("unable to %s %s address to multicast filter for %s",
628 (remove
)?"delete":"add",
629 cfg
->g_protocols
[i
].name
,
636 iface_eth_init(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
640 if ((fd
= priv_iface_init(hardware
->h_ifname
)) == -1)
642 hardware
->h_sendfd
= fd
; /* Send */
645 if ((status
= iface_set_filter(hardware
->h_ifname
, fd
)) != 0) {
650 iface_multicast(cfg
, hardware
->h_ifname
, 0);
652 levent_hardware_add_fd(hardware
, fd
); /* Receive */
653 LLOG_DEBUG("interface %s initialized (fd=%d)", hardware
->h_ifname
,
659 iface_eth_send(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
660 char *buffer
, size_t size
)
662 return write(hardware
->h_sendfd
,
667 iface_eth_recv(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
668 int fd
, char *buffer
, size_t size
)
671 struct sockaddr_ll from
;
674 fromlen
= sizeof(from
);
675 if ((n
= recvfrom(fd
,
678 (struct sockaddr
*)&from
,
680 LLOG_WARN("error while receiving frame on %s",
682 hardware
->h_rx_discarded_cnt
++;
685 if (from
.sll_pkttype
== PACKET_OUTGOING
)
691 iface_eth_close(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
693 iface_multicast(cfg
, hardware
->h_ifname
, 1);
698 lldpd_ifh_eth(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
701 struct lldpd_hardware
*hardware
;
703 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
704 if (!iface_minimal_checks(cfg
, ifa
))
707 if ((hardware
= lldpd_get_hardware(cfg
,
709 if_nametoindex(ifa
->ifa_name
),
710 ð_ops
)) == NULL
) {
711 if ((hardware
= lldpd_alloc_hardware(cfg
,
712 ifa
->ifa_name
)) == NULL
) {
713 LLOG_WARNX("Unable to allocate space for %s",
717 if (iface_eth_init(cfg
, hardware
) != 0) {
718 LLOG_WARN("unable to initialize %s", hardware
->h_ifname
);
719 lldpd_hardware_cleanup(cfg
, hardware
);
722 hardware
->h_ops
= ð_ops
;
723 hardware
->h_ifindex
= if_nametoindex(ifa
->ifa_name
);
724 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
726 if (hardware
->h_flags
) continue; /* Already seen this time */
727 lldpd_port_cleanup(cfg
, &hardware
->h_lport
, 0);
730 hardware
->h_flags
= ifa
->ifa_flags
; /* Should be non-zero */
731 ifa
->ifa_flags
= 0; /* Future handlers
736 /* Get local address */
737 memcpy(&hardware
->h_lladdr
,
738 (u_int8_t
*)((u_int8_t
*)ifa
->ifa_addr
+
739 offsetof(struct sockaddr_ll
, sll_addr
)),
740 sizeof(hardware
->h_lladdr
));
742 /* Fill information about port */
743 iface_port_name_desc(hardware
);
745 /* Fill additional info */
746 iface_macphy(hardware
);
747 iface_mtu(cfg
, hardware
);
752 lldpd_ifh_whitelist(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
756 if (!cfg
->g_interfaces
)
759 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
760 if (ifa
->ifa_flags
== 0) continue; /* Already handled by someone else */
761 if (!pattern_match(ifa
->ifa_name
, cfg
->g_interfaces
, 0)) {
762 /* This interface was not found. We flag it. */
763 LLOG_DEBUG("blacklist %s", ifa
->ifa_name
);
770 iface_bond_init(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
772 char *mastername
= (char *)hardware
->h_data
; /* Master name */
776 if (!mastername
) return -1;
778 /* First, we get a socket to the raw physical interface */
779 if ((fd
= priv_iface_init(hardware
->h_ifname
)) == -1)
781 hardware
->h_sendfd
= fd
;
782 levent_hardware_add_fd(hardware
, fd
);
783 if ((status
= iface_set_filter(hardware
->h_ifname
, fd
)) != 0) {
787 iface_multicast(cfg
, hardware
->h_ifname
, 0);
789 /* Then, we open a raw interface for the master */
790 if ((fd
= priv_iface_init(mastername
)) == -1) {
791 close(hardware
->h_sendfd
);
794 if ((status
= iface_set_filter(mastername
, fd
)) != 0) {
795 close(hardware
->h_sendfd
);
799 /* With bonding and older kernels (< 2.6.27) we need to listen
800 * to bond device. We use setsockopt() PACKET_ORIGDEV to get
801 * physical device instead of bond device (works with >=
803 if (setsockopt(fd
, SOL_PACKET
,
804 PACKET_ORIGDEV
, &un
, sizeof(un
)) == -1) {
805 LLOG_DEBUG("[priv]: unable to setsockopt for master bonding device of %s. "
806 "You will get inaccurate results",
809 iface_multicast(cfg
, mastername
, 0);
811 levent_hardware_add_fd(hardware
, fd
);
812 LLOG_DEBUG("interface %s initialized (fd=%d,master=%s[%d])",
820 iface_bond_send(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
821 char *buffer
, size_t size
)
823 /* With bonds, we have duplicate MAC address on different physical
824 * interfaces. We need to alter the source MAC address when we send on
825 * an inactive slave. */
826 char *master
= (char*)hardware
->h_data
;
828 if (!iface_is_bond_slave(cfg
, hardware
->h_ifname
, master
, &active
)) {
829 LLOG_WARNX("%s seems to not be enslaved anymore?",
834 /* We need to modify the source MAC address */
835 if (size
< 2 * ETH_ALEN
) {
836 LLOG_WARNX("packet to send on %s is too small!",
840 memset(buffer
+ ETH_ALEN
, 0, ETH_ALEN
);
842 return write(hardware
->h_sendfd
,
847 iface_bond_recv(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
848 int fd
, char *buffer
, size_t size
)
851 struct sockaddr_ll from
;
854 fromlen
= sizeof(from
);
855 if ((n
= recvfrom(fd
, buffer
, size
, 0,
856 (struct sockaddr
*)&from
,
858 LLOG_WARN("error while receiving frame on %s",
860 hardware
->h_rx_discarded_cnt
++;
863 if (from
.sll_pkttype
== PACKET_OUTGOING
)
865 if (fd
== hardware
->h_sendfd
)
866 /* We received this on the physical interface. */
868 /* We received this on the bonding interface. Is it really for us? */
869 if (from
.sll_ifindex
== hardware
->h_ifindex
)
872 if (from
.sll_ifindex
== if_nametoindex((char*)hardware
->h_data
))
873 /* We don't know from which physical interface it comes (kernel
874 * < 2.6.24). In doubt, this is for us. */
876 return -1; /* Not for us */
880 iface_bond_close(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
882 iface_multicast(cfg
, hardware
->h_ifname
, 1);
883 iface_multicast(cfg
, (char*)hardware
->h_data
, 1);
884 free(hardware
->h_data
);
889 lldpd_ifh_bond(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
892 struct lldpd_hardware
*hardware
;
894 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
895 if (!iface_minimal_checks(cfg
, ifa
))
897 if ((master
= iface_is_enslaved(cfg
, ifa
->ifa_name
)) == -1)
900 if ((hardware
= lldpd_get_hardware(cfg
,
902 if_nametoindex(ifa
->ifa_name
),
903 &bond_ops
)) == NULL
) {
904 if ((hardware
= lldpd_alloc_hardware(cfg
,
905 ifa
->ifa_name
)) == NULL
) {
906 LLOG_WARNX("Unable to allocate space for %s",
910 hardware
->h_data
= (char *)calloc(1, IFNAMSIZ
);
911 if_indextoname(master
, hardware
->h_data
);
912 if (iface_bond_init(cfg
, hardware
) != 0) {
913 LLOG_WARN("unable to initialize %s",
915 lldpd_hardware_cleanup(cfg
, hardware
);
918 hardware
->h_ops
= &bond_ops
;
919 hardware
->h_ifindex
= if_nametoindex(ifa
->ifa_name
);
920 TAILQ_INSERT_TAIL(&cfg
->g_hardware
, hardware
, h_entries
);
922 if (hardware
->h_flags
) continue; /* Already seen this time */
923 memset(hardware
->h_data
, 0, IFNAMSIZ
);
924 if_indextoname(master
, hardware
->h_data
);
925 lldpd_port_cleanup(cfg
, &hardware
->h_lport
, 0);
928 hardware
->h_flags
= ifa
->ifa_flags
;
931 /* Get local address */
932 iface_get_permanent_mac(cfg
, hardware
);
934 /* Fill information about port */
935 iface_port_name_desc(hardware
);
937 /* Fill additional info */
939 hardware
->h_lport
.p_aggregid
= master
;
941 iface_macphy(hardware
);
942 iface_mtu(cfg
, hardware
);
948 iface_append_vlan(struct lldpd
*cfg
,
949 struct lldpd_hardware
*hardware
, struct ifaddrs
*ifa
)
951 struct lldpd_port
*port
= &hardware
->h_lport
;
952 struct lldpd_vlan
*vlan
;
953 struct vlan_ioctl_args ifv
;
955 /* Check if the VLAN is already here. */
956 TAILQ_FOREACH(vlan
, &port
->p_vlans
, v_entries
)
957 if (strncmp(ifa
->ifa_name
, vlan
->v_name
, IFNAMSIZ
) == 0)
959 if ((vlan
= (struct lldpd_vlan
*)
960 calloc(1, sizeof(struct lldpd_vlan
))) == NULL
)
962 if ((vlan
->v_name
= strdup(ifa
->ifa_name
)) == NULL
) {
966 memset(&ifv
, 0, sizeof(ifv
));
967 ifv
.cmd
= GET_VLAN_VID_CMD
;
968 strlcpy(ifv
.device1
, ifa
->ifa_name
, sizeof(ifv
.device1
));
969 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) < 0) {
970 /* Dunno what happened */
975 vlan
->v_vid
= ifv
.u
.VID
;
976 TAILQ_INSERT_TAIL(&port
->p_vlans
, vlan
, v_entries
);
980 lldpd_ifh_vlan(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
983 struct vlan_ioctl_args ifv
;
984 struct lldpd_hardware
*hardware
;
986 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
989 if (!iface_is_vlan(cfg
, ifa
->ifa_name
))
992 /* We need to find the physical interfaces of this
993 vlan, through bonds and bridges. */
994 memset(&ifv
, 0, sizeof(ifv
));
995 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
996 strlcpy(ifv
.device1
, ifa
->ifa_name
, sizeof(ifv
.device1
));
997 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0) {
999 1. we get a real device
1003 if ((hardware
= lldpd_get_hardware(cfg
,
1005 if_nametoindex(ifv
.u
.device2
),
1007 if (iface_is_bond(cfg
, ifv
.u
.device2
)) {
1008 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
,
1010 if (iface_is_bond_slave(cfg
,
1012 ifv
.u
.device2
, NULL
))
1013 iface_append_vlan(cfg
,
1015 } else if (iface_is_bridge(cfg
, ifv
.u
.device2
)) {
1016 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
,
1018 if (iface_is_bridged_to(cfg
,
1021 iface_append_vlan(cfg
,
1024 } else iface_append_vlan(cfg
,
1031 #ifndef IN_IS_ADDR_LOOPBACK
1032 #define IN_IS_ADDR_LOOPBACK(a) ((a)->s_addr == htonl(INADDR_LOOPBACK))
1034 #ifndef IN_IS_ADDR_GLOBAL
1035 #define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a))
1037 #ifndef IN6_IS_ADDR_GLOBAL
1038 #define IN6_IS_ADDR_GLOBAL(a) (!IN6_IS_ADDR_LOOPBACK(a) && \
1039 !IN6_IS_ADDR_LINKLOCAL(a))
1042 /* Find a management address in all available interfaces, even those that were
1043 already handled. This is a special interface handler because it does not
1044 really handle interface related information (management address is attached
1045 to the local chassis). */
1047 lldpd_ifh_mgmt(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
1049 struct ifaddrs
*ifa
;
1050 char addrstrbuf
[INET6_ADDRSTRLEN
];
1051 struct lldpd_mgmt
*mgmt
;
1053 size_t sin_addr_size
;
1055 int allnegative
= 0;
1057 lldpd_chassis_mgmt_cleanup(LOCAL_CHASSIS(cfg
));
1059 /* Is the pattern provided all negative? */
1060 if (cfg
->g_mgmt_pattern
== NULL
) allnegative
= 1;
1061 else if (cfg
->g_mgmt_pattern
[0] == '!') {
1062 /* If each comma is followed by '!', its an all
1064 char *sep
= cfg
->g_mgmt_pattern
;
1065 while ((sep
= strchr(sep
, ',')) &&
1067 if (sep
== NULL
) allnegative
= 1;
1070 /* Find management addresses */
1071 for (af
= LLDPD_AF_UNSPEC
+ 1; af
!= LLDPD_AF_LAST
; af
++) {
1072 /* We only take one of each address family, unless a
1073 pattern is provided and is not all negative. For
1074 example !*:*,!10.* will only blacklist
1075 addresses. We will pick the first IPv4 address not
1079 ifa
= ifa
->ifa_next
) {
1080 if (ifa
->ifa_addr
== NULL
)
1082 if (ifa
->ifa_addr
->sa_family
!= lldpd_af(af
))
1087 sin_addr_ptr
= &((struct sockaddr_in
*)ifa
->ifa_addr
)->sin_addr
;
1088 sin_addr_size
= sizeof(struct in_addr
);
1089 if (!IN_IS_ADDR_GLOBAL((struct in_addr
*)sin_addr_ptr
))
1093 sin_addr_ptr
= &((struct sockaddr_in6
*)ifa
->ifa_addr
)->sin6_addr
;
1094 sin_addr_size
= sizeof(struct in6_addr
);
1095 if (!IN6_IS_ADDR_GLOBAL((struct in6_addr
*)sin_addr_ptr
))
1102 if (inet_ntop(lldpd_af(af
), sin_addr_ptr
,
1103 addrstrbuf
, sizeof(addrstrbuf
)) == NULL
) {
1104 LLOG_WARN("unable to convert IP address to a string");
1107 if (cfg
->g_mgmt_pattern
== NULL
||
1108 pattern_match(addrstrbuf
, cfg
->g_mgmt_pattern
, allnegative
)) {
1109 mgmt
= lldpd_alloc_mgmt(af
, sin_addr_ptr
, sin_addr_size
,
1110 if_nametoindex(ifa
->ifa_name
));
1112 assert(errno
== ENOMEM
); /* anything else is a bug */
1113 LLOG_WARN("out of memory error");
1116 TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg
)->c_mgmt
, mgmt
, m_entries
);
1118 /* Don't take additional address if the pattern is all negative. */
1119 if (allnegative
) break;
1126 /* Fill out chassis ID if not already done. This handler is special
1127 because we will only handle interfaces that are already handled. */
1129 lldpd_ifh_chassis(struct lldpd
*cfg
, struct ifaddrs
*ifap
)
1131 struct ifaddrs
*ifa
;
1132 struct lldpd_hardware
*hardware
;
1134 if (LOCAL_CHASSIS(cfg
)->c_id
!= NULL
&&
1135 LOCAL_CHASSIS(cfg
)->c_id_subtype
== LLDP_CHASSISID_SUBTYPE_LLADDR
)
1136 return; /* We already have one */
1138 for (ifa
= ifap
; ifa
!= NULL
; ifa
= ifa
->ifa_next
) {
1139 if (ifa
->ifa_flags
) continue;
1140 if (cfg
->g_cid_pattern
&&
1141 !pattern_match(ifa
->ifa_name
, cfg
->g_cid_pattern
, 0)) continue;
1143 if ((hardware
= lldpd_get_hardware(cfg
,
1145 if_nametoindex(ifa
->ifa_name
),
1147 /* That's odd. Let's skip. */
1150 char *name
= malloc(sizeof(hardware
->h_lladdr
));
1152 LLOG_WARN("Not enough memory for chassis ID");
1155 free(LOCAL_CHASSIS(cfg
)->c_id
);
1156 memcpy(name
, hardware
->h_lladdr
, sizeof(hardware
->h_lladdr
));
1157 LOCAL_CHASSIS(cfg
)->c_id
= name
;
1158 LOCAL_CHASSIS(cfg
)->c_id_len
= sizeof(hardware
->h_lladdr
);
1159 LOCAL_CHASSIS(cfg
)->c_id_subtype
= LLDP_CHASSISID_SUBTYPE_LLADDR
;
1164 struct lldpd_ops eth_ops
= {
1165 .send
= iface_eth_send
,
1166 .recv
= iface_eth_recv
,
1167 .cleanup
= iface_eth_close
,
1169 struct lldpd_ops bond_ops
= {
1170 .send
= iface_bond_send
,
1171 .recv
= iface_bond_recv
,
1172 .cleanup
= iface_bond_close
,