* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define INCLUDE_LINUX_IF_H
#include "lldpd.h"
#include <stdio.h>
#include <linux/sockios.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
+#include <linux/ethtool.h>
#define SYSFS_PATH_MAX 256
#define MAX_PORTS 1024
static struct sock_filter lldpd_filter_f[] = { LLDPD_FILTER_F };
-/* net/if.h */
-extern unsigned int if_nametoindex (__const char *__ifname) __THROW;
-extern char *if_indextoname (unsigned int __ifindex, char *__ifname) __THROW;
-
struct lldpd_ops eth_ops;
struct lldpd_ops bond_ops;
}
static int
-old_iface_is_bridge(struct lldpd *cfg, const char *name)
+iface_nametoindex(struct netlink_interface_list *interfaces,
+ const char *device)
+{
+ struct netlink_interface *iface;
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (!strcmp(iface->name, device))
+ return iface->index;
+ }
+ log_debug("interfaces", "cannot get interface index for %s",
+ device);
+ return 0;
+}
+
+static int
+iface_indextoname(struct netlink_interface_list *interfaces,
+ int index, char *name)
+{
+ struct netlink_interface *iface;
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (iface->index == index) {
+ strncpy(name, iface->name, IFNAMSIZ);
+ return 0;
+ }
+ }
+ log_debug("interfaces", "cannot get interface name for index %d",
+ index);
+ return -1;
+}
+
+static int
+old_iface_is_bridge(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *name)
{
int ifindices[MAX_BRIDGES];
char ifname[IFNAMSIZ];
to fill logs. */
return 0;
for (i = 0; i < num; i++) {
- if (if_indextoname(ifindices[i], ifname) == NULL)
+ if (iface_indextoname(interfaces, ifindices[i], ifname) == -1)
log_info("interfaces", "unable to get name of interface %d",
ifindices[i]);
else if (strncmp(name, ifname, IFNAMSIZ) == 0)
}
static int
-iface_is_bridge(struct lldpd *cfg, const char *name)
+iface_is_bridge(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *name)
{
#ifdef SYSFS_BRIDGE_FDB
char path[SYSFS_PATH_MAX];
SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_FDB, name)) >= SYSFS_PATH_MAX)
log_warnx("interfaces", "path truncated");
if ((f = priv_open(path)) < 0) {
- return old_iface_is_bridge(cfg, name);
+ return old_iface_is_bridge(cfg, interfaces, name);
}
close(f);
return 1;
#else
- return old_iface_is_bridge(cfg, name);
+ return old_iface_is_bridge(cfg, interfaces, name);
#endif
}
#ifdef ENABLE_DOT1
static int
-old_iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
+old_iface_is_bridged_to(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *slave, const char *master)
{
- int j, index = if_nametoindex(slave);
+ int j, index = iface_nametoindex(interfaces, slave);
int ifptindices[MAX_PORTS];
unsigned long args2[4] = { BRCTL_GET_PORT_LIST,
(unsigned long)ifptindices, MAX_PORTS, 0 };
struct ifreq ifr;
+ if (index == 0) return 0;
strncpy(ifr.ifr_name, master, IFNAMSIZ);
memset(ifptindices, 0, sizeof(ifptindices));
}
static int
-iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
+iface_is_bridged_to(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *slave, const char *master)
{
#ifdef SYSFS_BRIDGE_PORT_SUBDIR
char path[SYSFS_PATH_MAX];
int f;
/* Master should be a bridge, first */
- if (!iface_is_bridge(cfg, master)) return 0;
+ if (!iface_is_bridge(cfg, interfaces, master)) return 0;
if (snprintf(path, SYSFS_PATH_MAX,
SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_PORT_SUBDIR "/%s/port_no",
master, slave) >= SYSFS_PATH_MAX)
log_warnx("interfaces", "path truncated");
if ((f = priv_open(path)) < 0) {
- return old_iface_is_bridged_to(cfg, slave, master);
+ return old_iface_is_bridged_to(cfg, interfaces, slave, master);
}
close(f);
return 1;
#else
- return old_iface_is_bridged_to(cfg, slave, master);
+ return old_iface_is_bridged_to(cfg, interfaces, slave, master);
#endif
}
#endif
}
static int
-iface_is_enslaved(struct lldpd *cfg, const char *name)
+iface_is_enslaved(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *name)
{
- struct ifaddrs *ifap, *ifa;
+ struct netlink_interface *iface;
int master;
- if (getifaddrs(&ifap) != 0) {
- log_warn("interfaces", "unable to get interface list");
- return -1;
- }
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (iface_is_bond_slave(cfg, name, ifa->ifa_name, NULL)) {
- master = if_nametoindex(ifa->ifa_name);
- freeifaddrs(ifap);
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (iface_is_bond_slave(cfg, name, iface->name, NULL)) {
+ master = iface->index;
return master;
}
}
- freeifaddrs(ifap);
return -1;
}
static void
-iface_get_permanent_mac(struct lldpd *cfg, struct lldpd_hardware *hardware)
+iface_get_permanent_mac(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ struct lldpd_hardware *hardware)
{
int master, f, state = 0;
FILE *netbond;
log_debug("interfaces", "get MAC address for %s",
hardware->h_ifname);
- if ((master = iface_is_enslaved(cfg, hardware->h_ifname)) == -1)
+ if ((master = iface_is_enslaved(cfg, interfaces,
+ hardware->h_ifname)) == -1)
return;
/* We have a bond, we need to query it to get real MAC addresses */
- if ((if_indextoname(master, bond)) == NULL) {
+ if ((iface_indextoname(interfaces, master, bond)) == -1) {
log_warnx("interfaces", "unable to get bond name");
return;
}
/* Generic minimal checks to handle a given interface. */
static int
-iface_minimal_checks(struct lldpd *cfg, struct ifaddrs *ifa)
+iface_minimal_checks(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ struct netlink_interface *iface)
{
- struct sockaddr_ll sdl;
struct ifreq ifr;
struct ethtool_drvinfo ethc;
const char * const *rif;
NULL
};
- int is_bridge = iface_is_bridge(cfg, ifa->ifa_name);
+ int is_bridge = iface_is_bridge(cfg, interfaces, iface->name);
- log_debug("interfaces", "minimal checks for %s", ifa->ifa_name);
+ log_debug("interfaces", "minimal checks for %s", iface->name);
if (!(LOCAL_CHASSIS(cfg)->c_cap_enabled & LLDP_CAP_BRIDGE) &&
is_bridge) {
log_debug("interfaces", "skip %s: is a bridge",
- ifa->ifa_name);
+ iface->name);
LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
return 0;
}
if (!(LOCAL_CHASSIS(cfg)->c_cap_enabled & LLDP_CAP_WLAN) &&
- iface_is_wireless(cfg, ifa->ifa_name))
+ iface_is_wireless(cfg, iface->name))
LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
/* First, check if this interface has already been handled */
- if (!ifa->ifa_flags) {
+ if (!iface->flags) {
log_debug("interfaces", "skip %s: already been handled",
- ifa->ifa_name);
+ iface->name);
return 0;
}
- if (ifa->ifa_addr == NULL) {
- if (ifa->ifa_addr->sa_family != PF_PACKET) {
- log_debug("interfaces", "skip %s: address family is %d and not PF_PACKET",
- ifa->ifa_name, ifa->ifa_addr->sa_family);
- return 0;
- }
- log_debug("interfaces", "skip %s: no address",
- ifa->ifa_name);
- }
-
- memcpy(&sdl, ifa->ifa_addr, sizeof(struct sockaddr_ll));
- if (sdl.sll_hatype != ARPHRD_ETHER || !sdl.sll_halen) {
+ if (iface->type != ARPHRD_ETHER) {
log_debug("interfaces", "skip %s: not an Ethernet device",
- ifa->ifa_name);
+ iface->name);
return 0;
}
/* We request that the interface is able to do either multicast
* or broadcast to be able to send discovery frames. */
- if (!(ifa->ifa_flags & (IFF_MULTICAST|IFF_BROADCAST))) {
+ if (!(iface->flags & (IFF_MULTICAST|IFF_BROADCAST))) {
log_debug("interfaces", "skip %s: not able to do multicast nor broadcast",
- ifa->ifa_name);
+ iface->name);
+ return 0;
+ }
+
+ /* If the interface is linked to another one, skip it too. */
+ if (iface->link != -1 && iface->index != iface->link) {
+ log_debug("interfaces", "skip %s: there is a lower interface (%d)",
+ iface->name, iface->link);
return 0;
}
/* Check if the driver is whitelisted */
memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, ifa->ifa_name);
+ strcpy(ifr.ifr_name, iface->name);
memset(ðc, 0, sizeof(ethc));
ifr.ifr_data = (caddr_t) ðc;
ethc.cmd = ETHTOOL_GDRVINFO;
if (strcmp(ethc.driver, *rif) == 0) {
/* White listed! */
log_debug("interfaces", "accept %s: whitelisted",
- ifa->ifa_name);
+ iface->name);
return 1;
}
}
}
- log_debug("interfaces", "keep %s: not whitelisted",
- ifa->ifa_name);
+ log_debug("interfaces", "keep checking %s: not whitelisted",
+ iface->name);
/* Check queue len. If no queue, this usually means that this
is not a "real" interface. */
- memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, ifa->ifa_name);
- if ((ioctl(cfg->g_sock, SIOCGIFTXQLEN, &ifr) < 0) || !ifr.ifr_qlen) {
+ if (iface->txqueue == 0) {
log_debug("interfaces", "skip %s: no queue",
- ifa->ifa_name);
+ iface->name);
return 0;
}
/* Don't handle bond and VLAN, nor bridge */
- if (iface_is_vlan(cfg, ifa->ifa_name)) {
+ if (iface_is_vlan(cfg, iface->name)) {
log_debug("interfaces", "skip %s: is a VLAN",
- ifa->ifa_name);
+ iface->name);
return 0;
}
- if (iface_is_bond(cfg, ifa->ifa_name)) {
+ if (iface_is_bond(cfg, iface->name)) {
log_debug("interfaces", "skip %s: is a bond",
- ifa->ifa_name);
+ iface->name);
return 0;
}
if (is_bridge) {
log_debug("interfaces", "skip %s: is a bridge",
- ifa->ifa_name);
+ iface->name);
return 0;
}
log_debug("interfaces", "%s passes the minimal checks",
- ifa->ifa_name);
+ iface->name);
return 1;
}
/* Fill up port name and description */
static void
-iface_port_name_desc(struct lldpd_hardware *hardware)
+iface_port_name_desc(struct lldpd_hardware *hardware, struct netlink_interface *iface)
{
struct lldpd_port *port = &hardware->h_lport;
- char buffer[256]; /* 256 = IFALIASZ */
- char path[SYSFS_PATH_MAX];
- int f;
/* There are two cases:
port name in description.
*/
- if ((snprintf(path, SYSFS_PATH_MAX,
- SYSFS_CLASS_NET "%s/ifalias", hardware->h_ifname)) >= SYSFS_PATH_MAX)
- log_warnx("interfaces", "path truncated");
- memset(buffer, 0, sizeof(buffer));
- if (((f = priv_open(path)) < 0) || (read(f, buffer, sizeof(buffer)-1) < 1)) {
+ if (iface->alias == NULL || strlen(iface->alias) == 0) {
/* Case 2: MAC address and port name */
- close(f);
log_debug("interfaces", "use ifname and MAC address for %s",
hardware->h_ifname);
port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
return;
}
/* Case 1: port name and port description */
- close(f);
log_debug("interfaces", "use ifname and ifalias for %s",
hardware->h_ifname);
port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
calloc(1, port->p_id_len)) == NULL)
fatal("interfaces", NULL);
memcpy(port->p_id, hardware->h_ifname, port->p_id_len);
- if (buffer[strlen(buffer) - 1] == '\n')
- buffer[strlen(buffer) - 1] = '\0';
- port->p_descr = strdup(buffer);
+ port->p_descr = strdup(iface->alias);
}
/* Fill up MAC/PHY for a given hardware port */
log_debug("interfaces", "ask ethtool for the appropriate MAC/PHY for %s",
hardware->h_ifname);
- if (priv_ethtool(hardware->h_ifname, ðc) == 0) {
+ if (priv_ethtool(hardware->h_ifname, ðc, sizeof(struct ethtool_cmd)) == 0) {
port->p_macphy.autoneg_support = (ethc.supported & SUPPORTED_Autoneg) ? 1 : 0;
port->p_macphy.autoneg_enabled = (ethc.autoneg == AUTONEG_DISABLE) ? 0 : 1;
for (j=0; advertised_ethtool_to_rfc3636[j][0]; j++) {
#endif
}
-static void
-iface_mtu(struct lldpd *cfg, struct lldpd_hardware *hardware)
-{
- struct ifreq ifr;
-
- /* get MTU */
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, hardware->h_ifname, sizeof(ifr.ifr_name));
- if (ioctl(cfg->g_sock, SIOCGIFMTU, (char*)&ifr) == -1) {
- log_warn("interfaces", "unable to get MTU of %s, using 1500", hardware->h_ifname);
- hardware->h_mtu = 1500;
- } else
- hardware->h_mtu = ifr.ifr_mtu;
-}
-
static void
iface_multicast(struct lldpd *cfg, const char *name, int remove)
{
log_debug("interfaces", "initialize ethernet device %s",
hardware->h_ifname);
- if ((fd = priv_iface_init(hardware->h_ifname)) == -1)
+ if ((fd = priv_iface_init(hardware->h_ifindex)) == -1)
return -1;
hardware->h_sendfd = fd; /* Send */
iface_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware,
char *buffer, size_t size)
{
- log_debug("interfaces", "send PDU to ethernet device %s",
- hardware->h_ifname);
+ log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)",
+ hardware->h_ifname, hardware->h_sendfd);
return write(hardware->h_sendfd,
buffer, size);
}
return 0;
}
-void
-lldpd_ifh_eth(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_eth(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
struct lldpd_hardware *hardware;
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (!iface_minimal_checks(cfg, ifa))
+ TAILQ_FOREACH(iface, interfaces, next) {
+ log_debug("interfaces", "check if %s is a real ethernet device",
+ iface->name);
+ if (!iface_minimal_checks(cfg, interfaces, iface))
continue;
log_debug("interfaces", "%s is an acceptable ethernet device",
- ifa->ifa_name);
+ iface->name);
if ((hardware = lldpd_get_hardware(cfg,
- ifa->ifa_name,
- if_nametoindex(ifa->ifa_name),
+ iface->name,
+ iface->index,
ð_ops)) == NULL) {
if ((hardware = lldpd_alloc_hardware(cfg,
- ifa->ifa_name)) == NULL) {
+ iface->name,
+ iface->index)) == NULL) {
log_warnx("interfaces", "Unable to allocate space for %s",
- ifa->ifa_name);
+ iface->name);
continue;
}
if (iface_eth_init(cfg, hardware) != 0) {
continue;
}
hardware->h_ops = ð_ops;
- hardware->h_ifindex = if_nametoindex(ifa->ifa_name);
TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
} else {
if (hardware->h_flags) continue; /* Already seen this time */
lldpd_port_cleanup(&hardware->h_lport, 0);
}
- hardware->h_flags = ifa->ifa_flags; /* Should be non-zero */
- ifa->ifa_flags = 0; /* Future handlers
+ hardware->h_flags = iface->flags; /* Should be non-zero */
+ iface->flags = 0; /* Future handlers
don't have to
care about this
interface. */
/* Get local address */
- memcpy(&hardware->h_lladdr,
- (u_int8_t*)((u_int8_t*)ifa->ifa_addr +
- offsetof(struct sockaddr_ll, sll_addr)),
- sizeof(hardware->h_lladdr));
+ memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
/* Fill information about port */
- iface_port_name_desc(hardware);
+ iface_port_name_desc(hardware, iface);
/* Fill additional info */
iface_macphy(hardware);
- iface_mtu(cfg, hardware);
+ hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
}
}
-void
-lldpd_ifh_whitelist(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_whitelist(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
if (!cfg->g_config.c_iface_pattern)
return;
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_flags == 0) continue; /* Already handled by someone else */
- if (!pattern_match(ifa->ifa_name, cfg->g_config.c_iface_pattern, 0)) {
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (iface->flags == 0) continue; /* Already handled by someone else */
+ if (!pattern_match(iface->name, cfg->g_config.c_iface_pattern, 0)) {
/* This interface was not found. We flag it. */
- log_debug("interfaces", "blacklist %s", ifa->ifa_name);
- ifa->ifa_flags = 0;
+ log_debug("interfaces", "blacklist %s", iface->name);
+ iface->flags = 0;
}
}
}
+struct bond_master {
+ char name[IFNAMSIZ];
+ int index;
+};
+
static int
iface_bond_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
{
- char *mastername = (char *)hardware->h_data; /* Master name */
+ struct bond_master *master = hardware->h_data;
int fd, status;
int un = 1;
- if (!mastername) return -1;
+ if (!master) return -1;
log_debug("interfaces", "initialize bonded device %s",
hardware->h_ifname);
/* First, we get a socket to the raw physical interface */
- if ((fd = priv_iface_init(hardware->h_ifname)) == -1)
+ if ((fd = priv_iface_init(hardware->h_ifindex)) == -1)
return -1;
hardware->h_sendfd = fd;
if ((status = iface_set_filter(hardware->h_ifname, fd)) != 0) {
iface_multicast(cfg, hardware->h_ifname, 0);
/* Then, we open a raw interface for the master */
- if ((fd = priv_iface_init(mastername)) == -1) {
+ if ((fd = priv_iface_init(master->index)) == -1) {
close(hardware->h_sendfd);
return -1;
}
- if ((status = iface_set_filter(mastername, fd)) != 0) {
+ if ((status = iface_set_filter(master->name, fd)) != 0) {
close(hardware->h_sendfd);
close(fd);
return status;
* physical device instead of bond device (works with >=
* 2.6.24). */
if (setsockopt(fd, SOL_PACKET,
- PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
- log_debug("interfaces", "unable to setsockopt for master bonding device of %s. "
- "You will get inaccurate results",
- hardware->h_ifname);
+ PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
+ log_info("interfaces", "unable to setsockopt for master bonding device of %s. "
+ "You will get inaccurate results",
+ hardware->h_ifname);
}
- iface_multicast(cfg, mastername, 0);
+ iface_multicast(cfg, master->name, 0);
levent_hardware_add_fd(hardware, hardware->h_sendfd);
levent_hardware_add_fd(hardware, fd);
log_debug("interfaces", "interface %s initialized (fd=%d,master=%s[%d])",
hardware->h_ifname,
hardware->h_sendfd,
- mastername, fd);
+ master->name, fd);
return 0;
}
/* With bonds, we have duplicate MAC address on different physical
* interfaces. We need to alter the source MAC address when we send on
* an inactive slave. */
- char *master = (char*)hardware->h_data;
+ struct bond_master *master = hardware->h_data;
int active;
log_debug("interfaces", "send PDU to bonded device %s",
hardware->h_ifname);
- if (!iface_is_bond_slave(cfg, hardware->h_ifname, master, &active)) {
+ if (!iface_is_bond_slave(cfg, hardware->h_ifname, master->name, &active)) {
log_warnx("interfaces", "%s seems to not be enslaved anymore?",
hardware->h_ifname);
return 0;
int n;
struct sockaddr_ll from;
socklen_t fromlen;
+ struct bond_master *master = hardware->h_data;
log_debug("interfaces", "receive PDU from bonded device %s",
hardware->h_ifname);
if (from.sll_ifindex == hardware->h_ifindex)
/* This is for us */
return n;
- if (from.sll_ifindex == if_nametoindex((char*)hardware->h_data))
+ if (from.sll_ifindex == master->index)
/* We don't know from which physical interface it comes (kernel
* < 2.6.24). In doubt, this is for us. */
return n;
static int
iface_bond_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
{
+ struct bond_master *master = hardware->h_data;
log_debug("interfaces", "closing bonded device %s",
hardware->h_ifname);
iface_multicast(cfg, hardware->h_ifname, 1);
- iface_multicast(cfg, (char*)hardware->h_data, 1);
+ iface_multicast(cfg, master->name, 1);
free(hardware->h_data);
return 0;
}
-void
-lldpd_ifh_bond(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_bond(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
struct lldpd_hardware *hardware;
- int master;
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (!iface_minimal_checks(cfg, ifa))
+ struct bond_master *master;
+ int idx;
+ TAILQ_FOREACH(iface, interfaces, next) {
+ log_debug("interfaces", "check if %s is part of a bond",
+ iface->name);
+ if (!iface_minimal_checks(cfg, interfaces, iface))
continue;
- if ((master = iface_is_enslaved(cfg, ifa->ifa_name)) == -1)
+ if ((idx = iface_is_enslaved(cfg, interfaces,
+ iface->name)) == -1)
continue;
log_debug("interfaces", "%s is an acceptable bonded device (master=%d)",
- ifa->ifa_name, master);
+ iface->name, idx);
if ((hardware = lldpd_get_hardware(cfg,
- ifa->ifa_name,
- if_nametoindex(ifa->ifa_name),
+ iface->name,
+ iface->index,
&bond_ops)) == NULL) {
if ((hardware = lldpd_alloc_hardware(cfg,
- ifa->ifa_name)) == NULL) {
+ iface->name,
+ iface->index)) == NULL) {
log_warnx("interfaces", "Unable to allocate space for %s",
- ifa->ifa_name);
+ iface->name);
+ continue;
+ }
+ hardware->h_data = master = calloc(1, sizeof(struct bond_master));
+ if (!hardware->h_data) {
+ log_warn("interfaces", "not enough memory");
+ lldpd_hardware_cleanup(cfg, hardware);
+ continue;
+ }
+ master->index = idx;
+ if (iface_indextoname(interfaces, master->index, master->name) == -1) {
+ lldpd_hardware_cleanup(cfg, hardware);
continue;
}
- hardware->h_data = (char *)calloc(1, IFNAMSIZ);
- if_indextoname(master, hardware->h_data);
if (iface_bond_init(cfg, hardware) != 0) {
log_warn("interfaces", "unable to initialize %s",
hardware->h_ifname);
continue;
}
hardware->h_ops = &bond_ops;
- hardware->h_ifindex = if_nametoindex(ifa->ifa_name);
TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
} else {
if (hardware->h_flags) continue; /* Already seen this time */
- memset(hardware->h_data, 0, IFNAMSIZ);
- if_indextoname(master, hardware->h_data);
+ master = hardware->h_data;
+ memset(hardware->h_data, 0, sizeof(struct bond_master));
+ master->index = idx;
+ iface_indextoname(interfaces, master->index, master->name);
lldpd_port_cleanup(&hardware->h_lport, 0);
}
-
- hardware->h_flags = ifa->ifa_flags;
- ifa->ifa_flags = 0;
+
+ hardware->h_flags = iface->flags;
+ iface->flags = 0;
/* Get local address */
- iface_get_permanent_mac(cfg, hardware);
-
+ iface_get_permanent_mac(cfg, interfaces, hardware);
+
/* Fill information about port */
- iface_port_name_desc(hardware);
-
+ iface_port_name_desc(hardware, iface);
+
/* Fill additional info */
#ifdef ENABLE_DOT3
- hardware->h_lport.p_aggregid = master;
+ hardware->h_lport.p_aggregid = master->index;
#endif
iface_macphy(hardware);
- iface_mtu(cfg, hardware);
+ hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
}
}
#ifdef ENABLE_DOT1
static void
iface_append_vlan(struct lldpd *cfg,
- struct lldpd_hardware *hardware, struct ifaddrs *ifa)
+ struct lldpd_hardware *hardware, struct netlink_interface *iface)
{
struct lldpd_port *port = &hardware->h_lport;
struct lldpd_vlan *vlan;
/* Check if the VLAN is already here. */
TAILQ_FOREACH(vlan, &port->p_vlans, v_entries)
- if (strncmp(ifa->ifa_name, vlan->v_name, IFNAMSIZ) == 0)
+ if (strncmp(iface->name, vlan->v_name, IFNAMSIZ) == 0)
return;
if ((vlan = (struct lldpd_vlan *)
calloc(1, sizeof(struct lldpd_vlan))) == NULL)
return;
- if ((vlan->v_name = strdup(ifa->ifa_name)) == NULL) {
+ if ((vlan->v_name = strdup(iface->name)) == NULL) {
free(vlan);
return;
}
memset(&ifv, 0, sizeof(ifv));
ifv.cmd = GET_VLAN_VID_CMD;
- strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
+ strlcpy(ifv.device1, iface->name, sizeof(ifv.device1));
if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
/* Dunno what happened */
free(vlan->v_name);
TAILQ_INSERT_TAIL(&port->p_vlans, vlan, v_entries);
}
-void
-lldpd_ifh_vlan(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_vlan(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
struct vlan_ioctl_args ifv;
struct lldpd_hardware *hardware;
-
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (!ifa->ifa_flags)
+
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (!iface->flags)
continue;
- if (!iface_is_vlan(cfg, ifa->ifa_name))
+ if (!iface_is_vlan(cfg, iface->name))
continue;
/* We need to find the physical interfaces of this
vlan, through bonds and bridges. */
+ /* TODO: use iflink instead? Possible since 2.6.17 only. */
log_debug("interfaces", "search physical interface for VLAN interface %s",
- ifa->ifa_name);
+ iface->name);
memset(&ifv, 0, sizeof(ifv));
ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
- strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
+ strlcpy(ifv.device1, iface->name, sizeof(ifv.device1));
if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) {
/* Three cases:
1. we get a real device
2. we get a bond
3. we get a bridge
*/
+ int idx = iface_nametoindex(interfaces, ifv.u.device2);
+ if (idx == 0) continue;
if ((hardware = lldpd_get_hardware(cfg,
ifv.u.device2,
- if_nametoindex(ifv.u.device2),
+ idx,
NULL)) == NULL) {
if (iface_is_bond(cfg, ifv.u.device2)) {
TAILQ_FOREACH(hardware, &cfg->g_hardware,
hardware->h_ifname,
ifv.u.device2);
iface_append_vlan(cfg,
- hardware, ifa);
+ hardware, iface);
}
- } else if (iface_is_bridge(cfg, ifv.u.device2)) {
+ } else if (iface_is_bridge(cfg, interfaces, ifv.u.device2)) {
TAILQ_FOREACH(hardware, &cfg->g_hardware,
h_entries)
if (iface_is_bridged_to(cfg,
+ interfaces,
hardware->h_ifname,
ifv.u.device2)) {
log_debug("interfaces",
hardware->h_ifname,
ifv.u.device2);
iface_append_vlan(cfg,
- hardware, ifa);
+ hardware, iface);
}
}
} else iface_append_vlan(cfg,
- hardware, ifa);
+ hardware, iface);
}
}
}
#define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a))
#endif
#ifndef IN6_IS_ADDR_GLOBAL
-#define IN6_IS_ADDR_GLOBAL(a) (!IN6_IS_ADDR_LOOPBACK(a) && \
- !IN6_IS_ADDR_LINKLOCAL(a))
+#define IN6_IS_ADDR_GLOBAL(a) \
+ (!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
#endif
/* Find a management address in all available interfaces, even those that were
already handled. This is a special interface handler because it does not
really handle interface related information (management address is attached
to the local chassis). */
-void
-lldpd_ifh_mgmt(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_mgmt(struct lldpd *cfg, struct netlink_address_list *addrs)
{
- struct ifaddrs *ifa;
+ struct netlink_address *addr;
char addrstrbuf[INET6_ADDRSTRLEN];
struct lldpd_mgmt *mgmt;
void *sin_addr_ptr;
example !*:*,!10.* will only blacklist
addresses. We will pick the first IPv4 address not
matching 10.*. */
- for (ifa = ifap;
- ifa != NULL;
- ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL)
- continue;
- if (ifa->ifa_addr->sa_family != lldpd_af(af))
+ TAILQ_FOREACH(addr, addrs, next) {
+ if (addr->address.ss_family != lldpd_af(af))
continue;
switch (af) {
case LLDPD_AF_IPV4:
- sin_addr_ptr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
+ sin_addr_ptr = &((struct sockaddr_in *)&addr->address)->sin_addr;
sin_addr_size = sizeof(struct in_addr);
if (!IN_IS_ADDR_GLOBAL((struct in_addr *)sin_addr_ptr))
continue;
break;
case LLDPD_AF_IPV6:
- sin_addr_ptr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+ sin_addr_ptr = &((struct sockaddr_in6 *)&addr->address)->sin6_addr;
sin_addr_size = sizeof(struct in6_addr);
if (!IN6_IS_ADDR_GLOBAL((struct in6_addr *)sin_addr_ptr))
continue;
continue;
}
if (inet_ntop(lldpd_af(af), sin_addr_ptr,
- addrstrbuf, sizeof(addrstrbuf)) == NULL) {
+ addrstrbuf, sizeof(addrstrbuf)) == NULL) {
log_warn("interfaces", "unable to convert IP address to a string");
continue;
}
if (cfg->g_config.c_mgmt_pattern == NULL ||
pattern_match(addrstrbuf, cfg->g_config.c_mgmt_pattern, allnegative)) {
mgmt = lldpd_alloc_mgmt(af, sin_addr_ptr, sin_addr_size,
- if_nametoindex(ifa->ifa_name));
+ addr->index);
if (mgmt == NULL) {
assert(errno == ENOMEM); /* anything else is a bug */
log_warn("interfaces", "out of memory error");
/* Fill out chassis ID if not already done. This handler is special
because we will only handle interfaces that are already handled. */
-void
-lldpd_ifh_chassis(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_chassis(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
struct lldpd_hardware *hardware;
char *name = NULL;
LOCAL_CHASSIS(cfg)->c_id_subtype == LLDP_CHASSISID_SUBTYPE_LLADDR)
return; /* We already have one */
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_flags) continue;
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (iface->flags) continue;
if (cfg->g_config.c_cid_pattern &&
- !pattern_match(ifa->ifa_name, cfg->g_config.c_cid_pattern, 0)) continue;
+ !pattern_match(iface->name, cfg->g_config.c_cid_pattern, 0)) continue;
if ((hardware = lldpd_get_hardware(cfg,
- ifa->ifa_name,
- if_nametoindex(ifa->ifa_name),
+ iface->name,
+ iface->index,
NULL)) == NULL)
/* That's odd. Let's skip. */
continue;
.recv = iface_bond_recv,
.cleanup = iface_bond_close,
};
+
+void
+interfaces_update(struct lldpd *cfg)
+{
+ struct netlink_interface_list *interfaces = NULL;
+ struct netlink_address_list *addresses = NULL;
+ interfaces = netlink_get_interfaces();
+ addresses = netlink_get_addresses();
+ if (interfaces == NULL || addresses == NULL) {
+ log_warnx("interfaces", "cannot update the list of local interfaces");
+ goto end;
+ }
+
+ lldpd_ifh_whitelist(cfg, interfaces);
+ lldpd_ifh_bond(cfg, interfaces);
+ lldpd_ifh_eth(cfg, interfaces);
+#ifdef ENABLE_DOT1
+ lldpd_ifh_vlan(cfg, interfaces);
+#endif
+ lldpd_ifh_mgmt(cfg, addresses);
+ lldpd_ifh_chassis(cfg, interfaces);
+
+end:
+ netlink_free_interfaces(interfaces);
+ netlink_free_addresses(addresses);
+ return;
+
+}