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

Reply via email to