]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
interfaces: detect interface index changes fix/port-remove-add 492/head
authorVincent Bernat <vincent@bernat.ch>
Sun, 12 Dec 2021 13:25:13 +0000 (14:25 +0100)
committerVincent Bernat <vincent@bernat.ch>
Sun, 12 Dec 2021 13:25:13 +0000 (14:25 +0100)
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.

NEWS
src/daemon/interfaces-linux.c
src/daemon/interfaces.c
src/daemon/lldpd.c
src/lldpd-structs.h
tests/integration/test_interfaces.py

diff --git a/NEWS b/NEWS
index 6c1a9717ae2b758278f071a95b027df64c622a91..698a052f784b5ab7ff97e7efdd9b1f29a760890c 100644 (file)
--- 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:
index 47b75fca75512f2d1ab952e0619bdbad85dd1873..da0df7f178529557433ca80a2dce835ab373b689 100644 (file)
@@ -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);
index 31ecad8bb7d2481eb3071ab9b9991300c85c62b5..4cd600dfc5854053bbfbc294fea4a71990ba7e0e 100644 (file)
@@ -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",
index c717c012c5a95ab9c1479beb28f70af0162a9e95..22ae7463989628eddbe57d07aa759c2a15548c40 100644 (file)
@@ -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);
                }
 
index 390b10f45917edfff13e03d3894a6e39030db663..e98a05513379e059d0041bb9cdbf8d04fd2e1c87 100644 (file)
@@ -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];
 
index 04233cf301fa320c5650e2f81a3ce837a1f03dd9..fb18748dcf63a1b2a315886662c88676168f6632 100644 (file)
@@ -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'
 
+