Hi, Eelco On Wed, Jun 4, 2025 at 4:51 PM Eelco Chaudron <echau...@redhat.com> wrote: > > > > On 3 Jun 2025, at 5:06, Changliang Wu wrote: > > > Hi, Eelco > > Thanks for reviewing the patch. > > > > 1. The test case must be very important. I will figure it out and add them > > in the next version. > > Thanks. > > > 2. I have no reply regarding the formatting issue in the comment. > > As it mentioned in V4, all output formats here are following > > https://github.com/lldpd/lldpd. > > The above project is widely used by many users, and the early > > implementation of ovs lldp looks very similar to this project. > > > > So we may need to discuss whether we should strictly follow the output > > format of the existing implementation (for easy adaptation) > > or optimize the output here (there are indeed some unreasonable places in > > the output of lldpd) > > Yes, we need to discuss whether we want a clean look or adopt an existing, > not-so-nice implementation. I might be biased here, as I worked on the early > LLDP spec and did the Extreme Networks implementation. > > > 3. I have implemented the decoding of dot1 dot3 tlv and will provide it in > > the next version. > > > > On Fri, May 30, 2025 at 8:35 PM Eelco Chaudron <echau...@redhat.com> wrote: > >> > >> > >> > >> On 27 May 2025, at 7:28, Changliang Wu wrote: > >> > >> Thanks for the patch. However, it’s missing unit tests. > >> See some other comments below. Note, this was a quick review, so more > > changes might be needed. > >> > >> > >>> New appctl 'lldp/neighbor' displays lldp neighbor informations. > >> > >> informations -> information > > OK > >> > >>> Support json output with --format json --pretty > >>> > >>> Example outputs would be: > >>> ovs-appctl lldp/neighbor > >>> > > ------------------------------------------------------------------------------- > >>> LLDP neighbors: > >>> > > ------------------------------------------------------------------------------- > >>> Interface: ens5 > >>> Chassis: > >>> Chassis ID: 9c:71:3a:58:05:b4 > >>> SysName: n-203 > >>> SysDescr: CentOS Linux 7 (Core) Linux 4.19.90-2307.3.0.el7...... > >>> MgmtIP: 4.4.4.203 > >>> MgmtIface: 13 > >>> MgmtIP: fe80::9e71:3aff:fe58:5b4 > >>> MgmtIface: 2 > >>> Capability: Bridge, off > >>> Capability: Router, off > >>> Capability: Wlan, off > >>> Capability: Station, on > >>> Port: > >>> PortID: fe:54:00:80:ea:68 > >>> PortDescr: vnet74 > >>> TTL: 120 > >>> > > ------------------------------------------------------------------------------- > >>> Interface: ens14np0 > >>> Chassis: > >>> Chassis ID: 1c:34:da:88:27:c0 > >>> SysName: 7F-67.239 > >>> SysDescr: MSN2700,Onyx,SWv3.8.2008 > >>> MgmtIP: 192.168.67.239 > >>> MgmtIface: 0 > >>> Capability: Bridge, on > >>> Capability: Router, off > >>> Port: > >>> PortID: Eth1/7/1 > >>> PortDescr: > >>> TTL: 120 > >>> > > ------------------------------------------------------------------------------- > >>> > >>> ovs-appctl lldp/neighbor ens14np0 > >>> > > ------------------------------------------------------------------------------- > >>> LLDP neighbours: > >>> > > ------------------------------------------------------------------------------- > >>> Interface: ens14np0 > >>> Chassis: > >> > >> Makes more sense to call this a neighbour. > > > > I am not a native English speaker. > > I learned from Google that neighbor and neighbour are only different in the > > US and UK. > > Also, in RFC, neighbor is used more often. Is there any other distinction > > here? > > Well I’m fine with any value, but you should be consistant to one. The > command is lldp/neighbor, and the header uses neighbours. >
Right! These are my spelling mistakes! > > However, I was more concerned about the ‘Chassis:’ header. I guess it will be > clarified if you have an example with two neighbors on one port. > Normally, this will not happen unless manually injecting different lldp pkt into a port. > >> > >>> Chassis ID: 1c:34:da:88:27:c0 > >>> SysName: 7F-67.239 > >>> SysDescr: MSN2700,Onyx,SWv3.8.2008 > >>> MgmtIP: 192.168.67.239 > >>> MgmtIface: 0 > >>> Capability: Bridge, on > >>> Capability: Router, off > >>> Port: > >> > >> Don’t think this port heading is needed. > >> > >>> PortID: Eth1/7/1 > >>> PortDescr: > >>> TTL: 120 > >> > >> I would move TTL up. Maybe order the items on the TLV type number? > > Mandatory items first. > >> Maybe (if tracked in the code), don’t display the missing non-mandatory > > items? > >> > >>> > > ------------------------------------------------------------------------------- > >>> > >>> ovs-appctl --format json --pretty lldp/neighbor ens14np0 > >>> { > >>> "lldp": { > >> > >> Don’t think the top lldp is needed > >> > >>> "interface": [ > >> > >> As multiple interfaces can exist, this should be ‘interfaces’. > >> > >>> { > >>> "ens14np0": { > >> > >> Multiple neighbours can exist, so there should be a ‘neighbours’ > > container. > >> > >>> "chassis": { > >> > >> Don’t think ‘chassis’ is needed, just a container grouping all the TVL > > data. > >> > >> > >>> "7F-67.239": { > >> > >> If you really want to ID individual neighbours, it should be a > > combination of the chassis ID + Port. > >> However, I guess a simple container will do the job. > >> > >> I think this is a good example of what it could look like (not names can > > be changed): > >> > >> { > >> "interfaces": { > >> "eth0": { > >> "neighbours": { > >> "Chassis ID": { > >> "type": "chasIdMacAddress", > >> "string": "1c:34:da:88:27:c0" > >> } > >> “Port ID": { > >> "type": "ifName", > >> "string": "Eth1/7/1" > >> } > >> “Management Address": { > >> "Family": "IP", > >> “Address”: "192.168.67.239" > >> < this has more attributes, not sure what we store > > >> } > >> “Port Description”: “Port from a to b” > >> “System Name”: “ ” > >> “System description”: “openvswitch 3.5.90” > >> “System Capabilities”: { > >> “Bridge” { > >> capable: true, > >> enabled: true > >> }, > >> “Router” { > >> capable: false, > >> enabled: false > >> } > >> ... > >> } > >> } > >> }, > >> "wlan0": { > >> "neighbours": { > >> ... > >> ... > >> } > >> } > >> } > >> } > >> > >> Note, I added some of the TLV using the format, naming as in the spec, > > which makes it easier to understand/read/parse. > >> > >>> "capability": [ > >>> { > >>> "enabled": true, > >>> "type": "Bridge"}, > >>> { > >>> "enabled": false, > >>> "type": "Router"}], > >>> "descr": "openvswitch 3.5.90", > >>> "id": { > >>> "type": "mac", > >>> "value": "1c:34:da:88:27:c0"}, > >>> "mgmt-iface": [ > >>> 0], > >>> "mgmt-ip": [ > >>> "192.168.67.239"]}}, > >>> "port": { > >>> "desc": " ", > >>> "id": { > >>> "type": "ifname", > >>> "value": "Eth1/7/1"}, > >>> "ttl": 120}}}]}} > >>> > >>> Signed-off-by: Changliang Wu <changliang...@smartx.com> > >>> --- > >>> > >>> V2: fix code lint and build warn > >>> V3: fix more static analyze error > >>> V4: fix build error > >>> (apologize for spam emails, found tests via github action and > > fully tested) > >>> V5: add json output, add NEWS > >>> > >>> NEWS | 1 + > >>> lib/ovs-lldp.c | 329 +++++++++++++++++++++++++++++++++++++ > >>> vswitchd/ovs-vswitchd.8.in | 4 + > >>> 3 files changed, 334 insertions(+) > >>> > >>> diff --git a/NEWS b/NEWS > >>> index e6da3b122..bc398ea95 100644 > >>> --- a/NEWS > >>> +++ b/NEWS > >>> @@ -13,6 +13,7 @@ Post-v3.5.0 > >>> core file size. > >>> - ovs-appctl: > >>> * Added JSON output support to the 'ovs/route/show' command. > >>> + * Added 'lldp/neighbor' command that displays lldp neighbor > > infomations. > >>> - SSL/TLS: > >>> * Support for deprecated TLSv1 and TLSv1.1 protocols on OpenFlow > > and > >>> database connections is now removed. > >>> diff --git a/lib/ovs-lldp.c b/lib/ovs-lldp.c > >>> index 2d13e971e..5ab5d27af 100644 > >>> --- a/lib/ovs-lldp.c > >>> +++ b/lib/ovs-lldp.c > >>> @@ -34,7 +34,9 @@ > >>> #include <inttypes.h> > >>> #include <stdbool.h> > >>> #include <stdlib.h> > >>> +#include "lldp/lldp-const.h" > >>> #include "openvswitch/dynamic-string.h" > >>> +#include "openvswitch/json.h" > >> > >> Add includes in alphabetical order if possible. > > > > OK, since the original content is not completely in alphabetical order, > > I can only make it sorted around the newly added includes. > > Ok, makes sense > > >>> #include "flow.h" > >>> #include "openvswitch/list.h" > >>> #include "lldp/lldpd.h" > >>> @@ -324,6 +326,284 @@ aa_print_isid_status(struct ds *ds, struct lldp > > *lldp) OVS_REQUIRES(mutex) > >>> } > >>> } > >>> > >>> +static void > >>> +lldp_print_neighbor_port(struct ds *ds, struct lldpd_hardware *hw) > >>> +{ > >>> + struct lldpd_port *port; > >>> + const char *none_str = "<None>"; > >>> + > >>> + LIST_FOR_EACH (port, p_entries, &hw->h_rports) { > >>> + if (!port->p_chassis) { > >>> + continue; > >>> + } > >>> + ds_put_format(ds, " Chassis:\n"); > >>> + char *id = NULL; > >> > >> Definitions right after LIST_FOR_EACH followed by a newline. > > > > OK > > > >> > >>> + if (port->p_chassis->c_id_len > 0) { > >>> + chassisid_to_string(port->p_chassis->c_id, > >>> + port->p_chassis->c_id_len, &id); > >>> + } > >>> + ds_put_format(ds, " Chassis ID:\t %s\n", id ?: none_str); > >>> + ds_put_format(ds, " SysName:\t %s\n", > >>> + strlen(port->p_chassis->c_name) ? > > port->p_chassis->c_name > >>> + : none_str); > >>> + ds_put_format(ds, " SysDescr:\t %s\n", > >>> + strlen(port->p_chassis->c_descr) > >>> + ? port->p_chassis->c_descr > >>> + : none_str); > >>> + free(id); > >>> + > >>> + struct lldpd_mgmt *mgmt; > >>> + struct in6_addr ip; > >> > >> Could these go inside the LIST_FOR_EACH? > > > > Sure > > > >> > >>> + LIST_FOR_EACH (mgmt, m_entries, &port->p_chassis->c_mgmt) { > >>> + switch (mgmt->m_family) { > >>> + case LLDPD_AF_IPV4: > >>> + in6_addr_set_mapped_ipv4(&ip, > > mgmt->m_addr.inet.s_addr); > >>> + break; > >>> + case LLDPD_AF_IPV6: ip = mgmt->m_addr.inet6; break; > >>> + default: continue; > >>> + } > >>> + ds_put_format(ds, " MgmtIP:\t "); > >>> + ipv6_format_mapped(&ip, ds); > >>> + ds_put_format(ds, "\n"); > >>> + ds_put_format(ds, " MgmtIface:\t %d\n", mgmt->m_iface); > >>> + } > >>> + > >>> + if (port->p_chassis->c_cap_available & LLDP_CAP_BRIDGE) { > >>> + ds_put_format(ds, " Capability:\t Bridge, %s\n", > >>> + port->p_chassis->c_cap_enabled & > > LLDP_CAP_BRIDGE > >>> + ? "on" > >>> + : "off"); > >>> + } > >>> + if (port->p_chassis->c_cap_available & LLDP_CAP_ROUTER) { > >>> + ds_put_format(ds, " Capability:\t Router, %s\n", > >>> + port->p_chassis->c_cap_enabled & > > LLDP_CAP_ROUTER > >>> + ? "on" > >>> + : "off"); > >>> + } > >>> + if (port->p_chassis->c_cap_available & LLDP_CAP_WLAN) { > >>> + ds_put_format( > >>> + ds, " Capability:\t Wlan, %s\n", > >>> + port->p_chassis->c_cap_enabled & LLDP_CAP_WLAN ? "on" > > : "off"); > >>> + } > >>> + if (port->p_chassis->c_cap_available & LLDP_CAP_STATION) { > >>> + ds_put_format(ds, " Capability:\t Station, %s\n", > >>> + port->p_chassis->c_cap_enabled & > > LLDP_CAP_STATION > >>> + ? "on" > >>> + : "off"); > >>> + } > >>> + > >> > >> Should we print both enabled and advertised? What about other > > capabilities? > >> > >>> + ds_put_format(ds, " Port:\n"); > >>> + > >>> + if (port->p_id_subtype == LLDP_PORTID_SUBTYPE_LLADDR) { > >>> + id = NULL; > >>> + if (port->p_id_len > 0) { > >>> + chassisid_to_string((uint8_t *) port->p_id, > > port->p_id_len, > >>> + &id); > >>> + } > >>> + ds_put_format(ds, " PortID:\t %s\n", id ?: none_str); > >>> + free(id); > >>> + } else { > >>> + ds_put_format(ds, " PortID:\t %s\n", port->p_id ?: > > none_str); > >> > >> Are we sure it’s a string if set for all other subtypes? > >> > >>> + } > >>> + ds_put_format(ds, " PortDescr:\t %s\n", > >>> + strlen(port->p_descr) ? port->p_descr : > > none_str); > >>> + ds_put_format(ds, " TTL:\t %d\n", port->p_chassis->c_ttl); > >>> + if (port->p_mfs) { > >>> + ds_put_format(ds, " MFS:\t %d\n", port->p_mfs); > >> > >> What is MFS, and is it ever set? > > > > It's a mistake, MFS (Maximum Frame Size) means MTU,defined in dot3 tlv. > > I have implemented the decoding of dot1 tlv and dot3 tlv, > > and will update it in the next version. > > See Aaron’s comments, so I guess we can remove it for now. > > > >>> + } > >>> + } > >>> +} > >>> + > >>> +static void > >>> +lldp_print_neighbor_port_json(struct json *interface_item_json, > >>> + struct lldpd_hardware *hw) > >>> +{ > >>> + const char *none_str = "<None>"; > >>> + struct lldpd_port *port; > >>> + > >>> + LIST_FOR_EACH (port, p_entries, &hw->h_rports) { > >>> + if (!port->p_chassis) { > >>> + continue; > >>> + } > >>> + > >>> + struct json *chassis_json = json_object_create(); > >>> + struct json *chassis_sys_json = json_object_create(); > >>> + struct json *chassis_id_json = json_object_create(); > >>> + struct json *chassis_mgmt_ip_json = json_array_create_empty(); > >>> + struct json *chassis_mgmt_iface_json = > > json_array_create_empty(); > >>> + struct json *chassis_capability_json = > > json_array_create_empty(); > >>> + struct json *chassis_capability_item_json; > >>> + struct json *port_json = json_object_create(); > >>> + struct json *port_id_json = json_object_create(); > >>> + > >>> + char *id = NULL; > >>> + if (port->p_chassis->c_id_len > 0) { > >>> + chassisid_to_string(port->p_chassis->c_id, > >>> + port->p_chassis->c_id_len, &id); > >>> + } > >>> + > >>> + json_object_put(chassis_id_json, "type", > > json_string_create("mac")); > >>> + json_object_put(chassis_id_json, "value", > >>> + json_string_create(id ?: none_str)); > >>> + json_object_put(chassis_sys_json, "id", chassis_id_json); > >>> + > >>> + json_object_put(chassis_json, > >>> + strlen(port->p_chassis->c_name) > >>> + ? port->p_chassis->c_name > >>> + : none_str, > >>> + chassis_sys_json); > >>> + > >>> + json_object_put(chassis_sys_json, "descr", > >>> + > > json_string_create(strlen(port->p_chassis->c_descr) > >>> + ? > > port->p_chassis->c_descr > >>> + : none_str)); > >>> + > >>> + free(id); > >>> + > >>> + struct lldpd_mgmt *mgmt; > >>> + struct in6_addr ip; > >>> + char addr_str[INET6_ADDRSTRLEN]; > >>> + LIST_FOR_EACH (mgmt, m_entries, &port->p_chassis->c_mgmt) { > >>> + switch (mgmt->m_family) { > >>> + case LLDPD_AF_IPV4: > >>> + in6_addr_set_mapped_ipv4(&ip, > > mgmt->m_addr.inet.s_addr); > >>> + break; > >>> + case LLDPD_AF_IPV6: ip = mgmt->m_addr.inet6; break; > >>> + default: continue; > >>> + } > >>> + > >>> + ipv6_string_mapped(addr_str, &ip); > >>> + json_array_add(chassis_mgmt_ip_json, > > json_string_create(addr_str)); > >>> + json_array_add(chassis_mgmt_iface_json, > >>> + json_integer_create(mgmt->m_iface)); > >>> + } > >>> + json_object_put(chassis_sys_json, "mgmt-ip", > > chassis_mgmt_ip_json); > >>> + json_object_put(chassis_sys_json, "mgmt-iface", > >>> + chassis_mgmt_iface_json); > >>> + > >>> + if (port->p_chassis->c_cap_available & LLDP_CAP_BRIDGE) { > >>> + chassis_capability_item_json = json_object_create(); > >>> + json_object_put(chassis_capability_item_json, "type", > >>> + json_string_create("Bridge")); > >>> + json_object_put( > >>> + chassis_capability_item_json, "enabled", > >>> + json_boolean_create(port->p_chassis->c_cap_enabled & > >>> + LLDP_CAP_BRIDGE)); > >>> + json_array_add(chassis_capability_json, > >>> + chassis_capability_item_json); > >>> + } > >>> + if (port->p_chassis->c_cap_available & LLDP_CAP_ROUTER) { > >>> + chassis_capability_item_json = json_object_create(); > >>> + json_object_put(chassis_capability_item_json, "type", > >>> + json_string_create("Router")); > >>> + json_object_put( > >>> + chassis_capability_item_json, "enabled", > >>> + json_boolean_create(port->p_chassis->c_cap_enabled & > >>> + LLDP_CAP_ROUTER)); > >>> + json_array_add(chassis_capability_json, > >>> + chassis_capability_item_json); > >>> + } > >>> + if (port->p_chassis->c_cap_available & LLDP_CAP_WLAN) { > >>> + chassis_capability_item_json = json_object_create(); > >>> + json_object_put(chassis_capability_item_json, "type", > >>> + json_string_create("Wlan")); > >>> + json_object_put( > >>> + chassis_capability_item_json, "enabled", > >>> + json_boolean_create(port->p_chassis->c_cap_enabled & > >>> + LLDP_CAP_WLAN)); > >>> + json_array_add(chassis_capability_json, > >>> + chassis_capability_item_json); > >>> + } > >>> + if (port->p_chassis->c_cap_available & LLDP_CAP_STATION) { > >>> + chassis_capability_item_json = json_object_create(); > >>> + json_object_put(chassis_capability_item_json, "type", > >>> + json_string_create("Station")); > >>> + json_object_put( > >>> + chassis_capability_item_json, "enabled", > >>> + json_boolean_create(port->p_chassis->c_cap_enabled & > >>> + LLDP_CAP_STATION)); > >>> + json_array_add(chassis_capability_json, > >>> + chassis_capability_item_json); > >>> + } > >>> + json_object_put(chassis_sys_json, "capability", > >>> + chassis_capability_json); > >>> + > >>> + if (port->p_id_subtype == LLDP_PORTID_SUBTYPE_LLADDR) { > >>> + id = NULL; > >>> + if (port->p_id_len > 0) { > >>> + chassisid_to_string((uint8_t *) port->p_id, > > port->p_id_len, > >>> + &id); > >>> + } > >>> + json_object_put(port_id_json, "type", > > json_string_create("mac")); > >>> + json_object_put(port_id_json, "value", > >>> + json_string_create(id ?: none_str)); > >>> + > >>> + free(id); > >>> + } else { > >>> + json_object_put(port_id_json, "type", > >>> + json_string_create("ifname")); > >>> + json_object_put(port_id_json, "value", > >>> + json_string_create(port->p_id ?: > > none_str)); > >>> + } > >>> + json_object_put(port_json, "id", port_id_json); > >>> + > >>> + json_object_put(port_json, "desc", > >>> + json_string_create( > >>> + strlen(port->p_descr) ? port->p_descr : > > none_str)); > >>> + json_object_put(port_json, "ttl", > >>> + json_integer_create(port->p_chassis->c_ttl)); > >>> + if (port->p_mfs) { > >>> + json_object_put(port_json, "mfs", > >>> + json_integer_create(port->p_mfs)); > >>> + } > >>> + > >>> + json_object_put(interface_item_json, "chassis", chassis_json); > >>> + json_object_put(interface_item_json, "port", port_json); > >>> + } > >>> +} > >>> + > >>> +static void > >>> +lldp_print_neighbor(struct ds *ds, struct lldp *lldp) > > OVS_REQUIRES(mutex) > >>> +{ > >>> + struct lldpd_hardware *hw; > >>> + > >>> + ds_put_format(ds, "Interface: %s\n", lldp->name); > >> > >> Do we need to print interfaces here? We do not do it for JSON. Also, if > > we do, we are missing the separator in this case. > >> > >> Can you include a test case where a single interface has two neighbours? > >> > >>> + if (!lldp->lldpd) { > >>> + return; > >>> + } > >>> + > >>> + LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware) { > >>> + lldp_print_neighbor_port(ds, hw); > >>> + } > >>> + ds_put_format(ds, > > "------------------------------------------------------" > >>> + "-------------------------\n"); > >>> +} > >>> + > >>> +static void > >>> +lldp_print_neighbor_json(struct json *interface_array_json, struct > > lldp *lldp) > >>> + OVS_REQUIRES(mutex) > >>> +{ > >>> + struct lldpd_hardware *hw; > >>> + struct json *interface_item_json; > >>> + struct json *interface_item_warp_json; > >>> + > >>> + if (!lldp->lldpd) { > >>> + return; > >>> + } > >>> + > >>> + LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware) { > >>> + interface_item_json = json_object_create(); > >>> + lldp_print_neighbor_port_json(interface_item_json, hw); > >>> + > >>> + interface_item_warp_json = json_object_create(); > >>> + json_object_put(interface_item_warp_json, lldp->name, > >>> + interface_item_json); > >>> + > >>> + json_array_add(interface_array_json, interface_item_warp_json); > >>> + } > >>> +} > >>> + > >>> static void > >>> aa_unixctl_status(struct unixctl_conn *conn, int argc OVS_UNUSED, > >>> const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) > >>> @@ -382,6 +662,53 @@ aa_unixctl_statistics(struct unixctl_conn *conn, > > int argc OVS_UNUSED, > >>> unixctl_command_reply(conn, ds_cstr(&ds)); > >>> } > >>> > >>> +static void > >>> +lldp_unixctl_show_neighbor(struct unixctl_conn *conn, int argc, > >>> + const char *argv[], void *aux OVS_UNUSED) > >>> + OVS_EXCLUDED(mutex) > >>> +{ > >>> + struct lldp *lldp; > >>> + > >>> + if (unixctl_command_get_output_format(conn) == > > UNIXCTL_OUTPUT_FMT_JSON) { > >>> + struct json *lldp_json = json_object_create(); > >>> + struct json *interface_json = json_object_create(); > >>> + struct json *interface_array_json = json_array_create_empty(); > >>> + > >>> + ovs_mutex_lock(&mutex); > >>> + HMAP_FOR_EACH (lldp, hmap_node, all_lldps) { > >>> + if (argc > 1 && strcmp(argv[1], lldp->name)) { > >>> + continue; > >>> + } > >>> + lldp_print_neighbor_json(interface_array_json,lldp); > >>> + } > >>> + ovs_mutex_unlock(&mutex); > >>> + > >>> + json_object_put(interface_json, "interface", > > interface_array_json); > >>> + json_object_put(lldp_json, "lldp", interface_json); > >>> + > >>> + unixctl_command_reply_json(conn, lldp_json); > >>> + } else { > >>> + struct ds ds = DS_EMPTY_INITIALIZER; > >>> + > >>> + ds_put_format(&ds, > > "--------------------------------------------------" > >>> + "-----------------------------\nLLDP > > neighbors:\n" > >>> + > > "--------------------------------------------------" > >>> + "-----------------------------\n"); > >>> + > >>> + ovs_mutex_lock(&mutex); > >>> + HMAP_FOR_EACH (lldp, hmap_node, all_lldps) { > >>> + if (argc > 1 && strcmp(argv[1], lldp->name)) { > >>> + continue; > >>> + } > >>> + lldp_print_neighbor(&ds, lldp); > >>> + } > >>> + ovs_mutex_unlock(&mutex); > >>> + > >>> + unixctl_command_reply(conn, ds_cstr(&ds)); > >>> + ds_destroy(&ds); > >>> + } > >>> +} > >>> + > >>> /* An Auto Attach mapping was configured. Populate the corresponding > >>> * structures in the LLDP hardware. > >>> */ > >>> @@ -649,6 +976,8 @@ lldp_init(void) > >>> aa_unixctl_show_isid, NULL); > >>> unixctl_command_register("autoattach/statistics", "[bridge]", 0, 1, > >>> aa_unixctl_statistics, NULL); > >>> + unixctl_command_register("lldp/neighbor", "[interface]", 0, 1, > >>> + lldp_unixctl_show_neighbor, NULL); > >>> } > >>> > >>> /* Returns true if 'lldp' should process packets from 'flow'. Sets > >>> diff --git a/vswitchd/ovs-vswitchd.8.in b/vswitchd/ovs-vswitchd.8.in > >>> index 98e58951d..e4a6f7e46 100644 > >>> --- a/vswitchd/ovs-vswitchd.8.in > >>> +++ b/vswitchd/ovs-vswitchd.8.in > >>> @@ -149,6 +149,10 @@ enabled. > >>> Force the fault status of the CFM module on \fIinterface\fR (or all > >>> interfaces if none is given) to be \fIstatus\fR. \fIstatus\fR can be > >>> "true", "false", or "normal" which reverts to the standard behavior. > >>> +.IP "\fBlldp/neighbor\fR [\fIinterface\fR]" > >>> +Displays detailed information about LLDP neighbor on \fIinterface\fR. > >> > >> LLDP neighbors on > > > > OK > > > >> > >>> +If \fIinterface\fR is not specified, then displays detailed information > >> > >> then it displays > > > > OK > > > >> > >>> +about all interfaces with LLDP enabled. > >>> .IP "\fBstp/tcn\fR [\fIbridge\fR]" > >>> Forces a topology change event on \fIbridge\fR if it's running STP. > > This > >>> may cause it to send Topology Change Notifications to its peers and > > flush > >>> -- > >>> 2.43.5 > >>> > >>> _______________________________________________ > >>> dev mailing list > >>> d...@openvswitch.org > >>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev > >> > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev