]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
lldp: attach remote TTL to port instead of chassis
authorVincent Bernat <vincent@bernat.im>
Mon, 13 Feb 2017 08:15:13 +0000 (09:15 +0100)
committerVincent Bernat <vincent@bernat.im>
Sun, 19 Feb 2017 12:59:48 +0000 (13:59 +0100)
When receiving a 0 TTL, we should trigger expiry of the remote port, not
the remote chassis. Therefore, TTL is moved to port, except for the
local chassis (we need it even when we don't have a port). So, for
remote ports, TTL is on the port. For local ports, it is on the
chassis. This fixes two cases:

 - a shutdown LLDPU should only expire one local port
 - when a port is refreshed, another port of the same chassis shouldn't
   be refreshed

16 files changed:
NEWS
src/client/display.c
src/daemon/event.c
src/daemon/protocols/cdp.c
src/daemon/protocols/edp.c
src/daemon/protocols/lldp.c
src/daemon/protocols/sonmp.c
src/lib/atoms/port.c
src/lib/lldpctl.h
src/lldpd-structs.c
src/lldpd-structs.h
tests/check_lldp.c
tests/decode.c
tests/integration/test_basic.py
tests/integration/test_lldpcli.py
tests/integration/test_pcap.py

diff --git a/NEWS b/NEWS
index 9b23fe296f1ca5012612e4b63e955c10381a36bf..100555f3bc003a0f21d689dd4d7aac9def7b4cad 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,6 @@
 lldpd (0.9.7)
   * Changes:
+    + Attach remote TTL to port instead of chassis.
     + JSON support is now built-in and unconditionally enabled. Use
       --enable-json0 to keep the pre-0.9.2 json-c format.
     + When logging to syslog and daemonizing, don't log to stderr.
index fad64962db0b1d532f5eec4557f9cc5e7e6f6860..13bbfa8f07cdd7b68c02e85c0bb6f475a1c8a1ab 100644 (file)
@@ -252,7 +252,7 @@ display_chassis(struct writer* w, lldpctl_atom_t* chassis, int details)
        }
        tag_datatag(w, "descr", "SysDescr",
            lldpctl_atom_get_str(chassis, lldpctl_k_chassis_descr));
-       if (details)
+       if (details && lldpctl_atom_get_int(chassis, lldpctl_k_chassis_ttl) > 0)
                tag_datatag(w, "ttl", "TTL",
                    lldpctl_atom_get_str(chassis, lldpctl_k_chassis_ttl));
 
@@ -352,6 +352,9 @@ display_port(struct writer *w, lldpctl_atom_t *port, int details)
 
        tag_datatag(w, "descr", "PortDescr",
            lldpctl_atom_get_str(port, lldpctl_k_port_descr));
+       if (details)
+               tag_datatag(w, "ttl", "TTL",
+                   lldpctl_atom_get_str(port, lldpctl_k_port_ttl));
 
        /* Dot3 */
        if (details == DISPLAY_DETAILS) {
index abcdaf33626ce4649996f8d4b27fec395ce616f7..bf12879ebf0c8a3ce1e2da0d1e562b28df572f75 100644 (file)
@@ -804,16 +804,16 @@ levent_schedule_cleanup(struct lldpd *cfg)
        struct lldpd_port *port;
        TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
                TAILQ_FOREACH(port, &hardware->h_rports, p_entries) {
-                       if (now >= port->p_lastupdate + port->p_chassis->c_ttl) {
+                       if (now >= port->p_lastupdate + port->p_ttl) {
                                tv.tv_sec = 0;
                                log_debug("event", "immediate cleanup on port %s (%lld, %d, %lld)",
                                    hardware->h_ifname,
                                    (long long)now,
-                                   port->p_chassis->c_ttl,
+                                   port->p_ttl,
                                    (long long)port->p_lastupdate);
                                break;
                        }
-                       next = port->p_chassis->c_ttl - (now - port->p_lastupdate);
+                       next = port->p_ttl - (now - port->p_lastupdate);
                        if (next < tv.tv_sec)
                                tv.tv_sec = next;
                }
index cbb1242cc7974312d1561acf26109a1ccd0451ce..cc2c93e4e5fce7d4619d126bb82f16e2f7c66d4c 100644 (file)
@@ -358,7 +358,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
                    version, hardware->h_ifname);
                goto malformed;
        }
