From 68bc4a4d6293dabb5fc7761fa41e01cd41632311 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sun, 15 Sep 2019 17:45:52 +0200 Subject: [PATCH] interfaces: enable matching on interface name for management address We allow the user to match a management address using the interface name by specifying the interface name as a pattern. The same rules as for specifying IP patterns apply but there is no notion of exact match for an interface. Fix #349. --- NEWS | 4 ++ src/client/lldpcli.8.in | 2 + src/daemon/interfaces-bsd.c | 2 +- src/daemon/interfaces-linux.c | 2 +- src/daemon/interfaces-solaris.c | 2 +- src/daemon/interfaces.c | 70 +++++++++++++++++---------------- src/daemon/lldpd.8.in | 2 + src/daemon/lldpd.h | 3 +- tests/integration/test_basic.py | 16 ++++++++ 9 files changed, 66 insertions(+), 37 deletions(-) diff --git a/NEWS b/NEWS index 2fb52626..0a27324a 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +lldpd (1.0.5) + * Changes: + + Interface names are also matched for management addresses. + lldpd (1.0.4) * Changes: + Add "configure system max-neighbors XX" command to modify maximum diff --git a/src/client/lldpcli.8.in b/src/client/lldpcli.8.in index bf902b0d..65b3d94d 100644 --- a/src/client/lldpcli.8.in +++ b/src/client/lldpcli.8.in @@ -391,6 +391,8 @@ without any check. If only negative patterns are provided, only one IPv4 and one IPv6 addresses are chosen. Otherwise, many of them can be selected. If you want to blacklist IPv6 addresses, you can use .Em !*:* . +If an interface name is matched, the first IPv4 address and the first +IPv6 address associated to this interface will be chosen. .Ed .Cd unconfigure diff --git a/src/daemon/interfaces-bsd.c b/src/daemon/interfaces-bsd.c index 458e02cd..341490a5 100644 --- a/src/daemon/interfaces-bsd.c +++ b/src/daemon/interfaces-bsd.c @@ -672,7 +672,7 @@ interfaces_update(struct lldpd *cfg) #ifdef ENABLE_DOT1 interfaces_helper_vlan(cfg, interfaces); #endif - interfaces_helper_mgmt(cfg, addresses); + interfaces_helper_mgmt(cfg, addresses, interfaces); interfaces_helper_chassis(cfg, interfaces); /* Mac/PHY */ diff --git a/src/daemon/interfaces-linux.c b/src/daemon/interfaces-linux.c index a8280c85..b57758d3 100644 --- a/src/daemon/interfaces-linux.c +++ b/src/daemon/interfaces-linux.c @@ -1020,7 +1020,7 @@ interfaces_update(struct lldpd *cfg) #ifdef ENABLE_DOT1 interfaces_helper_vlan(cfg, interfaces); #endif - interfaces_helper_mgmt(cfg, addresses); + interfaces_helper_mgmt(cfg, addresses, interfaces); interfaces_helper_chassis(cfg, interfaces); /* Mac/PHY */ diff --git a/src/daemon/interfaces-solaris.c b/src/daemon/interfaces-solaris.c index 0f9f5e53..f9d8bc52 100644 --- a/src/daemon/interfaces-solaris.c +++ b/src/daemon/interfaces-solaris.c @@ -164,7 +164,7 @@ interfaces_update(struct lldpd *cfg) { interfaces_helper_whitelist(cfg, interfaces); interfaces_helper_physical(cfg, interfaces, &bpf_ops, ifbpf_phys_init); - interfaces_helper_mgmt(cfg, addresses); + interfaces_helper_mgmt(cfg, addresses, interfaces); interfaces_helper_chassis(cfg, interfaces); /* Mac/PHY */ diff --git a/src/daemon/interfaces.c b/src/daemon/interfaces.c index e6fcc551..953e9711 100644 --- a/src/daemon/interfaces.c +++ b/src/daemon/interfaces.c @@ -390,9 +390,11 @@ static int interfaces_helper_mgmt_for_af(struct lldpd *cfg, int af, struct interfaces_address_list *addrs, + struct interfaces_device_list *interfaces, int global, int allnegative) { struct interfaces_address *addr; + struct interfaces_device *device; struct lldpd_mgmt *mgmt; char addrstrbuf[INET6_ADDRSTRLEN]; int found = 0; @@ -438,7 +440,11 @@ interfaces_helper_mgmt_for_af(struct lldpd *cfg, continue; } if (cfg->g_config.c_mgmt_pattern == NULL || - pattern_match(addrstrbuf, cfg->g_config.c_mgmt_pattern, allnegative)) { + /* Match on IP address */ + pattern_match(addrstrbuf, cfg->g_config.c_mgmt_pattern, allnegative) || + /* Match on interface name */ + ((device = interfaces_indextointerface(interfaces, addr->index)) && + pattern_match(device->name, cfg->g_config.c_mgmt_pattern, allnegative))) { mgmt = lldpd_alloc_mgmt(af, &in_addr, in_addr_size, addr->index); if (mgmt == NULL) { @@ -463,7 +469,8 @@ interfaces_helper_mgmt_for_af(struct lldpd *cfg, to the local chassis). */ void interfaces_helper_mgmt(struct lldpd *cfg, - struct interfaces_address_list *addrs) + struct interfaces_address_list *addrs, + struct interfaces_device_list *interfaces) { int allnegative = 0; int af; @@ -490,39 +497,36 @@ interfaces_helper_mgmt(struct lldpd *cfg, if (inet_pton(lldpd_af(af), pattern, &addr) == 1) break; } - if (af == LLDPD_AF_LAST) { - log_debug("interfaces", - "interface management pattern is an incorrect IP"); - return; - } - - /* Try to get the index if possible. */ - TAILQ_FOREACH(ifaddr, addrs, next) { - if (ifaddr->address.ss_family != lldpd_af(af)) - continue; - if (LLDPD_AF_IPV4 == af) { - struct sockaddr_in *sa_sin; - sa_sin = (struct sockaddr_in *)&ifaddr->address; - if ((sa_sin->sin_addr.s_addr) == ((struct in_addr *)&addr)->s_addr) - break; - } - else if (LLDPD_AF_IPV6 == af) { - if (0 == memcmp(&addr, - &((struct sockaddr_in6 *)&ifaddr->address)->sin6_addr, - addr_size)) - break; + if (af != LLDPD_AF_LAST) { + /* Try to get the index if possible. */ + TAILQ_FOREACH(ifaddr, addrs, next) { + if (ifaddr->address.ss_family != lldpd_af(af)) + continue; + if (LLDPD_AF_IPV4 == af) { + struct sockaddr_in *sa_sin; + sa_sin = (struct sockaddr_in *)&ifaddr->address; + if ((sa_sin->sin_addr.s_addr) == ((struct in_addr *)&addr)->s_addr) + break; + } + else if (LLDPD_AF_IPV6 == af) { + if (0 == memcmp(&addr, + &((struct sockaddr_in6 *)&ifaddr->address)->sin6_addr, + addr_size)) + break; + } } - } - mgmt = lldpd_alloc_mgmt(af, &addr, addr_size, ifaddr ? ifaddr->index : 0); - if (mgmt == NULL) { - log_warn("interfaces", "out of memory error"); + mgmt = lldpd_alloc_mgmt(af, &addr, addr_size, ifaddr ? ifaddr->index : 0); + if (mgmt == NULL) { + log_warn("interfaces", "out of memory error"); + return; + } + log_debug("interfaces", "add exact management address %s", + pattern); + TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries); return; } - log_debug("interfaces", "add exact management address %s", - pattern); - TAILQ_INSERT_TAIL(&LOCAL_CHASSIS(cfg)->c_mgmt, mgmt, m_entries); - return; + /* else: could be an interface name */ } /* Is the pattern provided all negative? */ @@ -538,8 +542,8 @@ interfaces_helper_mgmt(struct lldpd *cfg, /* Find management addresses */ for (af = LLDPD_AF_UNSPEC + 1; af != LLDPD_AF_LAST; af++) { - (void)(interfaces_helper_mgmt_for_af(cfg, af, addrs, 1, allnegative) || - interfaces_helper_mgmt_for_af(cfg, af, addrs, 0, allnegative)); + (void)(interfaces_helper_mgmt_for_af(cfg, af, addrs, interfaces, 1, allnegative) || + interfaces_helper_mgmt_for_af(cfg, af, addrs, interfaces, 0, allnegative)); } } diff --git a/src/daemon/lldpd.8.in b/src/daemon/lldpd.8.in index 9534ebb0..e5040434 100644 --- a/src/daemon/lldpd.8.in +++ b/src/daemon/lldpd.8.in @@ -198,6 +198,8 @@ without any check. If only negative patterns are provided, only one IPv4 and one IPv6 addresses are chosen. Otherwise, many of them can be selected. If you want to blacklist IPv6 addresses, you can use .Em !*:* . +If an interface name is matched, the first IPv4 address and the first +IPv6 address associated to this interface will be chosen. .It Fl u Ar file Specify the Unix-domain socket used for communication with .Xr lldpctl 8 . diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index cf25dd67..12c745ed 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -361,7 +361,8 @@ void interfaces_helper_port_name_desc(struct lldpd *, struct lldpd_hardware *, struct interfaces_device *); void interfaces_helper_mgmt(struct lldpd *, - struct interfaces_address_list *); + struct interfaces_address_list *, + struct interfaces_device_list *); #ifdef ENABLE_DOT1 void interfaces_helper_vlan(struct lldpd *, struct interfaces_device_list *); diff --git a/tests/integration/test_basic.py b/tests/integration/test_basic.py index 3e31d532..e0f1329d 100644 --- a/tests/integration/test_basic.py +++ b/tests/integration/test_basic.py @@ -180,6 +180,22 @@ def test_management_address(lldpd1, lldpd, lldpcli, links, namespaces): assert out["lldp.eth0.chassis.mgmt-iface"] == "2" +def test_management_interface(lldpd1, lldpd, lldpcli, links, namespaces): + links(namespaces(1), namespaces(2), 4) + with namespaces(2): + ipr = pyroute2.IPRoute() + idx = ipr.link_lookup(ifname="eth1")[0] + ipr.addr('add', index=idx, address="192.168.14.2", mask=24) + idx = ipr.link_lookup(ifname="eth3")[0] + ipr.addr('add', index=idx, address="172.25.21.47", mask=24) + lldpd("-m", "eth3") + with namespaces(1): + out = lldpcli("-f", "keyvalue", "show", "neighbors") + assert out["lldp.eth0.chassis.mgmt-ip"] == ["172.25.21.47", + "fe80::200:ff:fe00:4"] + assert out["lldp.eth0.chassis.mgmt-iface"] == ["4", "4"] + + def test_change_management_address(lldpd1, lldpd, lldpcli, links, namespaces): with namespaces(2): ipr = pyroute2.IPRoute() -- 2.39.5