From: Vincent Bernat Date: Sun, 15 Oct 2023 18:28:46 +0000 (+0200) Subject: daemon/lldp: restore read support for 802.3BT X-Git-Tag: 1.0.18~27 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=551717c697fb5d4f77d0646ad2ff2fd922bcdfa2;p=thirdparty%2Flldpd.git daemon/lldp: restore read support for 802.3BT As it was said to work for most people, let's keep it. Just remove write support for now. --- diff --git a/NEWS b/NEWS index f0e0fb19..767a4020 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,6 @@ lldpd (1.0.18) * Changes (breaking): - + Remove support for 802.3bt (broken). + + Remove support for building 802.3bt TLVs (broken). * Fix: + Fix memory leaks in EDP/FDP decoding when receiving some TLVs twice. diff --git a/src/client/display.c b/src/client/display.c index d6338d0d..a050432d 100644 --- a/src/client/display.c +++ b/src/client/display.c @@ -493,6 +493,80 @@ display_port(struct writer *w, lldpctl_atom_t *port, int details) tag_end(w); } + /* 802.3bt */ + if (lldpctl_atom_get_int(dot3_power, + lldpctl_k_dot3_power_type_ext) > + LLDP_DOT3_POWER_8023BT_OFF) { + tag_start(w, "requested-a", "Requested mode A"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_requested_a)); + tag_end(w); + tag_start(w, "requested-b", "Requested mode B"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_requested_b)); + tag_end(w); + tag_start(w, "allocated-a", "Allocated alternative A"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_allocated_a)); + tag_end(w); + tag_start(w, "allocated-b", "Allocated alternative B"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_allocated_b)); + tag_end(w); + tag_start(w, "pse-powering-status", + "PSE powering status"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_pse_status)); + tag_end(w); + tag_start(w, "pd-powering-status", + "PD powering status"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_pd_status)); + tag_end(w); + tag_start(w, "power-pairs-ext", "Power pairs extra"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_pse_pairs_ext)); + tag_end(w); + tag_start(w, "power-class-ext-a", "Class extra A"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_class_a)); + tag_end(w); + tag_start(w, "power-class-ext-b", "Class extra B"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_class_b)); + tag_end(w); + tag_start(w, "power-class-ext", "Class extra"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_class_ext)); + tag_end(w); + tag_start(w, "power-type-ext", "Power type extra"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_type_ext)); + tag_end(w); + tag_start(w, "pd-load", "PD load"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_pd_load)); + tag_end(w); + tag_start(w, "max-power", + "PSE maximum available power"); + tag_data(w, + lldpctl_atom_get_str(dot3_power, + lldpctl_k_dot3_power_pse_max)); + tag_end(w); + } + tag_end(w); } lldpctl_atom_dec_ref(dot3_power); diff --git a/src/daemon/protocols/lldp.c b/src/daemon/protocols/lldp.c index 647c6e97..64d34473 100644 --- a/src/daemon/protocols/lldp.c +++ b/src/daemon/protocols/lldp.c @@ -991,6 +991,47 @@ lldp_decode(struct lldpd *cfg, char *frame, int s, struct lldpd_hardware *hardwa } else port->p_power.powertype = LLDP_DOT3_POWER_8023AT_OFF; + /* 802.3bt? */ + if (tlv_size >= 29) { + port->p_power.requested_a = PEEK_UINT16; + port->p_power.requested_b = PEEK_UINT16; + port->p_power.allocated_a = PEEK_UINT16; + port->p_power.allocated_b = PEEK_UINT16; + port->p_power.pse_status = PEEK_UINT16; + port->p_power.pd_status = + (port->p_power.pse_status & + (1 << 13 | 1 << 12)) >> + 12; + port->p_power.pse_pairs_ext = + (port->p_power.pse_status & + (1 << 11 | 1 << 10)) >> + 10; + port->p_power.class_a = + (port->p_power.pse_status & + (1 << 9 | 1 << 8 | 1 << 7)) >> + 7; + port->p_power.class_b = + (port->p_power.pse_status & + (1 << 6 | 1 << 5 | 1 << 4)) >> + 4; + port->p_power.class_ext = + (port->p_power.pse_status & 0xf); + port->p_power.pse_status = + (port->p_power.pse_status & + (1 << 15 | 1 << 14)) >> + 14; + port->p_power.type_ext = PEEK_UINT8; + port->p_power.pd_load = + (port->p_power.type_ext & 0x1); + port->p_power.type_ext = + ((port->p_power.type_ext & + (1 << 3 | 1 << 2 | 1 << 1)) + + 1); + port->p_power.pse_max = PEEK_UINT16; + } else { + port->p_power.type_ext = + LLDP_DOT3_POWER_8023BT_OFF; + } break; default: /* Unknown Dot3 TLV, ignore it */ diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 2ed037bb..6cc6bc4d 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -54,7 +54,7 @@ CLEANFILES = atom-glue.c # -version-number could be computed from -version-info, mostly major # is `current` - `age`, minor is `age` and revision is `revision' and # major.minor should be used when updating lldpctl.map. -liblldpctl_la_LDFLAGS = $(AM_LDFLAGS) -version-info 14:0:10 +liblldpctl_la_LDFLAGS = $(AM_LDFLAGS) -version-info 13:1:9 liblldpctl_la_DEPENDENCIES = libfixedpoint.la if HAVE_LD_VERSION_SCRIPT diff --git a/src/lib/atoms/dot3.c b/src/lib/atoms/dot3.c index 202ac9b6..f3f490ae 100644 --- a/src/lib/atoms/dot3.c +++ b/src/lib/atoms/dot3.c @@ -63,6 +63,128 @@ static struct atom_map port_dot3_power_priority_map = { }, }; +static struct atom_map port_dot3_power_pd_4pid_map = { + .key = lldpctl_k_dot3_power_pd_4pid, + .map = { + { 0, "PD does not support powering both modes" }, + { 1, "PD supports powering both modes" }, + { 0, NULL}, + }, +}; + +static struct atom_map port_dot3_power_pse_status_map = { + .key = lldpctl_k_dot3_power_pse_status, + .map = { + { 0, "unknown" }, + { 1, "2-pair powering" }, + { 2, "4-pair powering dual-signature PD" }, + { 3, "4-pair powering single-signature PD" }, + { 0, NULL }, + }, +}; + +static struct atom_map port_dot3_power_pd_status_map = { + .key = lldpctl_k_dot3_power_pd_status, + .map = { + { 0, "unknown" }, + { 1, "2-pair powered PD" }, + { 2, "4-pair powered dual-signature PD" }, + { 3, "4-pair powered single-signature PD" }, + { 0, NULL }, + }, +}; + +static struct atom_map port_dot3_power_pse_pairs_ext_map = { + .key = lldpctl_k_dot3_power_pse_pairs_ext, + .map = { + { 0, "unknown" }, + { 1, "alternative A" }, + { 2, "alternative B" }, + { 3, "both alternatives" }, + { 0, NULL }, + }, +}; + +static struct atom_map port_dot3_power_class_a_map = { + .key = lldpctl_k_dot3_power_class_a, + .map = { + { 0, "unknown" }, + { 1, "class 1" }, + { 2, "class 2" }, + { 3, "class 3" }, + { 4, "class 4" }, + { 5, "class 5" }, + { 6, "unknown" }, + { 7, "single-signature PD or 2-pair only PSE" }, + { 0, NULL }, + }, +}; + +static struct atom_map port_dot3_power_class_b_map = { + .key = lldpctl_k_dot3_power_class_b, + .map = { + { 0, "unknown" }, + { 1, "class 1" }, + { 2, "class 2" }, + { 3, "class 3" }, + { 4, "class 4" }, + { 5, "class 5" }, + { 6, "unknown" }, + { 7, "single-signature PD or 2-pair only PSE" }, + { 0, NULL }, + }, +}; + +static struct atom_map port_dot3_power_class_ext_map = { + .key = lldpctl_k_dot3_power_class_ext, + .map = { + { 0, "unknown" }, + { 1, "class 1" }, + { 2, "class 2" }, + { 3, "class 3" }, + { 4, "class 4" }, + { 5, "class 5" }, + { 6, "class 6" }, + { 7, "class 7" }, + { 8, "class 8" }, + { 9, "unknown" }, + { 10, "unknown" }, + { 11, "unknown" }, + { 12, "unknown" }, + { 13, "unknown" }, + { 14, "unknown" }, + { 15, "dual-signature PD" }, + { 0, NULL }, + }, +}; + +static struct atom_map port_dot3_power_type_ext_map = { + .key = lldpctl_k_dot3_power_type_ext, + .map = { + { LLDP_DOT3_POWER_8023BT_OFF, "802.3bt off" }, + { 1, "type 3 PSE" }, + { 2, "type 4 PSE" }, + { 3, "type 3 single-signature PD" }, + { 4, "type 3 dual-signature PD" }, + { 5, "type 4 single-signature PD" }, + { 6, "type 4 dual-signature PD" }, + { 7, "unknown" }, + { 8, "unknown" }, + { 0, NULL }, + }, +}; + +static struct atom_map port_dot3_power_pd_load_map = { + .key = lldpctl_k_dot3_power_pd_load, + .map = { + { 0, "PD is single- or dual-signature and power is not " + "electrically isolated" }, + { 1, "PD is dual-signature and power is electrically " + "isolated" }, + { 0, NULL }, + }, +}; + ATOM_MAP_REGISTER(port_dot3_power_pairs_map, 4); ATOM_MAP_REGISTER(port_dot3_power_class_map, 5); ATOM_MAP_REGISTER(port_dot3_power_priority_map, 6); @@ -109,6 +231,33 @@ _lldpctl_atom_get_str_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key) case lldpctl_k_dot3_power_priority: return map_lookup(port_dot3_power_priority_map.map, port->p_power.priority); + case lldpctl_k_dot3_power_pd_4pid: + return map_lookup(port_dot3_power_pd_4pid_map.map, + port->p_power.pd_4pid); + case lldpctl_k_dot3_power_pse_status: + return map_lookup(port_dot3_power_pse_status_map.map, + port->p_power.pse_status); + case lldpctl_k_dot3_power_pd_status: + return map_lookup(port_dot3_power_pd_status_map.map, + port->p_power.pd_status); + case lldpctl_k_dot3_power_pse_pairs_ext: + return map_lookup(port_dot3_power_pse_pairs_ext_map.map, + port->p_power.pse_pairs_ext); + case lldpctl_k_dot3_power_class_a: + return map_lookup(port_dot3_power_class_a_map.map, + port->p_power.class_a); + case lldpctl_k_dot3_power_class_b: + return map_lookup(port_dot3_power_class_b_map.map, + port->p_power.class_b); + case lldpctl_k_dot3_power_class_ext: + return map_lookup(port_dot3_power_class_ext_map.map, + port->p_power.class_ext); + case lldpctl_k_dot3_power_type_ext: + return map_lookup(port_dot3_power_type_ext_map.map, + port->p_power.type_ext); + case lldpctl_k_dot3_power_pd_load: + return map_lookup(port_dot3_power_pd_load_map.map, + port->p_power.pd_load); default: SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); return NULL; @@ -146,6 +295,35 @@ _lldpctl_atom_get_int_dot3_power(lldpctl_atom_t *atom, lldpctl_key_t key) return port->p_power.requested * 100; case lldpctl_k_dot3_power_allocated: return port->p_power.allocated * 100; + /* 802.3bt additions */ + case lldpctl_k_dot3_power_pd_4pid: + return port->p_power.pd_4pid; + case lldpctl_k_dot3_power_requested_a: + return port->p_power.requested_a * 100; + case lldpctl_k_dot3_power_requested_b: + return port->p_power.requested_b * 100; + case lldpctl_k_dot3_power_allocated_a: + return port->p_power.allocated_a * 100; + case lldpctl_k_dot3_power_allocated_b: + return port->p_power.allocated_b * 100; + case lldpctl_k_dot3_power_pse_status: + return port->p_power.pse_status; + case lldpctl_k_dot3_power_pd_status: + return port->p_power.pd_status; + case lldpctl_k_dot3_power_pse_pairs_ext: + return port->p_power.pse_pairs_ext; + case lldpctl_k_dot3_power_class_a: + return port->p_power.class_a; + case lldpctl_k_dot3_power_class_b: + return port->p_power.class_b; + case lldpctl_k_dot3_power_class_ext: + return port->p_power.class_ext; + case lldpctl_k_dot3_power_type_ext: + return port->p_power.type_ext; + case lldpctl_k_dot3_power_pd_load: + return port->p_power.pd_load; + case lldpctl_k_dot3_power_pse_max: + return port->p_power.pse_max * 100; default: return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST); } diff --git a/src/lib/lldpctl.h b/src/lib/lldpctl.h index cea5706f..6c2844a3 100644 --- a/src/lib/lldpctl.h +++ b/src/lib/lldpctl.h @@ -773,6 +773,26 @@ typedef enum { lldpctl_k_dot3_power_allocated, /**< `(I,W)` 802.3AT power allocated */ lldpctl_k_dot3_power_requested, /**< `(I,W)` 802.3AT power requested */ + /* 802.3bt additions */ + lldpctl_k_dot3_power_pd_4pid, /**< `(IS)` 802.3BT both modes supported? */ + lldpctl_k_dot3_power_requested_a, /**< `(I)` 802.3BT power value requested for + A */ + lldpctl_k_dot3_power_requested_b, /**< `(I)` 802.3BT power value requested for + B */ + lldpctl_k_dot3_power_allocated_a, /**< `(I)` 802.3BT power value allocated for + A */ + lldpctl_k_dot3_power_allocated_b, /**< `(I)` 802.3BT power value allocated for + B */ + lldpctl_k_dot3_power_pse_status, /**< `(IS)` 802.3BT PSE powering status */ + lldpctl_k_dot3_power_pd_status, /**< `(IS)` 802.3BT PD powering status */ + lldpctl_k_dot3_power_pse_pairs_ext, /**< `(IS)` 802.3BT PSE power pairs */ + lldpctl_k_dot3_power_class_a, /**< `(IS)` 802.3BT power class for A */ + lldpctl_k_dot3_power_class_b, /**< `(IS)` 802.3BT power class for B */ + lldpctl_k_dot3_power_class_ext, /**< `(IS)` 802.3BT power class */ + lldpctl_k_dot3_power_type_ext, /**< `(IS)` 802.3BT power type */ + lldpctl_k_dot3_power_pd_load, /**< `(IS)` 802.3BT dualsig isolated? */ + lldpctl_k_dot3_power_pse_max, /**< `(I)` 802.3BT maximum available power */ + lldpctl_k_port_vlan_pvid = 1500, /**< `(I)` Primary VLAN ID */ lldpctl_k_port_vlans, /**< `(AL)` List of VLAN */ lldpctl_k_vlan_id, /**< `(I)` VLAN ID */ @@ -865,8 +885,8 @@ typedef enum { `LLDP_MED_POW_PRIO_*` */ lldpctl_k_med_power_val, /**< `(I,W)` LLDP MED power value */ - lldpctl_k_mgmt_ip = 3000, /**< `(S)` IP address */ - lldpctl_k_mgmt_iface_index, /**< `(I)` Interface index */ + lldpctl_k_mgmt_ip = 3000, /**< `(S)` IP address */ + lldpctl_k_mgmt_iface_index = 30001, /**< `(I)` Interface index */ lldpctl_k_tx_cnt = 4000, /**< `(I)` tx cnt. Only works for a local port. */ lldpctl_k_rx_cnt, /**< `(I)` rx cnt. Only works for a local port. */ @@ -1135,11 +1155,11 @@ lldpctl_atom_t *lldpctl_atom_iter_value(lldpctl_atom_t *atom, * reference count of the provided value is decremented. If you need to use it * outside of the loop, you need to increment it. */ -#define lldpctl_atom_foreach(atom, value) \ - for (lldpctl_atom_iter_t *iter##_LINE_ = lldpctl_atom_iter(atom); \ - iter##_LINE_ && (value = lldpctl_atom_iter_value(atom, iter##_LINE_)); \ - iter##_LINE_ = lldpctl_atom_iter_next(atom, iter##_LINE_), \ - lldpctl_atom_dec_ref(value)) +#define lldpctl_atom_foreach(atom, value) \ + for (lldpctl_atom_iter_t *iter##_LINE_ = lldpctl_atom_iter(atom); \ + iter##_LINE_ && (value = lldpctl_atom_iter_value(atom, iter##_LINE_)); \ + iter##_LINE_ = lldpctl_atom_iter_next(atom, iter##_LINE_), \ + lldpctl_atom_dec_ref(value)) /** * Create a new value for an iterable element. diff --git a/src/lldp-const.h b/src/lldp-const.h index c3fc40e4..454424d0 100644 --- a/src/lldp-const.h +++ b/src/lldp-const.h @@ -207,6 +207,11 @@ #define LLDP_DOT3_POWER_8023AT_TYPE1 1 #define LLDP_DOT3_POWER_8023AT_TYPE2 2 +/* 802.3bt additions */ +#define LLDP_DOT3_POWER_8023BT_OFF 0 +#define LLDP_DOT3_POWER_8023BT_TYPE3 1 +#define LLDP_DOT3_POWER_8023BT_TYPE4 2 + /* Dot3 power source */ #define LLDP_DOT3_POWER_SOURCE_UNKNOWN 0 #define LLDP_DOT3_POWER_SOURCE_PRIMARY 1 diff --git a/src/lldpd-structs.h b/src/lldpd-structs.h index 10fcdf65..5647c83f 100644 --- a/src/lldpd-structs.h +++ b/src/lldpd-structs.h @@ -125,6 +125,22 @@ struct lldpd_dot3_power { u_int8_t priority; u_int16_t requested; u_int16_t allocated; + + /* For 802.3BT */ + u_int8_t pd_4pid; + u_int16_t requested_a; + u_int16_t requested_b; + u_int16_t allocated_a; + u_int16_t allocated_b; + u_int16_t pse_status; + u_int8_t pd_status; + u_int8_t pse_pairs_ext; + u_int8_t class_a; + u_int8_t class_b; + u_int8_t class_ext; + u_int8_t type_ext; + u_int8_t pd_load; + u_int16_t pse_max; }; MARSHAL(lldpd_dot3_power); #endif diff --git a/tests/integration/data/8023bt.pcap b/tests/integration/data/8023bt.pcap new file mode 100644 index 00000000..932b593f Binary files /dev/null and b/tests/integration/data/8023bt.pcap differ diff --git a/tests/integration/test_pcap.py b/tests/integration/test_pcap.py index 3a61cea4..ef8ff01c 100644 --- a/tests/integration/test_pcap.py +++ b/tests/integration/test_pcap.py @@ -50,6 +50,46 @@ def test_cisco_sg200(request, lldpd1, lldpcli, namespaces): assert out == expected +@pytest.mark.skipif("'Dot3' not in config.lldpd.features", readon="Dot3 not supported") +def test_8023bt(lldpd1, lldpcli, namespaces): + with namespaces(2): + pytest.helpers.send_pcap("data/8023bt.pcap", "eth1") + with namespaces(1): + out = lldpcli("-f", "keyvalue", "show", "neighbors", "details") + for k in list(out.keys()): + if not k.startswith("lldp.eth0.port.power."): + del out[k] + assert out == { + "lldp.eth0.port.power.supported": "yes", + "lldp.eth0.port.power.enabled": "yes", + "lldp.eth0.port.power.paircontrol": "yes", + "lldp.eth0.port.power.device-type": "PSE", + "lldp.eth0.port.power.pairs": "signal", + "lldp.eth0.port.power.class": "class 4", + "lldp.eth0.port.power.power-type": "2", + "lldp.eth0.port.power.source": "PSE", + "lldp.eth0.port.power.priority": "low", + "lldp.eth0.port.power.requested": "71000", + "lldp.eth0.port.power.allocated": "51000", + "lldp.eth0.port.power.requested-a": "35500", + "lldp.eth0.port.power.requested-b": "35500", + "lldp.eth0.port.power.allocated-a": "25500", + "lldp.eth0.port.power.allocated-b": "25500", + "lldp.eth0.port.power.pse-powering-status": "4-pair powering single-signature PD", + "lldp.eth0.port.power.pd-powering-status": "unknown", + "lldp.eth0.port.power.power-pairs-ext": "both alternatives", + "lldp.eth0.port.power.power-class-ext-a": "class 4", + "lldp.eth0.port.power.power-class-ext-b": "class 4", + "lldp.eth0.port.power.power-class-ext": "dual-signature PD", + "lldp.eth0.port.power.power-type-ext": "type 3 PSE", + "lldp.eth0.port.power.pd-load": ( + "PD is single- or dual-signature and power " + "is not electrically isolated" + ), + "lldp.eth0.port.power.max-power": "51000", + } + + @pytest.mark.skipif( "'LLDP-MED' not in config.lldpd.features", readon="LLDP-MED not supported" )