-       chassis->c_ttl = PEEK_UINT8; /* TTL */
+       port->p_ttl = PEEK_UINT8; /* TTL */
        PEEK_DISCARD_UINT16;         /* Checksum, already checked */
 
        while (length) {
@@ -563,7 +563,7 @@ cdp_decode(struct lldpd *cfg, char *frame, int s,
            (chassis->c_name == NULL) ||
            (chassis->c_descr == NULL) ||
            (port->p_descr == NULL) ||
-           (chassis->c_ttl == 0) ||
+           (port->p_ttl == 0) ||
            (chassis->c_cap_enabled == 0)) {
                log_warnx("cdp", "some mandatory CDP/FDP tlv are missing for frame received on %s",
                    hardware->h_ifname);
index 818dce92542a11d8796271ad1fe16e710715a2e3..9cd55f6a8933e2e478b25bf9ecd8a498a7d4bc7a 100644 (file)
@@ -307,7 +307,7 @@ edp_decode(struct lldpd *cfg, char *frame, int s,
                    hardware->h_ifname);
                goto malformed;
        }
-       chassis->c_ttl = cfg?cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold:0;
+       port->p_ttl = cfg?cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold:0;
        chassis->c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
        chassis->c_id_len = ETHER_ADDR_LEN;
        if ((chassis->c_id = (char *)malloc(ETHER_ADDR_LEN)) == NULL) {
index 1f79fb9d2cb0fb54501130c3f9b5ba6918550d6c..a338313f5a6030d3f3f5c76703a3255bba4ee3ab 100644 (file)
@@ -707,7 +707,7 @@ lldp_decode(struct lldpd *cfg, char *frame, int s,
                        break;
                case LLDP_TLV_TTL:
                        CHECK_TLV_SIZE(2, "TTL");
-                       chassis->c_ttl = PEEK_UINT16;
+                       port->p_ttl = PEEK_UINT16;
                        ttl_received = 1;
                        break;
                case LLDP_TLV_PORT_DESCR:
index b55d73b7a59b078eb759a44ce507a6f70a0c62ca..faa00208d3153c8fc74525faf6a80d9d49ec060b 100644 (file)
@@ -365,7 +365,7 @@ sonmp_decode(struct lldpd *cfg, char *frame, int s,
                goto malformed;
        }
        TAILQ_INSERT_TAIL(&chassis->c_mgmt, mgmt, m_entries);
-       chassis->c_ttl = cfg?(cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold):
+       port->p_ttl = cfg?(cfg->g_config.c_tx_interval * cfg->g_config.c_tx_hold):
            LLDPD_TTL;
 
        port->p_id_subtype = LLDP_PORTID_SUBTYPE_LOCAL;
index 545155c2db7cf7b11b969cde9074d8aea2e28c68..459aa0b99c5255637eb1a3003e21d13bb55fe110 100644 (file)
@@ -616,6 +616,8 @@ _lldpctl_atom_get_int_port(lldpctl_atom_t *atom, lldpctl_key_t key)
                return port->p_protocol;
        case lldpctl_k_port_age:
                return port->p_lastchange;
+       case lldpctl_k_port_ttl:
+               return port->p_ttl;
        case lldpctl_k_port_id_subtype:
                return port->p_id_subtype;
        case lldpctl_k_port_hidden:
index ea19fae5dcb4f3552bea6bc8185aa285ef989cb0..a5fbb733881220a133c70e561268f2c2e287d610 100644 (file)
@@ -684,6 +684,7 @@ typedef enum {
        lldpctl_k_port_hidden,     /**< `(I)` Is this port hidden (or should it be displayed?)? */
        lldpctl_k_port_status,     /**< `(IS,WO)` Operational status of this (local) port */
        lldpctl_k_port_chassis,    /**< `(A)` Chassis associated to the port */
+       lldpctl_k_port_ttl,        /**< `(I)` TTL for port, 0 if info is attached to chassis */
 
        lldpctl_k_port_dot3_mfs = 1300,    /**< `(I)` MFS */
        lldpctl_k_port_dot3_aggregid,   /**< `(I)` Port aggregation ID */
index d42ebfb585b84d9439edc2c0dbdf373ed7be953b..2e7efebb6f69025cb4ec28bea9197cfac03d962e 100644 (file)
@@ -174,7 +174,7 @@ lldpd_remote_cleanup(struct lldpd_hardware *hardware,
                port_next = TAILQ_NEXT(port, p_entries);
                del = all;
                if (!all && expire &&
-                   (now >= port->p_lastupdate + port->p_chassis->c_ttl)) {
+                   (now >= port->p_lastupdate + port->p_ttl)) {
                        hardware->h_ageout_cnt++;
                        hardware->h_delete_cnt++;
                        del = 1;
index 0cbb6bdcf4ed195d4132c317a3f0a9b1c5d1a119..5596cf7996b8d5eda16724cc7392174c865945b7 100644 (file)
@@ -178,7 +178,7 @@ struct lldpd_chassis {
        u_int16_t                c_cap_available;
        u_int16_t                c_cap_enabled;
 
-       u_int16_t                c_ttl;
+       u_int16_t                c_ttl; /* TTL for local chassis */
 
        TAILQ_HEAD(, lldpd_mgmt) c_mgmt;
 
@@ -261,6 +261,7 @@ struct lldpd_port {
        char                    *p_descr;
        int                      p_descr_force; /* Description has been forced by user */
        u_int16_t                p_mfs;
+       u_int16_t                p_ttl; /* TTL for remote port */
 
 #ifdef ENABLE_DOT3
        /* Dot3 stuff */
index f35bb25758fddc75f5622d4cfe009682557455ba..94110e47090e1e5933d1fb57e555e42364d6c92a 100644 (file)
@@ -513,10 +513,10 @@ Link Layer Discovery Protocol
            LLDP_PORTID_SUBTYPE_LLADDR);
        ck_assert_int_eq(nport->p_id_len, ETHER_ADDR_LEN);
        fail_unless(memcmp(mac2, nport->p_id, ETHER_ADDR_LEN) == 0);
-       ck_assert_int_eq(nchassis->c_ttl, 120);
        ck_assert_ptr_eq(nchassis->c_name, NULL);
        ck_assert_ptr_eq(nchassis->c_descr, NULL);
        ck_assert_ptr_eq(nport->p_descr, NULL);
+       ck_assert_int_eq(nport->p_ttl, 120);
 }
 END_TEST
 
@@ -718,7 +718,7 @@ Link Layer Discovery Protocol
            LLDP_PORTID_SUBTYPE_LLADDR);
        ck_assert_int_eq(nport->p_id_len, ETHER_ADDR_LEN);
        fail_unless(memcmp(mac1, nport->p_id, ETHER_ADDR_LEN) == 0);
-       ck_assert_int_eq(nchassis->c_ttl, 120);
+       ck_assert_int_eq(nport->p_ttl, 120);
        ck_assert_str_eq(nchassis->c_name, "naruto.XXXXXXXXXXXXXXXXXXX");
        ck_assert_str_eq(nchassis->c_descr,
            "Linux 2.6.29-2-amd64 #1 SMP Sun May 17 17:15:47 UTC 2009 x86_64");
index 1487afdab22003c4dbe303fcd0d3a45067c3c5a3..68733500b1263c38a1b72cf8181836306e133a06 100644 (file)
@@ -178,6 +178,7 @@ main(int argc, char **argv)
        printf(" ID: %s\n", tohex(nport->p_id, nport->p_id_len));
        printf(" Description: %s\n", nport->p_descr?nport->p_descr:"(null)");
        printf(" MFS: %" PRIu16 "\n", nport->p_mfs);
+       printf(" TTL: %" PRIu16 "\n", nport->p_ttl);
 #ifdef ENABLE_DOT3
        printf(" Dot3 aggrID: %" PRIu32 "\n", nport->p_aggregid);
        printf(" Dot3 MAC/phy autoneg supported: %" PRIu8 "\n", nport->p_macphy.autoneg_support);
index 3d74e98b8ee096cace9de9fd7c2a7ae2d8df2e25..3b23242ce1ec51677dfb613a8e014a8c135e42b5 100644 (file)
@@ -21,12 +21,12 @@ def test_one_neighbor(lldpd1, lldpd, lldpcli, namespaces):
                        "lldp.eth0.rid": "1",
                        "lldp.eth0.chassis.mac": "00:00:00:00:00:02",
                        "lldp.eth0.chassis.name": "ns-2.example.com",
-                       "lldp.eth0.chassis.ttl": "120",
                        "lldp.eth0.chassis.mgmt-ip": "fe80::200:ff:fe00:2",
                        "lldp.eth0.chassis.Bridge.enabled": "off",
                        "lldp.eth0.chassis.Wlan.enabled": "off",
                        "lldp.eth0.port.mac": "00:00:00:00:00:02",
-                       "lldp.eth0.port.descr": "eth1"}
+                       "lldp.eth0.port.descr": "eth1",
+                       "lldp.eth0.port.ttl": "120"}
 
 
 @pytest.mark.parametrize("neighbors", (5, 10, 20))
index 7a969d1d0b47e7a54ff778353ba9ab39cb779d93..d828c06bf3685ade182ab703a6392048c93db63c 100644 (file)
@@ -35,7 +35,6 @@ Interface:    eth0, via: LLDP, RID: 1, Time: 0 day, 00:00:{seconds}
     ChassisID:    mac 00:00:00:00:00:02
     SysName:      ns-2.example.com
     SysDescr:     Spectacular GNU/Linux 2016 {uname}
-    TTL:          120
     MgmtIP:       fe80::200:ff:fe00:2
     Capability:   Bridge, off
     Capability:   Router, {router}
@@ -43,7 +42,8 @@ Interface:    eth0, via: LLDP, RID: 1, Time: 0 day, 00:00:{seconds}
     Capability:   Station, {station}
   Port:
     PortID:       mac 00:00:00:00:00:02
-    PortDescr:    eth1{dot3}
+    PortDescr:    eth1
+    TTL:          120{dot3}
 -------------------------------------------------------------------------------
 """
         out = result.stdout.decode('ascii')
@@ -90,7 +90,6 @@ def test_json_output(lldpd1, lldpd, lldpcli, namespaces, uname):
                             "value": "00:00:00:00:00:02"
                         },
                         "descr": "Spectacular GNU/Linux 2016 {}".format(uname),
-                        "ttl": "120",
                         "mgmt-ip": "fe80::200:ff:fe00:2",
                         "capability": [
                             {"type": "Bridge", "enabled": False},
@@ -103,7 +102,8 @@ def test_json_output(lldpd1, lldpd, lldpcli, namespaces, uname):
                         "type": "mac",
                         "value": "00:00:00:00:00:02"
                     },
-                    "descr": "eth1"
+                    "descr": "eth1",
+                    "ttl": "120"
                 }
             }}
         }}
@@ -147,7 +147,6 @@ def test_xml_output(lldpd1, lldpd, lldpcli, namespaces, uname):
    <id label="ChassisID" type="mac">00:00:00:00:00:02</id>
    <name label="SysName">ns-2.example.com</name>
    <descr label="SysDescr">Spectacular GNU/Linux 2016 {uname}</descr>
-   <ttl label="TTL">120</ttl>
    <mgmt-ip label="MgmtIP">fe80::200:ff:fe00:2</mgmt-ip>
    <capability label="Capability" type="Bridge" enabled="off"/>
    <capability label="Capability" type="Router" enabled="{router}"/>
@@ -156,7 +155,8 @@ def test_xml_output(lldpd1, lldpd, lldpcli, namespaces, uname):
   </chassis>
   <port label="Port">
    <id label="PortID" type="mac">00:00:00:00:00:02</id>
-   <descr label="PortDescr">eth1</descr>{dot3}
+   <descr label="PortDescr">eth1</descr>
+   <ttl label="TTL">120</ttl>{dot3}
   </port>
  </interface>
 </lldp>
index 04af32e2ee27dc1423197dad44e9e0070513e863..3058f045bc900f4df0f7a50115a7f991e3a1aa45 100644 (file)
@@ -36,7 +36,7 @@ class TestPcapCaptures(object):
                 "lldp.eth0.via": "LLDP",
                 "lldp.eth0.rid": "1",
                 "lldp.eth0.chassis.mac": "00:35:35:35:35:35",
-                "lldp.eth0.chassis.ttl": "120",
+                "lldp.eth0.port.ttl": "120",
                 "lldp.eth0.port.ifname": "g1",
             }
             if 'Dot3' in pytest.config.lldpd.features: