From: Vincent Bernat Date: Sun, 12 Dec 2021 13:25:13 +0000 (+0100) Subject: interfaces: detect interface index changes X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0ffff892a64df19419705c6dfb7606078a0fe358;p=thirdparty%2Flldpd.git interfaces: detect interface index changes When an interface is deleted and recreated, we didn't detect any change and just updated its index. However, the handles we had on this interface are now invalid. Ensure the interface is correctly reinitialized in this case. Fix #490. --- diff --git a/NEWS b/NEWS index 6c1a9717..698a052f 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,7 @@ lldpd (1.0.14) * Fix: + Update seccomp rules for newer kernel/libc (#488) + + Correctly handle an interface whose index has changed (#490) lldpd (1.0.13) * Fix: diff --git a/src/daemon/interfaces-linux.c b/src/daemon/interfaces-linux.c index 47b75fca..da0df7f1 100644 --- a/src/daemon/interfaces-linux.c +++ b/src/daemon/interfaces-linux.c @@ -803,7 +803,7 @@ iflinux_handle_bond(struct lldpd *cfg, struct interfaces_device_list *interfaces created = 1; } if (hardware->h_flags) continue; - if (hardware->h_ops != &bond_ops) { + if (hardware->h_ops != &bond_ops || hardware->h_ifindex_changed) { if (!created) { log_debug("interfaces", "bond %s is converted from another type of interface", @@ -822,7 +822,7 @@ iflinux_handle_bond(struct lldpd *cfg, struct interfaces_device_list *interfaces } else bmaster = hardware->h_data; bmaster->index = master->index; strlcpy(bmaster->name, master->name, IFNAMSIZ); - if (hardware->h_ops != &bond_ops) { + if (hardware->h_ops != &bond_ops || hardware->h_ifindex_changed) { if (iface_bond_init(cfg, hardware) != 0) { log_warn("interfaces", "unable to initialize %s", hardware->h_ifname); diff --git a/src/daemon/interfaces.c b/src/daemon/interfaces.c index 31ecad8b..4cd600df 100644 --- a/src/daemon/interfaces.c +++ b/src/daemon/interfaces.c @@ -679,7 +679,7 @@ interfaces_helper_physical(struct lldpd *cfg, } if (hardware->h_flags) continue; - if (hardware->h_ops != ops) { + if (hardware->h_ops != ops || hardware->h_ifindex_changed) { if (!created) { log_debug("interfaces", "interface %s is converted from another type of interface", diff --git a/src/daemon/lldpd.c b/src/daemon/lldpd.c index c717c012..22ae7463 100644 --- a/src/daemon/lldpd.c +++ b/src/daemon/lldpd.c @@ -147,6 +147,12 @@ lldpd_get_hardware(struct lldpd *cfg, char *name, int index) TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) { if (strcmp(hardware->h_ifname, name) == 0) { if (hardware->h_flags == 0) { + if (hardware->h_ifindex != 0 && + hardware->h_ifindex != index) { + log_debug("interfaces", "%s changed index: from %d to %d", + hardware->h_ifname, hardware->h_ifindex, index); + hardware->h_ifindex_changed = 1; + } hardware->h_ifindex = index; break; } @@ -392,7 +398,8 @@ lldpd_reset_timer(struct lldpd *cfg) } /* Compare with the previous value */ - if (hardware->h_lport_previous && + if (!hardware->h_ifindex_changed && + hardware->h_lport_previous && output_len == hardware->h_lport_previous_len && !memcmp(output, hardware->h_lport_previous, output_len)) { log_debug("localchassis", @@ -402,6 +409,7 @@ lldpd_reset_timer(struct lldpd *cfg) log_debug("localchassis", "change detected for port %s, resetting its timer", hardware->h_ifname); + hardware->h_ifindex_changed = 0; levent_schedule_pdu(hardware); } diff --git a/src/lldpd-structs.h b/src/lldpd-structs.h index 390b10f4..e98a0551 100644 --- a/src/lldpd-structs.h +++ b/src/lldpd-structs.h @@ -474,6 +474,7 @@ struct lldpd_hardware { removed if this is left to 0. */ int h_ifindex; /* Interface index, used by SNMP */ + int h_ifindex_changed; /* Interface index has changed */ char h_ifname[IFNAMSIZ]; /* Should be unique */ u_int8_t h_lladdr[ETHER_ADDR_LEN]; diff --git a/tests/integration/test_interfaces.py b/tests/integration/test_interfaces.py index 04233cf3..fb18748d 100644 --- a/tests/integration/test_interfaces.py +++ b/tests/integration/test_interfaces.py @@ -344,6 +344,25 @@ def test_new_interface(lldpd1, lldpd, lldpcli, namespaces, links): assert out['lldp.eth0.rid'] == out['lldp.eth2.rid'] # Same chassis +def test_remove_add_interface(lldpd, lldpcli, namespaces, links): + links(namespaces(1), namespaces(2)) + with namespaces(1): + lldpd() + links.remove('eth0') + links.count = 0 # Ack to reset interface count + links(namespaces(1), namespaces(2)) + time.sleep(2) # lldpd(1) should process the change + with namespaces(2): + lldpd() + with namespaces(1): + lldpcli("update") + time.sleep(2) # lldpd(2) should receive the LLDPDU + with namespaces(2): + out = lldpcli("-f", "keyvalue", "show", "neighbors", "details") + print(1, "out", out) + assert out['lldp.eth1.port.descr'] == 'eth0' + + def test_set_interface_description(lldpd, lldpcli, namespaces, links): links(namespaces(1), namespaces(2)) with namespaces(1): @@ -371,3 +390,4 @@ def test_set_interface_description(lldpd, lldpcli, namespaces, links): out = lldpcli("-f", "keyvalue", "show", "neighbors", "details") assert out['lldp.eth1.port.descr'] == 'eth0' +