1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx>
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 #include <sys/ioctl.h>
24 #if defined(__clang__)
25 #pragma clang diagnostic push
26 #pragma clang diagnostic ignored "-Wdocumentation"
28 #include <linux/if_vlan.h>
29 #include <linux/if_bonding.h>
30 #include <linux/if_bridge.h>
31 #include <linux/wireless.h>
32 #include <linux/sockios.h>
33 #include <linux/if_packet.h>
34 #include <linux/ethtool.h>
35 #if defined(__clang__)
36 #pragma clang diagnostic pop
39 #define SYSFS_PATH_MAX 256
40 #define MAX_PORTS 1024
41 #define MAX_BRIDGES 1024
44 iflinux_eth_init(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
48 log_debug("interfaces", "initialize ethernet device %s",
50 if ((fd
= priv_iface_init(hardware
->h_ifindex
, hardware
->h_ifname
)) == -1)
52 hardware
->h_sendfd
= fd
; /* Send */
54 interfaces_setup_multicast(cfg
, hardware
->h_ifname
, 0);
56 levent_hardware_add_fd(hardware
, fd
); /* Receive */
57 log_debug("interfaces", "interface %s initialized (fd=%d)", hardware
->h_ifname
,
62 /* Generic ethernet send/receive */
64 iflinux_eth_send(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
65 char *buffer
, size_t size
)
67 log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)",
68 hardware
->h_ifname
, hardware
->h_sendfd
);
69 return write(hardware
->h_sendfd
,
74 iflinux_eth_recv(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
75 int fd
, char *buffer
, size_t size
)
78 struct sockaddr_ll from
= {};
81 log_debug("interfaces", "receive PDU from ethernet device %s",
83 fromlen
= sizeof(from
);
87 (struct sockaddr
*)&from
,
89 log_warn("interfaces", "error while receiving frame on %s",
91 hardware
->h_rx_discarded_cnt
++;
94 if (from
.sll_pkttype
== PACKET_OUTGOING
)
100 iflinux_eth_close(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
102 log_debug("interfaces", "close ethernet device %s",
104 interfaces_setup_multicast(cfg
, hardware
->h_ifname
, 1);
108 static struct lldpd_ops eth_ops
= {
109 .send
= iflinux_eth_send
,
110 .recv
= iflinux_eth_recv
,
111 .cleanup
= iflinux_eth_close
,
115 iflinux_is_bridge(struct lldpd
*cfg
,
116 struct interfaces_device_list
*interfaces
,
117 struct interfaces_device
*iface
)
120 struct interfaces_device
*port
;
121 char path
[SYSFS_PATH_MAX
];
124 if ((snprintf(path
, SYSFS_PATH_MAX
,
125 SYSFS_CLASS_NET
"%s/" SYSFS_BRIDGE_FDB
,
126 iface
->name
)) >= SYSFS_PATH_MAX
)
127 log_warnx("interfaces", "path truncated");
128 if ((f
= priv_open(path
)) < 0)
132 /* Also grab all ports */
133 TAILQ_FOREACH(port
, interfaces
, next
) {
134 if (port
->upper
) continue;
135 if (snprintf(path
, SYSFS_PATH_MAX
,
136 SYSFS_CLASS_NET
"%s/" SYSFS_BRIDGE_PORT_SUBDIR
"/%s/port_no",
137 iface
->name
, port
->name
) >= SYSFS_PATH_MAX
)
138 log_warnx("interfaces", "path truncated");
139 if ((f
= priv_open(path
)) < 0)
141 log_debug("interfaces",
142 "port %s is bridged to %s",
143 port
->name
, iface
->name
);
155 iflinux_is_vlan(struct lldpd
*cfg
,
156 struct interfaces_device_list
*interfaces
,
157 struct interfaces_device
*iface
)
160 struct vlan_ioctl_args ifv
= {};
161 ifv
.cmd
= GET_VLAN_REALDEV_NAME_CMD
;
162 strlcpy(ifv
.device1
, iface
->name
, sizeof(ifv
.device1
));
163 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) >= 0) {
164 /* This is a VLAN, get the lower interface and the VID */
165 struct interfaces_device
*lower
=
166 interfaces_nametointerface(interfaces
, ifv
.u
.device2
);
168 log_debug("interfaces",
169 "unable to find lower interface for VLAN %s",
174 memset(&ifv
, 0, sizeof(ifv
));
175 ifv
.cmd
= GET_VLAN_VID_CMD
;
176 strlcpy(ifv
.device1
, iface
->name
, sizeof(ifv
.device1
));
177 if (ioctl(cfg
->g_sock
, SIOCGIFVLAN
, &ifv
) < 0) {
178 log_debug("interfaces",
179 "unable to find VID for VLAN %s",
184 iface
->lower
= lower
;
185 iface
->vlanid
= ifv
.u
.VID
;
193 iflinux_is_bond(struct lldpd
*cfg
,
194 struct interfaces_device_list
*interfaces
,
195 struct interfaces_device
*master
)
198 /* Shortcut if we detect the new team driver. Upper and lower links
199 * should already be set with netlink in this case. */
200 if (master
->driver
&& !strcmp(master
->driver
, "team")) {
204 struct ifreq ifr
= {};
205 struct ifbond ifb
= {};
206 strlcpy(ifr
.ifr_name
, master
->name
, sizeof(ifr
.ifr_name
));
207 ifr
.ifr_data
= (char *)&ifb
;
208 if (ioctl(cfg
->g_sock
, SIOCBONDINFOQUERY
, &ifr
) >= 0) {
209 while (ifb
.num_slaves
--) {
211 memset(&ifr
, 0, sizeof(ifr
));
212 memset(&ifs
, 0, sizeof(ifs
));
213 strlcpy(ifr
.ifr_name
, master
->name
, sizeof(ifr
.ifr_name
));
214 ifr
.ifr_data
= (char *)&ifs
;
215 ifs
.slave_id
= ifb
.num_slaves
;
216 if (ioctl(cfg
->g_sock
, SIOCBONDSLAVEINFOQUERY
, &ifr
) >= 0) {
217 struct interfaces_device
*slave
=
218 interfaces_nametointerface(interfaces
,
220 if (slave
== NULL
) continue;
221 if (slave
->upper
) continue;
222 log_debug("interfaces",
223 "interface %s is enslaved to %s",
224 slave
->name
, master
->name
);
225 slave
->upper
= master
;
234 /* Get the permanent MAC address using ethtool as a fallback There is a slight
235 * difference with /proc/net/bonding method. The /proc/net/bonding method will
236 * retrieve the MAC address of the interface before it was added to the
237 * bond. The ethtool method will retrieve the real permanent MAC address. For
238 * some devices, there is no such address (for example, virtual devices like
241 iflinux_get_permanent_mac_ethtool(struct lldpd
*cfg
,
242 struct interfaces_device_list
*interfaces
,
243 struct interfaces_device
*iface
)
245 struct interfaces_device
*master
;
246 u_int8_t mac
[ETHER_ADDR_LEN
];
248 /* We could do that for any interface, but let's do that only for
250 if ((master
= iface
->upper
) == NULL
|| master
->type
!= IFACE_BOND_T
)
253 log_debug("interfaces", "get MAC address for %s",
256 if (priv_iface_mac(iface
->name
, mac
, ETHER_ADDR_LEN
) != 0) {
257 log_warnx("interfaces",
258 "unable to get permanent MAC address for %s",
263 for (i
= 0; i
< ETHER_ADDR_LEN
; i
++)
264 if (mac
[i
] != 0) break;
265 if (i
== ETHER_ADDR_LEN
) {
266 log_warnx("interfaces",
267 "no permanent MAC address found for %s",
271 memcpy(iface
->address
, mac
,
276 iflinux_get_permanent_mac(struct lldpd
*cfg
,
277 struct interfaces_device_list
*interfaces
,
278 struct interfaces_device
*iface
)
280 struct interfaces_device
*master
;
283 const char *slaveif
= "Slave Interface: ";
284 const char *hwaddr
= "Permanent HW addr: ";
285 u_int8_t mac
[ETHER_ADDR_LEN
];
286 char path
[SYSFS_PATH_MAX
];
289 if ((master
= iface
->upper
) == NULL
|| master
->type
!= IFACE_BOND_T
)
292 /* We have a bond, we need to query it to get real MAC addresses */
293 if (snprintf(path
, SYSFS_PATH_MAX
, "/proc/net/bonding/%s",
294 master
->name
) >= SYSFS_PATH_MAX
) {
295 log_warnx("interfaces", "path truncated");
298 if ((f
= priv_open(path
)) < 0) {
299 if (snprintf(path
, SYSFS_PATH_MAX
, "/proc/self/net/bonding/%s",
300 master
->name
) >= SYSFS_PATH_MAX
) {
301 log_warnx("interfaces", "path truncated");
307 iflinux_get_permanent_mac_ethtool(cfg
, interfaces
, iface
);
310 if ((netbond
= fdopen(f
, "r")) == NULL
) {
311 log_warn("interfaces", "unable to read stream from %s", path
);
316 We parse the file to search "Slave Interface: ". If found, go to
319 We parse the file to search "Permanent HW addr: ". If found, we get
322 while (fgets(line
, sizeof(line
), netbond
)) {
325 if (strncmp(line
, slaveif
, strlen(slaveif
)) == 0) {
326 if (line
[strlen(line
)-1] == '\n')
327 line
[strlen(line
)-1] = '\0';
328 if (strcmp(iface
->name
,
329 line
+ strlen(slaveif
)) == 0)
334 if (strncmp(line
, hwaddr
, strlen(hwaddr
)) == 0) {
335 if (line
[strlen(line
)-1] == '\n')
336 line
[strlen(line
)-1] = '\0';
337 if (sscanf(line
+ strlen(hwaddr
),
338 "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
339 &mac
[0], &mac
[1], &mac
[2],
340 &mac
[3], &mac
[4], &mac
[5]) !=
342 log_warn("interfaces", "unable to parse %s",
343 line
+ strlen(hwaddr
));
347 memcpy(iface
->address
, mac
,
355 log_warnx("interfaces", "unable to find real mac address for %s",
360 /* Fill up MAC/PHY for a given hardware port */
362 iflinux_macphy(struct lldpd_hardware
*hardware
)
365 struct ethtool_cmd ethc
;
366 struct lldpd_port
*port
= &hardware
->h_lport
;
368 int advertised_ethtool_to_rfc3636
[][2] = {
369 {ADVERTISED_10baseT_Half
, LLDP_DOT3_LINK_AUTONEG_10BASE_T
},
370 {ADVERTISED_10baseT_Full
, LLDP_DOT3_LINK_AUTONEG_10BASET_FD
},
371 {ADVERTISED_100baseT_Half
, LLDP_DOT3_LINK_AUTONEG_100BASE_TX
},
372 {ADVERTISED_100baseT_Full
, LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD
},
373 {ADVERTISED_1000baseT_Half
, LLDP_DOT3_LINK_AUTONEG_1000BASE_T
},
374 {ADVERTISED_1000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD
},
375 {ADVERTISED_10000baseT_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
376 {ADVERTISED_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE
},
377 {ADVERTISED_Asym_Pause
, LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE
},
378 {ADVERTISED_2500baseX_Full
, LLDP_DOT3_LINK_AUTONEG_OTHER
},
381 log_debug("interfaces", "ask ethtool for the appropriate MAC/PHY for %s",
383 if (priv_ethtool(hardware
->h_ifname
, ðc
, sizeof(struct ethtool_cmd
)) == 0) {
384 port
->p_macphy
.autoneg_support
= (ethc
.supported
& SUPPORTED_Autoneg
) ? 1 : 0;
385 port
->p_macphy
.autoneg_enabled
= (ethc
.autoneg
== AUTONEG_DISABLE
) ? 0 : 1;
386 for (j
=0; advertised_ethtool_to_rfc3636
[j
][0]; j
++) {
387 if (ethc
.advertising
& advertised_ethtool_to_rfc3636
[j
][0])
388 port
->p_macphy
.autoneg_advertised
|=
389 advertised_ethtool_to_rfc3636
[j
][1];
391 switch (ethc
.speed
) {
393 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
394 LLDP_DOT3_MAU_10BASETFD
: LLDP_DOT3_MAU_10BASETHD
;
395 if (ethc
.port
== PORT_BNC
) port
->p_macphy
.mau_type
= LLDP_DOT3_MAU_10BASE2
;
396 if (ethc
.port
== PORT_FIBRE
)
397 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
398 LLDP_DOT3_MAU_10BASEFLFD
: LLDP_DOT3_MAU_10BASEFLHD
;
401 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
402 LLDP_DOT3_MAU_100BASETXFD
: LLDP_DOT3_MAU_100BASETXHD
;
403 if (ethc
.port
== PORT_BNC
)
404 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
405 LLDP_DOT3_MAU_100BASET2FD
: LLDP_DOT3_MAU_100BASET2HD
;
406 if (ethc
.port
== PORT_FIBRE
)
407 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
408 LLDP_DOT3_MAU_100BASEFXFD
: LLDP_DOT3_MAU_100BASEFXHD
;
411 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
412 LLDP_DOT3_MAU_1000BASETFD
: LLDP_DOT3_MAU_1000BASETHD
;
413 if (ethc
.port
== PORT_FIBRE
)
414 port
->p_macphy
.mau_type
= (ethc
.duplex
== DUPLEX_FULL
) ? \
415 LLDP_DOT3_MAU_1000BASEXFD
: LLDP_DOT3_MAU_1000BASEXHD
;
418 port
->p_macphy
.mau_type
= (ethc
.port
== PORT_FIBRE
) ? \
419 LLDP_DOT3_MAU_10GIGBASEX
: LLDP_DOT3_MAU_10GIGBASER
;
422 if (ethc
.port
== PORT_AUI
) port
->p_macphy
.mau_type
= LLDP_DOT3_MAU_AUI
;
433 iface_bond_init(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
435 struct bond_master
*master
= hardware
->h_data
;
439 if (!master
) return -1;
441 log_debug("interfaces", "initialize enslaved device %s",
444 /* First, we get a socket to the raw physical interface */
445 if ((fd
= priv_iface_init(hardware
->h_ifindex
,
446 hardware
->h_ifname
)) == -1)
448 hardware
->h_sendfd
= fd
;
449 interfaces_setup_multicast(cfg
, hardware
->h_ifname
, 0);
451 /* Then, we open a raw interface for the master */
452 log_debug("interfaces", "enslaved device %s has master %s(%d)",
453 hardware
->h_ifname
, master
->name
, master
->index
);
454 if ((fd
= priv_iface_init(master
->index
, master
->name
)) == -1) {
455 close(hardware
->h_sendfd
);
458 /* With bonding and older kernels (< 2.6.27) we need to listen
459 * to bond device. We use setsockopt() PACKET_ORIGDEV to get
460 * physical device instead of bond device (works with >=
462 if (setsockopt(fd
, SOL_PACKET
,
463 PACKET_ORIGDEV
, &un
, sizeof(un
)) == -1) {
464 log_info("interfaces", "unable to setsockopt for master bonding device of %s. "
465 "You will get inaccurate results",
468 interfaces_setup_multicast(cfg
, master
->name
, 0);
470 levent_hardware_add_fd(hardware
, hardware
->h_sendfd
);
471 levent_hardware_add_fd(hardware
, fd
);
472 log_debug("interfaces", "interface %s initialized (fd=%d,master=%s[%d])",
480 iface_bond_recv(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
,
481 int fd
, char *buffer
, size_t size
)
484 struct sockaddr_ll from
= {};
486 struct bond_master
*master
= hardware
->h_data
;
488 log_debug("interfaces", "receive PDU from enslaved device %s",
490 fromlen
= sizeof(from
);
491 if ((n
= recvfrom(fd
, buffer
, size
, 0,
492 (struct sockaddr
*)&from
,
494 log_warn("interfaces", "error while receiving frame on %s",
496 hardware
->h_rx_discarded_cnt
++;
499 if (from
.sll_pkttype
== PACKET_OUTGOING
)
501 if (fd
== hardware
->h_sendfd
)
502 /* We received this on the physical interface. */
504 /* We received this on the bonding interface. Is it really for us? */
505 if (from
.sll_ifindex
== hardware
->h_ifindex
)
508 if (from
.sll_ifindex
== master
->index
)
509 /* We don't know from which physical interface it comes (kernel
510 * < 2.6.24). In doubt, this is for us. */
512 return -1; /* Not for us */
516 iface_bond_close(struct lldpd
*cfg
, struct lldpd_hardware
*hardware
)
518 struct bond_master
*master
= hardware
->h_data
;
519 log_debug("interfaces", "closing enslaved device %s",
521 interfaces_setup_multicast(cfg
, hardware
->h_ifname
, 1);
522 interfaces_setup_multicast(cfg
, master
->name
, 1);
523 free(hardware
->h_data
); hardware
->h_data
= NULL
;
527 struct lldpd_ops bond_ops
= {
528 .send
= iflinux_eth_send
,
529 .recv
= iface_bond_recv
,
530 .cleanup
= iface_bond_close
,
534 iflinux_handle_bond(struct lldpd
*cfg
, struct interfaces_device_list
*interfaces
)
536 struct interfaces_device
*iface
;
537 struct interfaces_device
*master
;
538 struct lldpd_hardware
*hardware
;
539 struct bond_master
*bmaster
;
541 TAILQ_FOREACH(iface
, interfaces
, next
) {
542 if (!(iface
->type
& IFACE_PHYSICAL_T
)) continue;
543 if (iface
->ignore
) continue;
544 if (!iface
->upper
|| !(iface
->upper
->type
& IFACE_BOND_T
)) continue;
546 master
= iface
->upper
;
547 log_debug("interfaces", "%s is an acceptable enslaved device (master=%s)",
548 iface
->name
, master
->name
);
550 if ((hardware
= lldpd_get_hardware(cfg
,
552 iface
->index
)) == NULL
) {
553 if ((hardware
= lldpd_alloc_hardware(cfg
,
555 iface
->index
)) == NULL
) {
556 log_warnx("interfaces", "Unable to allocate space for %s",
562 if (hardware
->h_flags
) continue;
563 if (hardware
->h_ops
!= &bond_ops
) {
565 log_debug("interfaces",
566 "bond %s is converted from another type of interface",
568 if (hardware
->h_ops
&& hardware
->h_ops
->cleanup
)
569 hardware
->h_ops
->cleanup(cfg
, hardware
);
570 levent_hardware_release(hardware
);
571 levent_hardware_init(hardware
);
573 bmaster
= hardware
->h_data
= calloc(1, sizeof(struct bond_master
));
575 log_warn("interfaces", "not enough memory");
576 lldpd_hardware_cleanup(cfg
, hardware
);
579 } else bmaster
= hardware
->h_data
;
580 bmaster
->index
= master
->index
;
581 strlcpy(bmaster
->name
, master
->name
, IFNAMSIZ
);
582 if (hardware
->h_ops
!= &bond_ops
) {
583 if (iface_bond_init(cfg
, hardware
) != 0) {
584 log_warn("interfaces", "unable to initialize %s",
586 lldpd_hardware_cleanup(cfg
, hardware
);
589 hardware
->h_ops
= &bond_ops
;
590 hardware
->h_mangle
= 1;
593 interfaces_helper_add_hardware(cfg
, hardware
);
595 lldpd_port_cleanup(&hardware
->h_lport
, 0);
597 hardware
->h_flags
= iface
->flags
;
600 /* Get local address */
601 memcpy(&hardware
->h_lladdr
, iface
->address
, ETHER_ADDR_LEN
);
603 /* Fill information about port */
604 interfaces_helper_port_name_desc(cfg
, hardware
, iface
);
606 /* Fill additional info */
608 hardware
->h_lport
.p_aggregid
= master
->index
;
610 hardware
->h_mtu
= iface
->mtu
? iface
->mtu
: 1500;
614 /* Query each interface to get the appropriate driver */
616 iflinux_add_driver(struct lldpd
*cfg
,
617 struct interfaces_device_list
*interfaces
)
619 struct interfaces_device
*iface
;
620 TAILQ_FOREACH(iface
, interfaces
, next
) {
621 struct ethtool_drvinfo ethc
= {
622 .cmd
= ETHTOOL_GDRVINFO
625 .ifr_data
= (caddr_t
)ðc
627 if (iface
->driver
) continue;
629 strlcpy(ifr
.ifr_name
, iface
->name
, IFNAMSIZ
);
630 if (ioctl(cfg
->g_sock
, SIOCETHTOOL
, &ifr
) == 0) {
631 iface
->driver
= strdup(ethc
.driver
);
632 log_debug("interfaces", "driver for %s is `%s`",
633 iface
->name
, iface
->driver
);
638 /* Query each interface to see if it is a wireless one */
640 iflinux_add_wireless(struct lldpd
*cfg
,
641 struct interfaces_device_list
*interfaces
)
643 struct interfaces_device
*iface
;
644 TAILQ_FOREACH(iface
, interfaces
, next
) {
645 struct iwreq iwr
= {};
646 strlcpy(iwr
.ifr_name
, iface
->name
, IFNAMSIZ
);
647 if (ioctl(cfg
->g_sock
, SIOCGIWNAME
, &iwr
) >= 0) {
648 log_debug("interfaces", "%s is wireless",
650 iface
->type
|= IFACE_WIRELESS_T
| IFACE_PHYSICAL_T
;
655 /* Query each interface to see if it is a bridge */
657 iflinux_add_bridge(struct lldpd
*cfg
,
658 struct interfaces_device_list
*interfaces
)
660 struct interfaces_device
*iface
;
662 TAILQ_FOREACH(iface
, interfaces
, next
) {
663 if (iface
->type
& (IFACE_PHYSICAL_T
|
664 IFACE_VLAN_T
|IFACE_BOND_T
|IFACE_BRIDGE_T
))
666 if (iflinux_is_bridge(cfg
, interfaces
, iface
)) {
667 log_debug("interfaces",
668 "interface %s is a bridge",
670 iface
->type
|= IFACE_BRIDGE_T
;
675 /* Query each interface to see if it is a bond */
677 iflinux_add_bond(struct lldpd
*cfg
,
678 struct interfaces_device_list
*interfaces
)
680 struct interfaces_device
*iface
;
682 TAILQ_FOREACH(iface
, interfaces
, next
) {
683 if (iface
->type
& (IFACE_PHYSICAL_T
|IFACE_VLAN_T
|
684 IFACE_BOND_T
|IFACE_BRIDGE_T
))
686 if (iflinux_is_bond(cfg
, interfaces
, iface
)) {
687 log_debug("interfaces",
688 "interface %s is a bond",
690 iface
->type
|= IFACE_BOND_T
;
695 /* Query each interface to see if it is a vlan */
697 iflinux_add_vlan(struct lldpd
*cfg
,
698 struct interfaces_device_list
*interfaces
)
700 struct interfaces_device
*iface
;
702 TAILQ_FOREACH(iface
, interfaces
, next
) {
703 if (iface
->type
& (IFACE_PHYSICAL_T
|IFACE_VLAN_T
|
704 IFACE_BOND_T
|IFACE_BRIDGE_T
))
706 if (iflinux_is_vlan(cfg
, interfaces
, iface
)) {
707 log_debug("interfaces",
708 "interface %s is a VLAN",
710 iface
->type
|= IFACE_VLAN_T
;
716 iflinux_add_physical(struct lldpd
*cfg
,
717 struct interfaces_device_list
*interfaces
)
719 struct interfaces_device
*iface
;
721 TAILQ_FOREACH(iface
, interfaces
, next
) {
722 if (iface
->type
& (IFACE_VLAN_T
|
723 IFACE_BOND_T
|IFACE_BRIDGE_T
))
726 iface
->type
&= ~IFACE_PHYSICAL_T
;
728 /* We request that the interface is able to do either multicast
729 * or broadcast to be able to send discovery frames. */
730 if (!(iface
->flags
& (IFF_MULTICAST
|IFF_BROADCAST
))) {
731 log_debug("interfaces", "skip %s: not able to do multicast nor broadcast",
736 /* If the interface is linked to another one, skip it too. */
737 if (iface
->lower
&& (!iface
->driver
|| strcmp(iface
->driver
, "veth"))) {
738 log_debug("interfaces", "skip %s: there is a lower interface (%s)",
739 iface
->name
, iface
->lower
->name
);
743 /* Get the real MAC address (for example, if the interface is enslaved) */
744 iflinux_get_permanent_mac(cfg
, interfaces
, iface
);
746 log_debug("interfaces",
747 "%s is a physical interface",
749 iface
->type
|= IFACE_PHYSICAL_T
;
754 interfaces_update(struct lldpd
*cfg
)
756 struct lldpd_hardware
*hardware
;
757 struct interfaces_device_list
*interfaces
;
758 struct interfaces_address_list
*addresses
;
759 interfaces
= netlink_get_interfaces(cfg
);
760 addresses
= netlink_get_addresses(cfg
);
761 if (interfaces
== NULL
|| addresses
== NULL
) {
762 log_warnx("interfaces", "cannot update the list of local interfaces");
766 /* Add missing bits to list of interfaces */
767 iflinux_add_driver(cfg
, interfaces
);
768 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_WLAN
)
769 iflinux_add_wireless(cfg
, interfaces
);
770 if (LOCAL_CHASSIS(cfg
)->c_cap_available
& LLDP_CAP_BRIDGE
)
771 iflinux_add_bridge(cfg
, interfaces
);
772 iflinux_add_bond(cfg
, interfaces
);
773 iflinux_add_vlan(cfg
, interfaces
);
774 iflinux_add_physical(cfg
, interfaces
);
776 interfaces_helper_whitelist(cfg
, interfaces
);
777 iflinux_handle_bond(cfg
, interfaces
);
778 interfaces_helper_physical(cfg
, interfaces
,
782 interfaces_helper_vlan(cfg
, interfaces
);
784 interfaces_helper_mgmt(cfg
, addresses
);
785 interfaces_helper_chassis(cfg
, interfaces
);
788 TAILQ_FOREACH(hardware
, &cfg
->g_hardware
, h_entries
) {
789 if (!hardware
->h_flags
) continue;
790 iflinux_macphy(hardware
);
791 interfaces_helper_promisc(cfg
, hardware
);
796 interfaces_cleanup(struct lldpd
*cfg
)
798 netlink_cleanup(cfg
);