Changliang Wu <changliang...@smartx.com> writes: > Signed-off-by: Changliang Wu <changliang...@smartx.com> > --- > NEWS | 1 + > lib/lldp/lldp-const.h | 41 +++--- > lib/lldp/lldp.c | 76 +++++++++- > lib/lldp/lldpd-structs.h | 24 ++++ > lib/ovs-lldp.c | 303 +++++++++++++++++++++++++++++++++++++++ > 5 files changed, 427 insertions(+), 18 deletions(-) > > diff --git a/NEWS b/NEWS > index c66b41e64..72e0f495e 100644 > --- a/NEWS > +++ b/NEWS > @@ -16,6 +16,7 @@ Post-v3.5.0 > - ovs-appctl: > * Added JSON output support to the 'ovs/route/show' command. > * Added 'lldp/neighbor' command that displays lldp neighbor infomation. > + Support for lldp dot1 and dot3 tlv.
This should be its own section - lldp: * Added support for dot1 and dot3 TLVs. > - SSL/TLS: > * Support for deprecated TLSv1 and TLSv1.1 protocols on OpenFlow and > database connections is now removed. > diff --git a/lib/lldp/lldp-const.h b/lib/lldp/lldp-const.h > index 8c5c0733e..7b9c74149 100644 > --- a/lib/lldp/lldp-const.h > +++ b/lib/lldp/lldp-const.h > @@ -85,6 +85,11 @@ > #define LLDP_DOT3_MAU_10GIGBASELW 39 > #define LLDP_DOT3_MAU_10GIGBASESW 40 > > +#define LLDP_DOT3_POWER_PORT_CLASS (1 << 0) > +#define LLDP_DOT3_POWER_SUPPORT (1 << 1) > +#define LLDP_DOT3_POWER_ENABLED (1 << 2) > +#define LLDP_DOT3_POWER_PAIRCONTROL (1 << 3) > + > /* Dot3 Power Devicetype */ > #define LLDP_DOT3_POWER_PSE 1 > #define LLDP_DOT3_POWER_PD 2 > @@ -112,23 +117,27 @@ > #define LLDP_DOT3_POWER_PRIO_HIGH 2 > #define LLDP_DOT3_POWER_PRIO_LOW 3 > > +/* Auto-Negotiation Support/Status field, from RFC 4836 */ > +#define LLDP_DOT3_LINK_AUTONEG_SUPPORT (1 << 0) > +#define LLDP_DOT3_LINK_AUTONEG_ENABLED (1 << 1) > + > /* PMD Auto-Negotiation Advertised Capability field, from RFC 3636 */ > -#define LLDP_DOT3_LINK_AUTONEG_OTHER 0x8000 > -#define LLDP_DOT3_LINK_AUTONEG_10BASE_T 0x4000 > -#define LLDP_DOT3_LINK_AUTONEG_10BASET_FD 0x2000 > -#define LLDP_DOT3_LINK_AUTONEG_100BASE_T4 0x1000 > -#define LLDP_DOT3_LINK_AUTONEG_100BASE_TX 0x0800 > -#define LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD 0x0400 > -#define LLDP_DOT3_LINK_AUTONEG_100BASE_T2 0x0200 > -#define LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD 0x0100 > -#define LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE 0x0080 > -#define LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE 0x0040 > -#define LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE 0x0020 > -#define LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE 0x0010 > -#define LLDP_DOT3_LINK_AUTONEG_1000BASE_X 0x0008 > -#define LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD 0x0004 > -#define LLDP_DOT3_LINK_AUTONEG_1000BASE_T 0x0002 > -#define LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD 0x0001 > +#define LLDP_DOT3_LINK_AUTONEG_OTHER 0x8000 > +#define LLDP_DOT3_LINK_AUTONEG_10BASE_T 0x4000 > +#define LLDP_DOT3_LINK_AUTONEG_10BASE_T_FD 0x2000 > +#define LLDP_DOT3_LINK_AUTONEG_100BASE_T4 0x1000 > +#define LLDP_DOT3_LINK_AUTONEG_100BASE_TX 0x0800 > +#define LLDP_DOT3_LINK_AUTONEG_100BASE_TX_FD 0x0400 > +#define LLDP_DOT3_LINK_AUTONEG_100BASE_T2 0x0200 > +#define LLDP_DOT3_LINK_AUTONEG_100BASE_T2_FD 0x0100 > +#define LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE 0x0080 > +#define LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE 0x0040 > +#define LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE 0x0020 > +#define LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE 0x0010 > +#define LLDP_DOT3_LINK_AUTONEG_1000BASE_X 0x0008 > +#define LLDP_DOT3_LINK_AUTONEG_1000BASE_X_FD 0x0004 > +#define LLDP_DOT3_LINK_AUTONEG_1000BASE_T 0x0002 > +#define LLDP_DOT3_LINK_AUTONEG_1000BASE_T_FD 0x0001 Why did you rename these constants? Please keep them as in lldpd. > /* Capabilities */ > #define LLDP_CAP_OTHER 0x01 > diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c > index 6fdcfef56..136247100 100644 > --- a/lib/lldp/lldp.c > +++ b/lib/lldp/lldp.c > @@ -18,6 +18,7 @@ > */ > > #include <config.h> > +#include "lldp-tlv.h" > #include "lldpd.h" > #include <errno.h> > #include <time.h> > @@ -567,10 +568,81 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, > int s, > CHECK_TLV_SIZE(1 + sizeof orgid, "Organisational"); > PEEK_BYTES(orgid, sizeof orgid); > tlv_subtype = PEEK_UINT8; > + uint8_t tlv_org_size; > if (memcmp(dot1, orgid, sizeof orgid) == 0) { > - hardware->h_rx_unrecognized_cnt++; > + switch (tlv_subtype) { > + case LLDP_TLV_DOT1_PVID: > + CHECK_TLV_SIZE(2, "Dot1 Port VLAN ID"); > + port->p_dot1.pvid = PEEK_UINT16; > + port->p_dot1_enable |= (1 << LLDP_TLV_DOT1_PVID); > + break; > + case LLDP_TLV_DOT1_PPVID: > + CHECK_TLV_SIZE(2, "Dot1 Port And Protocol VLAN ID"); > + port->p_dot1.ppvid = PEEK_UINT16; > + port->p_dot1_enable |= (1 << LLDP_TLV_DOT1_PPVID); > + break; > + case LLDP_TLV_DOT1_VLANNAME: > + case LLDP_TLV_DOT1_PI: > + if (tlv_subtype == LLDP_TLV_DOT1_VLANNAME) { > + CHECK_TLV_SIZE(2, "DOT1 VLAN ID"); > + port->p_dot1.vlan_id = PEEK_UINT16; > + port->p_dot1_enable |= (1 << LLDP_TLV_DOT1_VLANNAME); > + } > + CHECK_TLV_SIZE(1, "DOT1 VLAN Name/PI Length"); > + tlv_org_size = PEEK_UINT8; > + if (tlv_org_size < 1) { > + VLOG_DBG("empty dot1 vlan name/pi tlv received on > %s", > + hardware->h_ifname); > + goto malformed; > + } > + CHECK_TLV_SIZE(tlv_org_size, "DOT1 VLAN Name/PI"); > + b = xzalloc(tlv_org_size + 1); > + PEEK_BYTES(b, tlv_org_size); > + if (tlv_subtype == LLDP_TLV_DOT1_VLANNAME) { > + free(port->p_dot1.vlan_name); > + port->p_dot1.vlan_name = b; > + } else if (tlv_subtype == LLDP_TLV_DOT1_PI) { > + free(port->p_dot1.pi); > + port->p_dot1.pi = b; > + port->p_dot1_enable |= (1 << LLDP_TLV_DOT1_PI); > + } This code introduces two subtle memory leaks. The first is when tlv_subtype is not recognized, and the second is if multiple instances of the DOT1 TLVs are included. Both need to be addressed. Further, this code does not mirror lldpd at all. Why change from the lldpd implementation? I raised the issue back when you first mentioned adding support for dot1 and dot3 TLVs and I asked whether it would be better to try and work with lldpd folks to export their protocol handling as a library we could use. That would mean we wouldn't be introducing these kinds of issues from the lldpd side, and we could retain an upgrade path that would be independent of the OVS tree. That might be the better approach here. > + break; > + default: > + VLOG_INFO("unknown org tlv [%02x:%02x:%02x] received " > + "on %s", > + orgid[0], orgid[1], orgid[2], > + hardware->h_ifname); > + hardware->h_rx_unrecognized_cnt++; > + } > } else if (memcmp(dot3, orgid, sizeof orgid) == 0) { > - hardware->h_rx_unrecognized_cnt++; > + switch (tlv_subtype) { > + case LLDP_TLV_DOT3_MAC: > + CHECK_TLV_SIZE(5, "DOT3 MAC"); > + port->p_dot3.auto_nego = PEEK_UINT8; > + port->p_dot3.pmd_auto_nego = PEEK_UINT16; > + port->p_dot3.mau = PEEK_UINT16; > + port->p_dot3_enable |= (1 << LLDP_TLV_DOT3_MAC); > + break; > + case LLDP_TLV_DOT3_POWER: > + CHECK_TLV_SIZE(3, "DOT3 MDI"); > + port->p_dot3.mdi = PEEK_UINT8; > + port->p_dot3.pse = PEEK_UINT8; > + port->p_dot3.power_class = PEEK_UINT8; > + port->p_dot3_enable |= (1 << LLDP_TLV_DOT3_POWER); > + break; > + case LLDP_TLV_DOT3_LA: break; > + case LLDP_TLV_DOT3_MFS: > + CHECK_TLV_SIZE(3, "DOT3 MFS"); > + port->p_dot3.mfs = PEEK_UINT16; > + port->p_dot3_enable |= (1 << LLDP_TLV_DOT3_MFS); > + break; > + default: > + VLOG_INFO("unknown org tlv [%02x:%02x:%02x] received " > + "on %s", > + orgid[0], orgid[1], orgid[2], > + hardware->h_ifname); > + hardware->h_rx_unrecognized_cnt++; > + } > } else if (memcmp(med, orgid, sizeof orgid) == 0) { > /* LLDP-MED */ > hardware->h_rx_unrecognized_cnt++; > diff --git a/lib/lldp/lldpd-structs.h b/lib/lldp/lldpd-structs.h > index fe5d5f9f8..bb8939db1 100644 > --- a/lib/lldp/lldpd-structs.h > +++ b/lib/lldp/lldpd-structs.h > @@ -79,6 +79,24 @@ struct lldpd_chassis { > /* WARNING: any change to this structure should also be reflected into > `lldpd_copy_chassis()` which is not using marshaling. */ > > +struct lldpd_tlv_dot1 { > + u_int16_t pvid; /* Port VLAN identifier */ > + u_int16_t ppvid; /* Port and protocol VLAN identifier */ > + char *vlan_name; /* VLAN Name in LLDP_TLV_DOT1_VLANNAME */ > + u_int16_t vlan_id; /* VLAN ID in LLDP_TLV_DOT1_VLANNAME */ > + char *pi; /* protocol identity */ > +}; > + > +struct lldpd_tlv_dot3 { > + u_int8_t auto_nego; /* auto-negotiation support/status */ > + u_int16_t pmd_auto_nego; /* PMD auto-negotiation advertised capability */ > + u_int16_t mau; /* Operational MAU type */ > + u_int8_t mdi; /* MDI power support */ > + u_int8_t pse; /* PSE power pair */ > + u_int8_t power_class; /* Port class */ > + u_int16_t mfs; /* Maximum 802.3 frame size */ > +}; > + > struct lldpd_port { > struct ovs_list p_entries; > struct lldpd_chassis *p_chassis; /* Attached chassis */ > @@ -98,6 +116,12 @@ struct lldpd_port { > char *p_descr; > u_int16_t p_mfs; > struct lldpd_aa_element_tlv p_element; > + /* Bitmask for dot1 tlv received */ > + u_int16_t p_dot1_enable; > + struct lldpd_tlv_dot1 p_dot1; > + /* Bitmask for dot3 tlv received */ > + u_int16_t p_dot3_enable; > + struct lldpd_tlv_dot3 p_dot3; > struct ovs_list p_isid_vlan_maps; /* Contains "struct > lldpd_aa_isid_vlan_maps_tlv"s. */ > }; > > diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c > index da8faf873..b1febb355 100644 > --- a/lib/ovs-lldp.c > +++ b/lib/ovs-lldp.c > @@ -313,6 +313,303 @@ aa_print_isid_status(struct ds *ds, struct lldp *lldp) > OVS_REQUIRES(mutex) > } > } > > +static void > +lldp_print_neighbor_port_dot1(struct ds *ds, struct lldpd_port *port) > +{ > + if (port->p_dot1_enable & > + ((1 << LLDP_TLV_DOT1_PVID) | (1 << LLDP_TLV_DOT1_VLANNAME))) { > + ds_put_format(ds, " VLAN: \t"); > + } > + if (port->p_dot1_enable & (1 << LLDP_TLV_DOT1_PVID)) { > + ds_put_format(ds, " %d, ", port->p_dot1.pvid); > + if (!(port->p_dot1_enable & (1 << LLDP_TLV_DOT1_VLANNAME)) && > + port->p_dot1.pvid > 0) { > + ds_put_format(ds, "pvid: yes"); > + } > + } > + if (port->p_dot1_enable & (1 << LLDP_TLV_DOT1_VLANNAME)) { > + ds_put_format(ds, "pvid: %s", > + port->p_dot1.pvid == port->p_dot1.vlan_id ? "yes" > + : "no"); > + if (port->p_dot1.vlan_name) { > + ds_put_format(ds, ", %s", port->p_dot1.vlan_name); > + } > + } > + ds_put_format(ds, "\n"); > +} > + > +static void > +lldp_print_neighbor_port_dot1_json(struct json *interface_item_json, > + struct lldpd_port *port) > +{ > + struct json *vlan_json = NULL; > + if (port->p_dot1_enable & (1 << LLDP_TLV_DOT1_PVID)) { > + if (!vlan_json) { > + vlan_json = json_object_create(); > + } > + json_object_put(vlan_json, "vlan-id", > + json_integer_create(port->p_dot1.pvid)); > + > + if (!(port->p_dot1_enable & (1 << LLDP_TLV_DOT1_VLANNAME)) && > + port->p_dot1.pvid > 0) { > + json_object_put(vlan_json, "pvid", json_boolean_create(true)); > + } > + } > + if (port->p_dot1_enable & (1 << LLDP_TLV_DOT1_VLANNAME)) { > + if (!vlan_json) { > + vlan_json = json_object_create(); > + } > + json_object_put( > + vlan_json, "pvid", > + json_boolean_create( > + port->p_dot1.pvid == port->p_dot1.vlan_id ? true : false)); > + if (port->p_dot1.vlan_name) { > + json_object_put(vlan_json, "value", > + json_string_create(port->p_dot1.vlan_name)); > + } > + } > + if (vlan_json) { > + json_object_put(interface_item_json, "vlan", vlan_json); > + } > + > + if (port->p_dot1_enable & (1 << LLDP_TLV_DOT1_PPVID)) { > + struct json *ppid_json = json_object_create(); > + json_object_put(ppid_json, "supported", > + port->p_dot1.ppvid & LLDP_PPVID_CAP_SUPPORTED > + ? json_boolean_create(true) > + : json_boolean_create(false)); > + json_object_put(ppid_json, "enabled", > + port->p_dot1.ppvid & LLDP_PPVID_CAP_ENABLED > + ? json_boolean_create(true) > + : json_boolean_create(false)); > + json_object_put(interface_item_json, "ppid", ppid_json); > + } > +} > + > +static void > +lldp_dot3_autoneg_advertised(struct ds *ds, uint16_t pmd_auto_nego, int > bithd, > + int bitfd, const char *type) > +{ > + if (!((pmd_auto_nego & bithd) || (pmd_auto_nego & bitfd))) { > + return; > + } > + > + ds_put_format(ds, " Adv:\t %s", type); > + if (bithd != bitfd) { > + ds_put_format(ds, ", HD: %s, FD: %s\n", > + (pmd_auto_nego & bithd) ? "yes" : "no", > + (pmd_auto_nego & bitfd) ? "yes" : "no"); > + } > +} > + > +static void > +lldp_dot3_autoneg_advertised_json(struct json **advertised_json, > + uint16_t pmd_auto_nego, int bithd, int bitfd, > + const char *type) > +{ > + if (!((pmd_auto_nego & bithd) || (pmd_auto_nego & bitfd))) { > + return; > + } > + > + if (!*advertised_json) { > + *advertised_json = json_array_create_empty(); > + } > + > + struct json *advertised_item_json = json_object_create(); > + json_object_put(advertised_item_json, "type", json_string_create(type)); > + if (bithd != bitfd) { > + json_object_put(advertised_item_json, "hd", > + json_boolean_create((pmd_auto_nego & bithd) ? true > + : > false)); > + json_object_put(advertised_item_json, "fd", > + json_boolean_create((pmd_auto_nego & bitfd) ? true > + : > false)); > + } > + json_array_add(*advertised_json, advertised_item_json); > +} > + > +static void > +lldp_print_neighbor_port_dot3(struct ds *ds, struct lldpd_port *port) > +{ > + if (port->p_dot3_enable & (1 << LLDP_TLV_DOT3_MFS)) { > + ds_put_format(ds, " MFS:\t %d\n", port->p_dot3.mfs); > + } > + > + if (port->p_dot3_enable & (1 << LLDP_TLV_DOT3_MAC)) { > + ds_put_format( > + ds, " PMD autoneg: supported: %s, enabled: %s\n", > + port->p_dot3.auto_nego & LLDP_DOT3_LINK_AUTONEG_SUPPORT ? "yes" > + : "no", > + port->p_dot3.auto_nego & LLDP_DOT3_LINK_AUTONEG_ENABLED ? "yes" > + : "no"); > + > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_10BASE_T, > + LLDP_DOT3_LINK_AUTONEG_10BASE_T_FD, > + "10Base-T"); > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_100BASE_T4, > + LLDP_DOT3_LINK_AUTONEG_100BASE_T4, > + "100Base-T4"); > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_100BASE_TX, > + LLDP_DOT3_LINK_AUTONEG_100BASE_TX_FD, > + "100Base-TX"); > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_100BASE_T2, > + LLDP_DOT3_LINK_AUTONEG_100BASE_T2_FD, > + "100Base-T2"); > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_1000BASE_X, > + LLDP_DOT3_LINK_AUTONEG_1000BASE_X_FD, > + "1000Base-X"); > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_1000BASE_T, > + LLDP_DOT3_LINK_AUTONEG_1000BASE_T_FD, > + "1000Base-T"); > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE, > + LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE, > + "FDX_PAUSE"); > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE, > + LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE, > + "FDX_APAUSE"); > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE, > + LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE, > + "FDX_SPAUSE"); > + lldp_dot3_autoneg_advertised(ds, port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE, > + LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE, > + "FDX_BPAUSE"); > + > + ds_put_format(ds, " MAU oper type:\t %d\n", port->p_dot3.mau); > + } > + > + if (port->p_dot3_enable & (1 << LLDP_TLV_DOT3_POWER)) { > + ds_put_format( > + ds, > + " MDI Power:\t supported: %s, enabled: %s, pair control: > %s\n", > + port->p_dot3.mdi & LLDP_DOT3_POWER_SUPPORT ? "yes" : "no", > + port->p_dot3.mdi & LLDP_DOT3_POWER_ENABLED ? "yes" : "no", > + port->p_dot3.mdi & LLDP_DOT3_POWER_PAIRCONTROL ? "yes" : "no"); > + > + ds_put_format(ds, " Device type:\t %s\n", > + port->p_dot3.mdi & LLDP_DOT3_POWER_PORT_CLASS ? "PSE" > + : "PD"); > + } > +} > + > +static void > +lldp_print_neighbor_port_dot3_json(struct json *port_json, > + struct lldpd_port *port) > +{ > + if (port->p_dot3_enable & (1 << LLDP_TLV_DOT3_MAC)) { > + struct json *auto_nego_json = json_object_create(); > + json_object_put(auto_nego_json, "supported", > + port->p_dot3.auto_nego & > LLDP_DOT3_LINK_AUTONEG_SUPPORT > + ? json_boolean_create(true) > + : json_boolean_create(false)); > + json_object_put(auto_nego_json, "enabled", > + port->p_dot3.auto_nego & > LLDP_DOT3_LINK_AUTONEG_ENABLED > + ? json_boolean_create(true) > + : json_boolean_create(false)); > + > + struct json *advertised_json = NULL; > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_10BASE_T, > + LLDP_DOT3_LINK_AUTONEG_10BASE_T_FD, > + "10Base-T"); > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_100BASE_T4, > + LLDP_DOT3_LINK_AUTONEG_100BASE_T4, > + "100Base-T4"); > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_100BASE_TX, > + > LLDP_DOT3_LINK_AUTONEG_100BASE_TX_FD, > + "100Base-TX"); > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_100BASE_T2, > + > LLDP_DOT3_LINK_AUTONEG_100BASE_T2_FD, > + "100Base-T2"); > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_1000BASE_X, > + > LLDP_DOT3_LINK_AUTONEG_1000BASE_X_FD, > + "1000Base-X"); > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_1000BASE_T, > + > LLDP_DOT3_LINK_AUTONEG_1000BASE_T_FD, > + "1000Base-T"); > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE, > + LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE, > + "FDX_PAUSE"); > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE, > + LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE, > + "FDX_APAUSE"); > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE, > + LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE, > + "FDX_SPAUSE"); > + lldp_dot3_autoneg_advertised_json(&advertised_json, > + port->p_dot3.pmd_auto_nego, > + LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE, > + LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE, > + "FDX_BPAUSE"); > + if (advertised_json) { > + json_object_put(auto_nego_json, "advertised", advertised_json); > + } > + > + json_object_put(auto_nego_json, "current", > + json_integer_create(port->p_dot3.mau)); > + > + json_object_put(port_json, "auto-negotiation", auto_nego_json); > + } > + > + if (port->p_dot3_enable & (1 << LLDP_TLV_DOT3_POWER)) { > + struct json *power_json = json_object_create(); > + > + json_object_put( > + power_json, "device-type", > + json_string_create( > + port->p_dot3.mdi & LLDP_DOT3_POWER_PORT_CLASS ? "PSE" : > "PD")); > + > + json_object_put( > + power_json, "supported", > + json_boolean_create( > + port->p_dot3.mdi & LLDP_DOT3_POWER_SUPPORT ? true : false)); > + > + json_object_put( > + power_json, "enabled", > + json_boolean_create( > + port->p_dot3.mdi & LLDP_DOT3_POWER_ENABLED ? true : false)); > + > + json_object_put(power_json, "paircontrol", > + json_boolean_create(port->p_dot3.mdi & > + > LLDP_DOT3_POWER_PAIRCONTROL > + ? true > + : false)); > + > + json_object_put(port_json, "power", power_json); > + } > + > + if (port->p_dot3_enable & (1 << LLDP_TLV_DOT3_MFS)) { > + json_object_put(port_json, "mfs", > + json_integer_create(port->p_dot3.mfs)); > + } > +} > + > static void > lldp_print_neighbor(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex) > { > @@ -411,6 +708,9 @@ lldp_print_neighbor(struct ds *ds, struct lldp *lldp) > OVS_REQUIRES(mutex) > strlen(port->p_descr) ? port->p_descr : none_str); > ds_put_format(ds, " TTL:\t %d\n", port->p_chassis->c_ttl); > > + lldp_print_neighbor_port_dot3(ds, port); > + lldp_print_neighbor_port_dot1(ds, port); > + > ds_put_format(ds, > "-----------------------------------------------" > "--------------------------------\n"); > } > @@ -578,6 +878,9 @@ lldp_print_neighbor_json(struct json > *interface_array_json, struct lldp *lldp) > json_object_put(port_json, "ttl", > json_integer_create(port->p_chassis->c_ttl)); > > + lldp_print_neighbor_port_dot1_json(interface_item_json, port); > + lldp_print_neighbor_port_dot3_json(port_json, port); > + > json_object_put(interface_item_json, "chassis", chassis_json); > json_object_put(interface_item_json, "port", port_json); I didn't look at the json output side, because I think Eelco has some opinions on how best to output those details. But Ilya noted issues with the command outputs, so in the next round that needs to be addressed. _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev