From 78346c890cfb3e2d53333d9c29ab89234ba52540 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Mon, 13 Feb 2017 09:15:13 +0100 Subject: [PATCH] lldp: attach remote TTL to port instead of chassis 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 --- NEWS | 1 + src/client/display.c | 5 ++++- src/daemon/event.c | 6 +++--- src/daemon/protocols/cdp.c | 4 ++-- src/daemon/protocols/edp.c | 2 +- src/daemon/protocols/lldp.c | 2 +- src/daemon/protocols/sonmp.c | 2 +- src/lib/atoms/port.c | 2 ++ src/lib/lldpctl.h | 1 + src/lldpd-structs.c | 2 +- src/lldpd-structs.h | 3 ++- tests/check_lldp.c | 4 ++-- tests/decode.c | 1 + tests/integration/test_basic.py | 4 ++-- tests/integration/test_lldpcli.py | 12 ++++++------ tests/integration/test_pcap.py | 2 +- 16 files changed, 31 insertions(+), 22 deletions(-) diff --git a/NEWS b/NEWS index 9b23fe29..100555f3 100644 --- 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. diff --git a/src/client/display.c b/src/client/display.c index fad64962..13bbfa8f 100644 --- a/src/client/display.c +++ b/src/client/display.c @@ -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) { diff --git a/src/daemon/event.c b/src/daemon/event.c index abcdaf33..bf12879e 100644 --- a/src/daemon/event.c +++ b/src/daemon/event.c @@ -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; } diff --git a/src/daemon/protocols/cdp.c b/src/daemon/protocols/cdp.c index cbb1242c..cc2c93e4 100644 --- a/src/daemon/protocols/cdp.c +++ b/src/daemon/protocols/cdp.c @@ -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); diff --git a/src/daemon/protocols/edp.c b/src/daemon/protocols/edp.c index 818dce92..9cd55f6a 100644 --- a/src/daemon/protocols/edp.c +++ b/src/daemon/protocols/edp.c @@ -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) { diff --git a/src/daemon/protocols/lldp.c b/src/daemon/protocols/lldp.c index 1f79fb9d..a338313f 100644 --- a/src/daemon/protocols/lldp.c +++ b/src/daemon/protocols/lldp.c @@ -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: diff --git a/src/daemon/protocols/sonmp.c b/src/daemon/protocols/sonmp.c index b55d73b7..faa00208 100644 --- a/src/daemon/protocols/sonmp.c +++ b/src/daemon/protocols/sonmp.c @@ -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; diff --git a/src/lib/atoms/port.c b/src/lib/atoms/port.c index 545155c2..459aa0b9 100644 --- a/src/lib/atoms/port.c +++ b/src/lib/atoms/port.c @@ -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: diff --git a/src/lib/lldpctl.h b/src/lib/lldpctl.h index ea19fae5..a5fbb733 100644 --- a/src/lib/lldpctl.h +++ b/src/lib/lldpctl.h @@ -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 */ diff --git a/src/lldpd-structs.c b/src/lldpd-structs.c index d42ebfb5..2e7efebb 100644 --- a/src/lldpd-structs.c +++ b/src/lldpd-structs.c @@ -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; diff --git a/src/lldpd-structs.h b/src/lldpd-structs.h index 0cbb6bdc..5596cf79 100644 --- a/src/lldpd-structs.h +++ b/src/lldpd-structs.h @@ -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 */ diff --git a/tests/check_lldp.c b/tests/check_lldp.c index f35bb257..94110e47 100644 --- a/tests/check_lldp.c +++ b/tests/check_lldp.c @@ -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"); diff --git a/tests/decode.c b/tests/decode.c index 1487afda..68733500 100644 --- a/tests/decode.c +++ b/tests/decode.c @@ -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); diff --git a/tests/integration/test_basic.py b/tests/integration/test_basic.py index 3d74e98b..3b23242c 100644 --- a/tests/integration/test_basic.py +++ b/tests/integration/test_basic.py @@ -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)) diff --git a/tests/integration/test_lldpcli.py b/tests/integration/test_lldpcli.py index 7a969d1d..d828c06b 100644 --- a/tests/integration/test_lldpcli.py +++ b/tests/integration/test_lldpcli.py @@ -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): 00:00:00:00:00:02 ns-2.example.com Spectacular GNU/Linux 2016 {uname} - 120 fe80::200:ff:fe00:2 @@ -156,7 +155,8 @@ def test_xml_output(lldpd1, lldpd, lldpcli, namespaces, uname): 00:00:00:00:00:02 - eth1{dot3} + eth1 + 120{dot3} diff --git a/tests/integration/test_pcap.py b/tests/integration/test_pcap.py index 04af32e2..3058f045 100644 --- a/tests/integration/test_pcap.py +++ b/tests/integration/test_pcap.py @@ -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: -- 2.39.5