]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
lldp: when receiving a shutdown LLDPU, don't clear chassis information
authorVincent Bernat <vincent@bernat.ch>
Tue, 8 Oct 2019 17:35:41 +0000 (19:35 +0200)
committerVincent Bernat <vincent@bernat.ch>
Tue, 8 Oct 2019 18:35:48 +0000 (20:35 +0200)
The chassis may be shared with another port. When the MSAP is known
and we receive a shutdown LLDPDU, just leave the original chassis as
is instead of copying information from the new chassis to the old
chassis.

Fix #348.

NEWS
src/daemon/lldpd.c
tests/integration/requirements.txt
tests/integration/test_basic.py

diff --git a/NEWS b/NEWS
index 7c96206e67aa3d83ccf312b3f546e8461978f044..2bef25c87250abeba076654cf5cd9fc196dc5174 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ lldpd (1.0.5)
     + On Linux, only register protocol handler for LLDP when only LLDP
       is enabled.
     + Stricter on LLDP incoming frames validation.
+  * Fix:
+    + Don't clear chassis TLV on shutdown LLDPDU.
 
 lldpd (1.0.4)
   * Changes:
index 1d92dd3cc5ffcffe3ed7a9c35438b21e9a37e60c..dd4487ac5e0dc949aa3fccb14bd939e2401b9c19 100644 (file)
@@ -662,7 +662,14 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s,
                free(oport);
        }
        if (ochassis) {
-               lldpd_move_chassis(ochassis, chassis);
+               if (port->p_ttl == 0) {
+                       /* Shutdown LLDPDU is special. We do not want to replace
+                        * the chassis. Free the new chassis (which is mostly empty) */
+                       log_debug("decode", "received a shutdown LLDPDU");
+                       lldpd_chassis_cleanup(chassis, 1);
+               } else {
+                       lldpd_move_chassis(ochassis, chassis);
+               }
                chassis = ochassis;
        } else {
                /* Chassis not known, add it */
index 17e21ae1cd2376e762a0ee2b173223b0491bc005..15dc91c2e39f254d02ea4dd1a6110c84ebb0bf11 100644 (file)
@@ -1,3 +1,4 @@
 pyroute2==0.5.2
 pytest==3.10.1
 pytest-xdist==1.26.1
+scapy==2.4.3
index e0f1329d3c8026a943d04dd1d51aa4298a85288e..89d98756785035d7165930fe94ea30b3e2ad9117 100644 (file)
@@ -1,6 +1,8 @@
 import time
 import pytest
 import pyroute2
+import scapy.all
+import scapy.contrib.lldp
 
 
 def test_one_neighbor(lldpd1, lldpd, lldpcli, namespaces):
@@ -375,3 +377,91 @@ def test_set_interface_alias(lldpd1, lldpd, lldpcli, namespaces):
         ipr = pyroute2.IPRoute()
         link = ipr.link('get', ifname='eth0')[0]
         assert link.get_attr('IFLA_IFALIAS') == 'lldpd: connected to ns-2.example.com'
+
+
+def test_lldpdu_shutdown(lldpd, lldpcli, namespaces, links):
+    links(namespaces(1), namespaces(2))
+    links(namespaces(1), namespaces(2))
+    with namespaces(1):
+        lldpd()
+    # From https://github.com/vincentbernat/lldpd/issues/348
+    frm_fa01 = scapy.all.Ether(
+        src='04:fe:7f:00:00:01',
+        dst=scapy.contrib.lldp.LLDP_NEAREST_BRIDGE_MAC) / \
+        scapy.contrib.lldp.LLDPDUChassisID(
+            subtype=scapy.contrib.lldp.LLDPDUChassisID.SUBTYPE_MAC_ADDRESS,
+            id=b'\x04\xfe\x7f\x00\x00\x00') / \
+        scapy.contrib.lldp.LLDPDUPortID(
+            subtype=scapy.contrib.lldp.LLDPDUPortID.SUBTYPE_INTERFACE_NAME,
+            id='Fa0/1') / \
+        scapy.contrib.lldp.LLDPDUTimeToLive(ttl=65535) / \
+        scapy.contrib.lldp.LLDPDUSystemName(
+            system_name='this info should not disappear') / \
+        scapy.contrib.lldp.LLDPDUEndOfLLDPDU()
+    frm_fa01 = frm_fa01.build()
+    frm_fa01 = scapy.all.Ether(frm_fa01)
+
+    frm_fa02 = scapy.all.Ether(
+        src='04:fe:7f:00:00:02',
+        dst=scapy.contrib.lldp.LLDP_NEAREST_BRIDGE_MAC) / \
+        scapy.contrib.lldp.LLDPDUChassisID(
+            subtype=scapy.contrib.lldp.LLDPDUChassisID.SUBTYPE_MAC_ADDRESS,
+            id=b'\x04\xfe\x7f\x00\x00\x00') / \
+        scapy.contrib.lldp.LLDPDUPortID(
+            subtype=scapy.contrib.lldp.LLDPDUPortID.SUBTYPE_INTERFACE_NAME,
+            id='Fa0/2') / \
+        scapy.contrib.lldp.LLDPDUTimeToLive(ttl=65535) / \
+        scapy.contrib.lldp.LLDPDUSystemName(
+            system_name='this info should not disappear') / \
+        scapy.contrib.lldp.LLDPDUEndOfLLDPDU()
+    frm_fa02 = frm_fa02.build()
+    frm_fa02 = scapy.all.Ether(frm_fa02)
+
+    frm_shut_fa01 = scapy.all.Ether(
+        src='04:fe:7f:00:00:01',
+        dst=scapy.contrib.lldp.LLDP_NEAREST_BRIDGE_MAC) / \
+        scapy.contrib.lldp.LLDPDUChassisID(
+            subtype=scapy.contrib.lldp.LLDPDUChassisID.SUBTYPE_MAC_ADDRESS,
+            id=b'\x04\xfe\x7f\x00\x00\x00') / \
+        scapy.contrib.lldp.LLDPDUPortID(
+            subtype=scapy.contrib.lldp.LLDPDUPortID.SUBTYPE_INTERFACE_NAME,
+            id='Fa0/1') / \
+        scapy.contrib.lldp.LLDPDUTimeToLive(ttl=0) / \
+        scapy.contrib.lldp.LLDPDUEndOfLLDPDU()
+    frm_shut_fa01 = frm_shut_fa01.build()
+    frm_shut_fa01 = scapy.all.Ether(frm_shut_fa01)
+
+    with namespaces(2):
+        scapy.all.sendp(frm_fa01, iface='eth1')
+        scapy.all.sendp(frm_fa02, iface='eth3')
+        time.sleep(2)
+    with namespaces(1):
+        out = lldpcli("-f", "keyvalue", "show", "neighbors")
+        del out['lldp.eth0.age']
+        del out['lldp.eth2.age']
+        assert out == {
+            "lldp.eth0.via": "LLDP",
+            "lldp.eth0.rid": "1",
+            "lldp.eth0.chassis.mac": "04:fe:7f:00:00:00",
+            "lldp.eth0.chassis.name": "this info should not disappear",
+            "lldp.eth0.port.ifname": "Fa0/1",
+            "lldp.eth0.port.ttl": "65535",
+            "lldp.eth2.via": "LLDP",
+            "lldp.eth2.rid": "1",
+            "lldp.eth2.chassis.mac": "04:fe:7f:00:00:00",
+            "lldp.eth2.chassis.name": "this info should not disappear",
+            "lldp.eth2.port.ifname": "Fa0/2",
+            "lldp.eth2.port.ttl": "65535"}
+    with namespaces(2):
+        scapy.all.sendp(frm_shut_fa01, iface='eth1')
+        time.sleep(2)
+    with namespaces(1):
+        out = lldpcli("-f", "keyvalue", "show", "neighbors")
+        del out['lldp.eth2.age']
+        assert out == {
+            "lldp.eth2.via": "LLDP",
+            "lldp.eth2.rid": "1",
+            "lldp.eth2.chassis.mac": "04:fe:7f:00:00:00",
+            "lldp.eth2.chassis.name": "this info should not disappear",
+            "lldp.eth2.port.ifname": "Fa0/2",
+            "lldp.eth2.port.ttl": "65535"}