From patchwork Tue Jul 15 08:33:18 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changliang Wu X-Patchwork-Id: 2111436 X-Patchwork-Delegate: aconole@redhat.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=smartx-com.20230601.gappssmtp.com header.i=@smartx-com.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=sWiTYkbC; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=140.211.166.137; helo=smtp4.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp4.osuosl.org (smtp4.osuosl.org [140.211.166.137]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4bhCBb6LByz1xrM for ; Tue, 15 Jul 2025 18:33:27 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id E1EB640F8C; Tue, 15 Jul 2025 08:33:36 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id WJWasZGYgOcs; Tue, 15 Jul 2025 08:33:35 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org 2E49840F7D Authentication-Results: smtp4.osuosl.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=smartx-com.20230601.gappssmtp.com header.i=@smartx-com.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=sWiTYkbC Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp4.osuosl.org (Postfix) with ESMTPS id 2E49840F7D; Tue, 15 Jul 2025 08:33:35 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0D862C0017; Tue, 15 Jul 2025 08:33:35 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp4.osuosl.org (smtp4.osuosl.org [IPv6:2605:bc80:3010::137]) by lists.linuxfoundation.org (Postfix) with ESMTP id 37269C0017 for ; Tue, 15 Jul 2025 08:33:34 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp4.osuosl.org (Postfix) with ESMTP id 2702340F6C for ; Tue, 15 Jul 2025 08:33:34 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp4.osuosl.org ([127.0.0.1]) by localhost (smtp4.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id pG9fVpYMV5xX for ; Tue, 15 Jul 2025 08:33:33 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2607:f8b0:4864:20::72d; helo=mail-qk1-x72d.google.com; envelope-from=changliang.wu@smartx.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp4.osuosl.org BB00A40CC1 Authentication-Results: smtp4.osuosl.org; dmarc=pass (p=none dis=none) header.from=smartx.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp4.osuosl.org BB00A40CC1 Received: from mail-qk1-x72d.google.com (mail-qk1-x72d.google.com [IPv6:2607:f8b0:4864:20::72d]) by smtp4.osuosl.org (Postfix) with ESMTPS id BB00A40CC1 for ; Tue, 15 Jul 2025 08:33:32 +0000 (UTC) Received: by mail-qk1-x72d.google.com with SMTP id af79cd13be357-7d3f5796755so454201385a.1 for ; Tue, 15 Jul 2025 01:33:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1752568411; x=1753173211; darn=openvswitch.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=E5K9z0yKf9GT1yjaF3IdKfiJnMu0KKVclN+DWSqiho4=; b=sWiTYkbCx9YzfltP5tgvU4yG3OiQ9gzpdF3VTQIs8UOHkkrcOmWJ0izRb8WfLo7bML z1HawWiR8EOrUB5dFNnCg8aBXUJKgvsncb+39vLvu8a/lzIJWitcHV2MF+5Jk+i31Qvw hRPlY4TVoGNd6sIxbqcQi7er+b2fDOonMW43Ay0MqiJ17Y1F5ryAEGndH2ub6BM7v1OM 5GNcdYo46MDLMK1r+aDRfpdqvLbHrqe7kZu7p/2MwlyOn58xRsedOj8puzk3sW9b7U9r FZuUFiMEbnIr40SnbfGKL8M9AiLLFxgq0qG3MejdcYw4K0yY5DhCsf69M7+2KcfGqfsY 4aBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752568411; x=1753173211; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=E5K9z0yKf9GT1yjaF3IdKfiJnMu0KKVclN+DWSqiho4=; b=DuEFoFmfEUJu2EHe3e5z/EjPB1IsIwsd/qgFeurdPQq+atBs7gl4sX+JwR8zVy/wHY M7E10/xZKrDlSiTcEl4ZzARpUXTXpiUHR1PvKyf3OKs2LqFXq+FQABl7JibxzOg70AdA wXOEWy16+w4ec/0as+LlYLwaT3lWBvoORoFhv4nD9yzJvajIBt5xxISsivzfcl0OOTe4 jwvp51tVJmiUG0miNKV/NCVf/zXqvGvNSPmh1mQr2De+PzuDDWzK5A+f6QT75m+7ySOf OSn3Sl0CMrlPFAQf7pQC24mivuwLRrKKsNUNMf8bYNfWpoPmp5H0QtkBWFmQy4nlRyO6 j/Lw== X-Forwarded-Encrypted: i=1; AJvYcCVBySQzTuQMe+gNpy4mI58Kpf/HCv9vtxX8fHzKB9aG4ZQzv80mH9sHARs1oDGt6NAdPi4=@openvswitch.org X-Gm-Message-State: AOJu0Yx4LHwPVGgjazy34X6vXQ+shXrc2Jk719MWdTiFOp3lBeGLSmv5 cQ6lXkMV4W7aP1E/zvrg3Ivvgep8nmMBfKj5bTvOLt+aD8TwCXW6dLNVw1Jual1K8HcB9WsqJZv pURWzpsxa/g== X-Gm-Gg: ASbGncuqogY0l+retm1LjdFd4JWpAgNMaBK+mf/RtOBU2L50ecPLRf13OADS+TwwieI dD/RUO/4OLtkr7fG/m9mruHQenBKHJzKM7A7tcgeCGUoJkQTnUowzLxLb10F3ezgARysUs1sQDC euhw1ieKCIZsToFgbnXjWM1It/wRZAbp9s0gqMIAXHB3ngE//SwqMnws4WkI/SUeezM86KT2GzO 64s6a05opQhaw3ohErRMHOJtkzP6B3lWzW3U9BX504yVTm73VuSU+ljtiC67wby7iUOnT3GKTem Fb6f4B8SnhFGyk+IJHm8ljEi+03ucE6DPNEHqxmKcL3zySFNG/qD5S9ejq0qGVkJr30M408d67/ oOTQVwY7wJEQdustYM1wE4/MGWufkzxldqMKbRgrx X-Google-Smtp-Source: AGHT+IELX51XjKOyW83EYcau3oz+iS5KU0uwua1lubeyOCCtdKztkKRIO4YWIubi/IpCDNq/VhAJvw== X-Received: by 2002:a05:620a:2710:b0:7d0:9e4a:e42f with SMTP id af79cd13be357-7deca0ff256mr2353243385a.43.1752568411060; Tue, 15 Jul 2025 01:33:31 -0700 (PDT) Received: from localhost.localdomain ([45.8.186.102]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e32b48248csm187481585a.88.2025.07.15.01.33.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 15 Jul 2025 01:33:30 -0700 (PDT) From: Changliang Wu To: aconole@redhat.com, echaudro@redhat.com, i.maximets@ovn.org, dev@openvswitch.org Date: Tue, 15 Jul 2025 16:33:18 +0800 Message-ID: <20250715083320.3747342-2-changliang.wu@smartx.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250715083320.3747342-1-changliang.wu@smartx.com> References: <20250715083320.3747342-1-changliang.wu@smartx.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH v9 1/3] lldp: Add ovs-appctl lldp/neighbor command. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" New appctl 'lldp/neighbor' displays lldp neighbor information. Support json output with --format json --pretty Signed-off-by: Changliang Wu --- NEWS | 1 + lib/ovs-lldp.c | 362 +++++++++++++++++++++++++++++++++++++ vswitchd/ovs-vswitchd.8.in | 4 + 3 files changed, 367 insertions(+) diff --git a/NEWS b/NEWS index c7bb53f2d..931fe5c71 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,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 infomation. - 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 152777248..2f3f6046a 100644 --- a/lib/ovs-lldp.c +++ b/lib/ovs-lldp.c @@ -36,7 +36,10 @@ #include #include "openvswitch/dynamic-string.h" #include "flow.h" +#include "openvswitch/json.h" #include "openvswitch/list.h" +#include "lldp/lldp-const.h" +#include "lldp/lldp-tlv.h" #include "lldp/lldpd.h" #include "lldp/lldpd-structs.h" #include "netdev.h" @@ -310,6 +313,321 @@ aa_print_isid_status(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex) } } +static void +lldp_print_neighbor(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex) +{ + const char *none_str = ""; + struct lldpd_hardware *hw; + struct lldpd_port *port; + + if (!lldp->lldpd) { + return; + } + + bool is_first_interface = true; + LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware) { + if (!hw->h_rports.next) { + continue; + } + LIST_FOR_EACH (port, p_entries, &hw->h_rports) { + struct ds chassis_id = DS_EMPTY_INITIALIZER; + if (!port->p_chassis) { + continue; + } + if (is_first_interface) { + is_first_interface = false; + } else { + ds_put_format(ds, "\n"); + } + ds_put_format(ds, "Interface: %s\n", lldp->name); + ds_put_format(ds, " Chassis:\n"); + + if (port->p_chassis->c_id_len > 0) { + ds_put_hex_with_delimiter(&chassis_id, port->p_chassis->c_id, + port->p_chassis->c_id_len, ":"); + } + ds_put_format(ds, " %-20s%s\n", "Chassis ID:", + chassis_id.length ? ds_cstr_ro(&chassis_id) + : none_str); + ds_put_format(ds, " %-20s%s\n", "SysName:", + strlen(port->p_chassis->c_name) + ? port->p_chassis->c_name + : none_str); + ds_put_format(ds, " %-20s%s\n", "SysDescr:", + strlen(port->p_chassis->c_descr) + ? port->p_chassis->c_descr + : none_str); + ds_destroy(&chassis_id); + + struct lldpd_mgmt *mgmt; + LIST_FOR_EACH (mgmt, m_entries, &port->p_chassis->c_mgmt) { + struct in6_addr ip; + 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, " %-20s", "MgmtIP:"); + ipv6_format_mapped(&ip, ds); + ds_put_format(ds, "\n"); + ds_put_format(ds, " %-20s%d\n", + "MgmtIface:", mgmt->m_iface); + } + + if (port->p_chassis->c_cap_available & LLDP_CAP_BRIDGE) { + ds_put_format(ds, " %-20sBridge, %s\n","Capability:", + 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, " %-20sRouter, %s\n","Capability:", + 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, " %-20sWlan, %s\n","Capability:", + 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, " %-20sStation, %s\n","Capability:", + port->p_chassis->c_cap_enabled & LLDP_CAP_STATION + ? "on" + : "off"); + } + + ds_put_format(ds, " Port:\n"); + + if (port->p_id_subtype == LLDP_PORTID_SUBTYPE_LLADDR) { + struct ds lladdr = DS_EMPTY_INITIALIZER; + if (port->p_id_len > 0) { + ds_put_hex_with_delimiter(&lladdr, (uint8_t *) port->p_id, + port->p_id_len, ":"); + } + ds_put_format(ds, " %-20s%s\n", "PortID:", + lladdr.length ? ds_cstr_ro(&lladdr) : none_str); + ds_destroy(&lladdr); + } else { + ds_put_format(ds, " %-20s%.*s\n", "PortID:", + (int) (port->p_id ? port->p_id_len + : strlen(none_str)), + port->p_id ?: none_str); + } + ds_put_format(ds, " %-20s%s\n", "PortDescr:", + strlen(port->p_descr) ? port->p_descr : none_str); + ds_put_format(ds, " %-20s%d\n", "TTL:", port->p_chassis->c_ttl); + } + } +} + +static void +lldp_print_neighbor_json(struct json *interface_json, struct lldp *lldp) + OVS_REQUIRES(mutex) +{ + const char *none_str = ""; + struct lldpd_hardware *hw; + struct lldpd_port *port; + + if (!lldp->lldpd) { + return; + } + + struct json *interface_item_warp_json_last = NULL; + struct json *interface_array_json = NULL; + bool has_multi_interfaces = false; + + LIST_FOR_EACH (hw, h_entries, &lldp->lldpd->g_hardware) { + if (!hw->h_rports.next) { + continue; + } + LIST_FOR_EACH (port, p_entries, &hw->h_rports) { + struct ds chassis_id = DS_EMPTY_INITIALIZER; + if (!port->p_chassis) { + continue; + } + + struct json *interface_item_warp_json = json_object_create(); + struct json *interface_item_json = json_object_create(); + 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(); + + if (port->p_chassis->c_id_len > 0) { + ds_put_hex_with_delimiter(&chassis_id, port->p_chassis->c_id, + port->p_chassis->c_id_len, ":"); + } + + json_object_put(chassis_id_json, "type", + json_string_create("mac")); + json_object_put(chassis_id_json, "value", + json_string_create(chassis_id.length + ? ds_cstr_ro(&chassis_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)); + ds_destroy(&chassis_id); + + struct lldpd_mgmt *mgmt; + LIST_FOR_EACH (mgmt, m_entries, &port->p_chassis->c_mgmt) { + char addr_str[INET6_ADDRSTRLEN]; + struct in6_addr ip; + 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) { + struct ds lladdr = DS_EMPTY_INITIALIZER; + if (port->p_id_len > 0) { + ds_put_hex_with_delimiter(&lladdr, port->p_id, + port->p_id_len, ":"); + } + json_object_put(port_id_json, "type", + json_string_create("mac")); + json_object_put(port_id_json, "value", + json_string_create(lladdr.length + ? ds_cstr_ro(&lladdr) + : none_str)); + ds_destroy(&lladdr); + } else { + json_object_put(port_id_json, "type", + json_string_create("ifname")); + if (port->p_id) { + struct ds port_ds = DS_EMPTY_INITIALIZER; + ds_put_buffer(&port_ds, port->p_id, port->p_id_len); + json_object_put(port_id_json, "value", + json_string_create(ds_cstr_ro(&port_ds))); + ds_destroy(&port_ds); + } else { + json_object_put(port_id_json, "value", + json_string_create(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)); + + json_object_put(interface_item_json, "chassis", chassis_json); + json_object_put(interface_item_json, "port", port_json); + + json_object_put(interface_item_warp_json, lldp->name, + interface_item_json); + + if (has_multi_interfaces) { + if (!interface_array_json) { + interface_array_json = json_array_create_empty(); + json_array_add(interface_array_json, + interface_item_warp_json_last); + } + json_array_add(interface_array_json, interface_item_warp_json); + } else { + has_multi_interfaces = true; + interface_item_warp_json_last = interface_item_warp_json; + } + } + } + if (interface_array_json || interface_item_warp_json_last) { + json_object_put(interface_json, "interface", + interface_array_json == NULL + ? interface_item_warp_json_last + : interface_array_json); + } +} + static void aa_unixctl_status(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) @@ -368,6 +686,48 @@ 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(); + + 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_json, lldp); + } + ovs_mutex_unlock(&mutex); + + 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, "LLDP neighbor:\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. */ @@ -635,6 +995,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..51b0a46b5 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 neighbors on \fIinterface\fR. +If \fIinterface\fR is not specified, then it displays detailed information +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 From patchwork Tue Jul 15 08:33:19 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changliang Wu X-Patchwork-Id: 2111437 X-Patchwork-Delegate: aconole@redhat.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=smartx-com.20230601.gappssmtp.com header.i=@smartx-com.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=ntvDErDp; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::138; helo=smtp1.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp1.osuosl.org (smtp1.osuosl.org [IPv6:2605:bc80:3010::138]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4bhCBk67lGz1xrM for ; Tue, 15 Jul 2025 18:33:34 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp1.osuosl.org (Postfix) with ESMTP id 24E1B83A4F; Tue, 15 Jul 2025 08:33:44 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp1.osuosl.org ([127.0.0.1]) by localhost (smtp1.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id u_qmSp60N1RY; Tue, 15 Jul 2025 08:33:42 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=2605:bc80:3010:104::8cd3:938; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp1.osuosl.org 6AAD18123C Authentication-Results: smtp1.osuosl.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=smartx-com.20230601.gappssmtp.com header.i=@smartx-com.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=ntvDErDp Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp1.osuosl.org (Postfix) with ESMTPS id 6AAD18123C; Tue, 15 Jul 2025 08:33:42 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4632DC0017; Tue, 15 Jul 2025 08:33:42 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 0D429C0016 for ; Tue, 15 Jul 2025 08:33:40 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 98254614B1 for ; Tue, 15 Jul 2025 08:33:38 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id yZsNRyac8uR8 for ; Tue, 15 Jul 2025 08:33:36 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2607:f8b0:4864:20::f2f; helo=mail-qv1-xf2f.google.com; envelope-from=changliang.wu@smartx.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org E230E6106E Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=smartx.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org E230E6106E Authentication-Results: smtp3.osuosl.org; dkim=pass (2048-bit key) header.d=smartx-com.20230601.gappssmtp.com header.i=@smartx-com.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=ntvDErDp Received: from mail-qv1-xf2f.google.com (mail-qv1-xf2f.google.com [IPv6:2607:f8b0:4864:20::f2f]) by smtp3.osuosl.org (Postfix) with ESMTPS id E230E6106E for ; Tue, 15 Jul 2025 08:33:35 +0000 (UTC) Received: by mail-qv1-xf2f.google.com with SMTP id 6a1803df08f44-6fabb948e5aso60665156d6.1 for ; Tue, 15 Jul 2025 01:33:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1752568414; x=1753173214; darn=openvswitch.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=PQyjARFFgJ2S6PAea6R5Blo0m6B1wARmiV0XZe1jlGI=; b=ntvDErDpjyJ6qz21Vu0l6Yf69eiQkTJzWonySQQRnNZn80rLwaPmxTzDkie52jJr0H 4NzS4RkcIKeJXlRp25mShtvMcGdFZsZsISxg51aAXeBIsALFY2hRF1bOJcbdI/bnrCTc EE09jztg/JLqK39inYz01r91WA4dBVDhvIEyX09kfeKhcEXa73lym1EGui6H6xzJTWXe mo/vgAth56AxgGDCKcvWyMTPrrm2sKKJ1kctcE0qRlzntDy1EzUO6RwwVcWgg+r6UPYE uHs2lA2GGLnEee1DG9akEXLUdoK3Rzpss9GRR5Om2CTWL6AYcuClN0w4ohatSyjl3mPt 7BzA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752568414; x=1753173214; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=PQyjARFFgJ2S6PAea6R5Blo0m6B1wARmiV0XZe1jlGI=; b=cXVzsAMkygGrg7EyeeW+GnY89rnBxsjeQ1neYS8s7cs72newKaawiIU8BVDUqohvRZ 64pHY4P1LPLOFg13ENuEULxQ0kFYlRlt9dggsZ7CUsf3/lBsy8rV5r09nALlfi/rSBre aHZwfybAKjYNiocp94yuyfrQb4SdJ8n3Tgk8xXja6NMJIKee7QM8dcHjaXPeXLNOs2ll swyu/xcFDfrtD8mKpvcUPdsI0x6U8x5c2f810q8nDZTCSE4r5CqV7QK8szB6OCxY2fdC aZ+rTU2a3DUrBROpNo9tQkaeRWwTpqVOnReoxARMPPHHZ1pd/Qc+ajh8UquQqwDh3Qbt yQnA== X-Forwarded-Encrypted: i=1; AJvYcCXHXjUpMcyTDrm10GG8b4WTvOYRZcOUCxvM544mSKbb8HKR+TcPBuZXuz0T5BqjuBja6Vw=@openvswitch.org X-Gm-Message-State: AOJu0Yw5GevDmdDtKZyNoVWRr+bJezzepXTQ/+ujtD83qBs8aDsqmalX pIXvvy+iMLHkoF1R9+GoZVC/wGFV/A/vb+H8zrnhILyxUSkpEa/8rSDpg3J69zNUDCA5vzo+5Mf bUw8BPLlkFg== X-Gm-Gg: ASbGncs0JnIN27fi/Y0PZApUOdP1xRvUtNDE6QqfpFdYGN0BzYfQq5a2NGKuvC1BOcN Xwk3wdWCAErJfWQ7gGCfSenDsVu48ffxnYnYndBKM+QVxTsh45DCi+fIc5xcZjpNrOrQwF0Nd0Z ktc229eU8uV/CY9JRWelC6ImDpImnOzjZtNVlvHN4QQdpJNRdCC+CIiKngK9lHxXrmgQ9J50Z3T CmhCKKuYm1HD6oa0pcAb9eD78BS5AilPlUZgn66rS1d9ZSDN5XGnuJ4Fu8L0UPTZuSGSuIHMq8H pnARXPBmiwkaYQA1tc20ozDujb0B97kAOmNTDUuUwgENQnvY1Y+unyFfB2GqgyHKOktso8pA8DB SoLm7jB10RICSPqMkhRMvjHLcAN9nveZ0wSr0IeIT X-Google-Smtp-Source: AGHT+IGUMv+n1NKKM9/gqLkzSVwZBf1EyvDeeQumptcj25u6QUI9TnkoSnobfMgFFjMtdLR4qT7bWg== X-Received: by 2002:a05:6214:4105:b0:6fa:c6e6:11f9 with SMTP id 6a1803df08f44-704a408117cmr240166426d6.11.1752568413909; Tue, 15 Jul 2025 01:33:33 -0700 (PDT) Received: from localhost.localdomain ([45.8.186.102]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e32b48248csm187481585a.88.2025.07.15.01.33.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 15 Jul 2025 01:33:33 -0700 (PDT) From: Changliang Wu To: aconole@redhat.com, echaudro@redhat.com, i.maximets@ovn.org, dev@openvswitch.org Date: Tue, 15 Jul 2025 16:33:19 +0800 Message-ID: <20250715083320.3747342-3-changliang.wu@smartx.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250715083320.3747342-1-changliang.wu@smartx.com> References: <20250715083320.3747342-1-changliang.wu@smartx.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH v9 2/3] lldp: Decode dot1, 3 tlv and display in lldp/neighbor. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" The 802.1 and 802.3 standards list ways for communicating important PoE, Maximum Frame Size, and other important link-level features that peers may want to look at. This commit provides a port of the LLDPD project's protocol decode for 802.1 and 802.3 TLVs of interest, preserving the implementation as closely as possible to the source materials. The supported decodes will allow decoding and displaying: * IEEE 802.1-2005 (Port VLAN and Protocol Configuration) * IEEE 802.3at (Power over Ethernet plus) * IEEE 802.3bt (4-pair PoE) The commit supports displaying this data in human readable and json formats. Signed-off-by: Changliang Wu --- NEWS | 2 + lib/lldp/lldp-const.h | 5 + lib/lldp/lldp.c | 164 +++++++++++++++++++- lib/lldp/lldpd-structs.c | 31 ++++ lib/lldp/lldpd-structs.h | 69 +++++++++ lib/ovs-lldp.c | 316 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 585 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 931fe5c71..d46f78743 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,8 @@ 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. + - lldp: + * Added support for decoding 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..e03c77f71 100644 --- a/lib/lldp/lldp-const.h +++ b/lib/lldp/lldp-const.h @@ -98,6 +98,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/lib/lldp/lldp.c b/lib/lldp/lldp.c index 6fdcfef56..c10bb27d9 100644 --- a/lib/lldp/lldp.c +++ b/lib/lldp/lldp.c @@ -18,6 +18,8 @@ */ #include +#include "lldp-const.h" +#include "lldp-tlv.h" #include "lldpd.h" #include #include @@ -372,6 +374,12 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, void *b; struct lldpd_aa_isid_vlan_maps_tlv *isid_vlan_map = NULL; u_int8_t msg_auth_digest[LLDP_TLV_AA_ISID_VLAN_DIGEST_LENGTH]; + + struct lldpd_vlan *vlan = NULL; + int vlan_len; + struct lldpd_ppvid *ppvid; + struct lldpd_pi *pi = NULL; + struct lldpd_mgmt *mgmt; u_int8_t addr_str_length, addr_str_buffer[32]; u_int8_t addr_family, addr_length, *addr_ptr, iface_subtype; @@ -384,6 +392,9 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, port = xzalloc(sizeof *port); ovs_list_init(&port->p_isid_vlan_maps); + ovs_list_init(&port->p_vlans); + ovs_list_init(&port->p_ppvids); + ovs_list_init(&port->p_pids); length = s; pos = (u_int8_t*) frame; @@ -568,9 +579,158 @@ lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s, PEEK_BYTES(orgid, sizeof orgid); tlv_subtype = PEEK_UINT8; if (memcmp(dot1, orgid, sizeof orgid) == 0) { - hardware->h_rx_unrecognized_cnt++; + switch (tlv_subtype) { + case LLDP_TLV_DOT1_VLANNAME: + CHECK_TLV_SIZE(7, "VLAN"); + vlan = xzalloc(sizeof *vlan); + vlan->v_vid = PEEK_UINT16; + vlan_len = PEEK_UINT8; + CHECK_TLV_SIZE(7 + vlan_len, "VLAN"); + vlan->v_name = xzalloc(vlan_len + 1); + PEEK_BYTES(vlan->v_name, vlan_len); + ovs_list_push_back(&port->p_vlans, &vlan->v_entries); + vlan = NULL; + break; + + case LLDP_TLV_DOT1_PVID: + CHECK_TLV_SIZE(6, "PVID"); + port->p_pvid = PEEK_UINT16; + break; + + case LLDP_TLV_DOT1_PPVID: + CHECK_TLV_SIZE(7, "PPVID"); + /* validation needed */ + /* PPVID has to be unique if more than + one PPVID TLVs are received - + discard if duplicate */ + /* if support bit is not set and + enabled bit is set - PPVID TLV is + considered error and discarded */ + /* if PPVID > 4096 - bad and discard */ + ppvid = xzalloc(sizeof *ppvid); + ppvid->p_cap_status = PEEK_UINT8; + ppvid->p_ppvid = PEEK_UINT16; + ovs_list_push_back(&port->p_ppvids, &ppvid->p_entries); + break; + + case LLDP_TLV_DOT1_PI: + /* validation needed */ + /* PI has to be unique if more than + one PI TLVs are received - discard + if duplicate ?? */ + pi = xzalloc(sizeof *pi); + pi->p_pi_len = PEEK_UINT8; + CHECK_TLV_SIZE(5 + pi->p_pi_len, "PI"); + pi->p_pi = xzalloc(pi->p_pi_len); + PEEK_BYTES(pi->p_pi, pi->p_pi_len); + ovs_list_push_back(&port->p_pids, &pi->p_entries); + pi = NULL; + 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(9, "MAC/PHY"); + port->p_macphy.autoneg_support = PEEK_UINT8; + port->p_macphy.autoneg_enabled = + (port->p_macphy.autoneg_support & 0x2) >> 1; + port->p_macphy.autoneg_support = + port->p_macphy.autoneg_support & 0x1; + port->p_macphy.autoneg_advertised = PEEK_UINT16; + port->p_macphy.mau_type = PEEK_UINT16; + break; + + case LLDP_TLV_DOT3_LA: + CHECK_TLV_SIZE(9, "Link aggregation"); + PEEK_DISCARD_UINT8; + port->p_aggregid = PEEK_UINT32; + break; + + case LLDP_TLV_DOT3_MFS: + CHECK_TLV_SIZE(6, "MFS"); + port->p_mfs = PEEK_UINT16; + break; + + case LLDP_TLV_DOT3_POWER: + CHECK_TLV_SIZE(7, "Power"); + port->p_power.devicetype = PEEK_UINT8; + port->p_power.supported = + (port->p_power.devicetype & 0x2) >> 1; + port->p_power.enabled = (port->p_power.devicetype & 0x4) >> + 2; + port->p_power.paircontrol = + (port->p_power.devicetype & 0x8) >> 3; + port->p_power.devicetype = (port->p_power.devicetype & 0x1) + ? LLDP_DOT3_POWER_PSE + : LLDP_DOT3_POWER_PD; + port->p_power.pairs = PEEK_UINT8; + port->p_power.class = PEEK_UINT8; + /* 802.3at? */ + if (tlv_size >= 12) { + port->p_power.powertype = PEEK_UINT8; + port->p_power.source = + (port->p_power.powertype & (1 << 5 | 1 << 4)) >> 4; + port->p_power.priority = + (port->p_power.powertype & (1 << 1 | 1 << 0)); + port->p_power.powertype = + (port->p_power.powertype & (1 << 7)) + ? LLDP_DOT3_POWER_8023AT_TYPE1 + : LLDP_DOT3_POWER_8023AT_TYPE2; + port->p_power.requested = PEEK_UINT16; + port->p_power.allocated = PEEK_UINT16; + } 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: + 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.c b/lib/lldp/lldpd-structs.c index a8c7fad09..9e1215293 100644 --- a/lib/lldp/lldpd-structs.c +++ b/lib/lldp/lldpd-structs.c @@ -113,6 +113,35 @@ lldpd_aa_maps_cleanup(struct lldpd_port *port) } } +static void +lldpd_dot13_lists_cleanup(struct lldpd_port *port) +{ + struct lldpd_vlan *vlan; + struct lldpd_ppvid *ppvid; + struct lldpd_pi *pid; + if (port->p_vlans.next && !ovs_list_is_empty(&port->p_vlans)) { + LIST_FOR_EACH_SAFE (vlan, v_entries, &port->p_vlans) { + ovs_list_remove(&vlan->v_entries); + free(vlan); + } + ovs_list_init(&port->p_vlans); + } + if (port->p_ppvids.next && !ovs_list_is_empty(&port->p_ppvids)) { + LIST_FOR_EACH_SAFE (ppvid, p_entries, &port->p_ppvids) { + ovs_list_remove(&ppvid->p_entries); + free(ppvid); + } + ovs_list_init(&port->p_ppvids); + } + if (port->p_pids.next && !ovs_list_is_empty(&port->p_pids)) { + LIST_FOR_EACH_SAFE (pid, p_entries, &port->p_pids) { + ovs_list_remove(&pid->p_entries); + free(pid); + } + ovs_list_init(&port->p_pids); + } +} + /* If `all' is true, clear all information, including information that are not refreshed periodically. Port should be freed manually. */ void @@ -127,6 +156,8 @@ lldpd_port_cleanup(struct lldpd_port *port, bool all) /* Cleanup auto-attach mappings */ lldpd_aa_maps_cleanup(port); + lldpd_dot13_lists_cleanup(port); + if (all) { free(port->p_lastframe); /* Chassis may not have been attributed, yet.*/ diff --git a/lib/lldp/lldpd-structs.h b/lib/lldp/lldpd-structs.h index fe5d5f9f8..1ec7fe777 100644 --- a/lib/lldp/lldpd-structs.h +++ b/lib/lldp/lldpd-structs.h @@ -45,6 +45,63 @@ lldpd_af(int af) } } +struct lldpd_ppvid { + struct ovs_list p_entries; + u_int8_t p_cap_status; + u_int16_t p_ppvid; +}; + +struct lldpd_vlan { + struct ovs_list v_entries; + char *v_name; + u_int16_t v_vid; +}; + +struct lldpd_pi { + struct ovs_list p_entries; + char *p_pi; + int p_pi_len; +}; + +struct lldpd_dot3_macphy { + u_int8_t autoneg_support; + u_int8_t autoneg_enabled; + u_int16_t autoneg_advertised; + u_int16_t mau_type; +}; + +struct lldpd_dot3_power { + u_int8_t devicetype; + u_int8_t supported; + u_int8_t enabled; + u_int8_t paircontrol; + u_int8_t pairs; + u_int8_t class; + u_int8_t powertype; /* If set to LLDP_DOT3_POWER_8023AT_OFF, + following fields have no meaning */ + u_int8_t source; + 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; +}; + + #define LLDPD_MGMT_MAXADDRSIZE 16 /* sizeof(struct in6_addr) */ struct lldpd_mgmt { struct ovs_list m_entries; @@ -98,6 +155,18 @@ struct lldpd_port { char *p_descr; u_int16_t p_mfs; struct lldpd_aa_element_tlv p_element; + + /* Dot3 stuff */ + u_int32_t p_aggregid; + struct lldpd_dot3_macphy p_macphy; + struct lldpd_dot3_power p_power; + + /* Dot1 stuff */ + u_int16_t p_pvid; + struct ovs_list p_vlans; /* Contains "struct lldpd_vlan"s. */ + struct ovs_list p_ppvids; /* Contains "struct lldpd_ppvid"s. */ + struct ovs_list p_pids; /* Contains "struct lldpd_pi"s. */ + 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 2f3f6046a..ff153fc7e 100644 --- a/lib/ovs-lldp.c +++ b/lib/ovs-lldp.c @@ -313,6 +313,316 @@ 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) +{ + struct lldpd_vlan *vlan; + struct lldpd_ppvid *ppvid; + struct lldpd_pi *pid; + + LIST_FOR_EACH (vlan, v_entries, &port->p_vlans) { + ds_put_format(ds, " %-20s%d, %s", "VLAN:", vlan->v_vid, + port->p_pvid == vlan->v_vid ? "pvid: yes" : "pvid: no"); + if (vlan->v_name) { + ds_put_format(ds, ", %s", vlan->v_name); + } + ds_put_format(ds, "\n"); + } + + LIST_FOR_EACH (ppvid, p_entries, &port->p_ppvids) { + ds_put_format(ds, " %-20s", "PPVID:"); + if (ppvid->p_ppvid) { + ds_put_format(ds, ", %d ", ppvid->p_ppvid); + } + ds_put_format( + ds, "supported: %s,enabled %s\n", + (ppvid->p_cap_status & LLDP_PPVID_CAP_SUPPORTED) ? "yes" : "no", + (ppvid->p_cap_status & LLDP_PPVID_CAP_ENABLED) ? "yes" : "no"); + } + + LIST_FOR_EACH (pid, p_entries, &port->p_pids) { + if (pid->p_pi && pid->p_pi_len > 0) { + ds_put_format(ds, " %-20s", "PI:"); + ds_put_buffer(ds, pid->p_pi, pid->p_pi_len); + 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_array = NULL; + struct json *vlan_json = NULL; + struct json *ppvid_json_array = NULL; + struct json *ppvid_json = NULL; + struct json *pi_json_array = NULL; + struct json *pi_json = NULL; + + struct lldpd_vlan *vlan; + struct lldpd_ppvid *ppvid; + struct lldpd_pi *pid; + + LIST_FOR_EACH (vlan, v_entries, &port->p_vlans) { + vlan_json = json_object_create(); + json_object_put(vlan_json, "vlan-id", + json_integer_create(vlan->v_vid)); + json_object_put(vlan_json, "pvid", + json_boolean_create(port->p_pvid == vlan->v_vid)); + if (vlan->v_name) { + json_object_put(vlan_json, "value", + json_string_create(vlan->v_name)); + } + if (ovs_list_size(&port->p_vlans) > 1) { + if (vlan_json_array == NULL) { + vlan_json_array = json_array_create_empty(); + } + json_array_add(vlan_json_array, vlan_json); + } + } + if (vlan_json_array || vlan_json) { + json_object_put(interface_item_json, "vlan", + vlan_json_array ? vlan_json_array : vlan_json); + } + + LIST_FOR_EACH (ppvid, p_entries, &port->p_ppvids) { + ppvid_json = json_object_create(); + if (ppvid->p_ppvid) { + json_object_put(ppvid_json, "ppvid", + json_integer_create(ppvid->p_ppvid)); + } + json_object_put(ppvid_json, "supported", + json_boolean_create(ppvid->p_cap_status & + LLDP_PPVID_CAP_SUPPORTED)); + json_object_put(ppvid_json, "enabled", + json_boolean_create(ppvid->p_cap_status & + LLDP_PPVID_CAP_ENABLED)); + if (ovs_list_size(&port->p_ppvids) > 1) { + if (ppvid_json_array == NULL) { + ppvid_json_array = json_array_create_empty(); + } + json_array_add(ppvid_json_array, ppvid_json); + } + } + if (ppvid_json_array || ppvid_json) { + json_object_put(interface_item_json, "ppvid", + ppvid_json_array ? ppvid_json_array : ppvid_json); + } + + LIST_FOR_EACH (pid, p_entries, &port->p_pids) { + if (pid->p_pi && pid->p_pi_len > 0) { + pi_json = json_object_create(); + struct ds pi_ds = DS_EMPTY_INITIALIZER; + ds_put_buffer(&pi_ds, pid->p_pi, pid->p_pi_len); + json_object_put(ppvid_json, "ppvid", + json_string_create(ds_cstr_ro(&pi_ds))); + ds_destroy(&pi_ds); + if (ovs_list_size(&port->p_pids) > 1) { + if (pi_json_array == NULL) { + pi_json_array = json_array_create_empty(); + } + json_array_add(pi_json_array, pi_json); + } + } + } + if (pi_json_array || pi_json) { + json_object_put(interface_item_json, "pi", + pi_json_array ? pi_json_array : pi_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, " %-18s%s", "Adv:", 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_mfs) { + ds_put_format(ds, " %-20s%d\n", "MFS:", port->p_mfs); + } + + long int autoneg_support, autoneg_enabled, autoneg_advertised, mautype; + autoneg_support = port->p_macphy.autoneg_support; + autoneg_enabled = port->p_macphy.autoneg_enabled; + autoneg_advertised = port->p_macphy.autoneg_advertised; + mautype = port->p_macphy.mau_type; + if (autoneg_support > 0 || autoneg_enabled > 0 || mautype > 0) { + ds_put_format(ds, " PMD autoneg: supported: %s, enabled: %s\n", + autoneg_support ? "yes" : "no", + autoneg_enabled ? "yes" : "no"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_10BASE_T, + LLDP_DOT3_LINK_AUTONEG_10BASET_FD, + "10Base-T"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_100BASE_T4, + LLDP_DOT3_LINK_AUTONEG_100BASE_T4, + "100Base-T4"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_100BASE_TX, + LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD, + "100Base-TX"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_100BASE_T2, + LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD, + "100Base-T2"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_1000BASE_X, + LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD, + "1000Base-X"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_1000BASE_T, + LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD, + "1000Base-T"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE, + LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE, + "FDX_PAUSE"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE, + LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE, + "FDX_APAUSE"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE, + LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE, + "FDX_SPAUSE"); + lldp_dot3_autoneg_advertised(ds, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE, + LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE, + "FDX_BPAUSE"); + ds_put_format(ds, " %-18s%ld\n", "MAU oper type:", mautype); + } + + if (port->p_power.devicetype) { + ds_put_format(ds, + " MDI Power: supported: %s, enabled: %s, pair " + "control: %s\n", + port->p_power.supported ? "yes" : "no", + port->p_power.enabled ? "yes" : "no", + port->p_power.paircontrol ? "yes" : "no"); + } +} + +static void +lldp_print_neighbor_port_dot3_json(struct json *port_json, + struct lldpd_port *port) +{ + if (port->p_mfs) { + json_object_put(port_json, "mfs", json_integer_create(port->p_mfs)); + } + + long int autoneg_support, autoneg_enabled, autoneg_advertised, mautype; + autoneg_support = port->p_macphy.autoneg_support; + autoneg_enabled = port->p_macphy.autoneg_enabled; + autoneg_advertised = port->p_macphy.autoneg_advertised; + mautype = port->p_macphy.mau_type; + if (autoneg_support > 0 || autoneg_enabled > 0 || mautype > 0) { + struct json *auto_nego_json = json_object_create(); + json_object_put(auto_nego_json, "supported", + json_boolean_create(autoneg_support)); + json_object_put(auto_nego_json, "enabled", + json_boolean_create(autoneg_enabled)); + + struct json *advertised_json = NULL; + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_10BASE_T, + LLDP_DOT3_LINK_AUTONEG_10BASET_FD, + "10Base-T"); + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_100BASE_T4, + LLDP_DOT3_LINK_AUTONEG_100BASE_T4, + "100Base-T4"); + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_100BASE_TX, + LLDP_DOT3_LINK_AUTONEG_100BASE_TXFD, + "100Base-TX"); + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_100BASE_T2, + LLDP_DOT3_LINK_AUTONEG_100BASE_T2FD, + "100Base-T2"); + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_1000BASE_X, + LLDP_DOT3_LINK_AUTONEG_1000BASE_XFD, + "1000Base-X"); + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_1000BASE_T, + LLDP_DOT3_LINK_AUTONEG_1000BASE_TFD, + "1000Base-T"); + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE, + LLDP_DOT3_LINK_AUTONEG_FDX_PAUSE, + "FDX_PAUSE"); + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE, + LLDP_DOT3_LINK_AUTONEG_FDX_APAUSE, + "FDX_APAUSE"); + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE, + LLDP_DOT3_LINK_AUTONEG_FDX_SPAUSE, + "FDX_SPAUSE"); + lldp_dot3_autoneg_advertised_json(&advertised_json, autoneg_advertised, + LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE, + LLDP_DOT3_LINK_AUTONEG_FDX_BPAUSE, + "FDX_BPAUSE"); + json_object_put(auto_nego_json, "current", + json_integer_create(mautype)); + + json_object_put(port_json, "auto-negotiation", auto_nego_json); + } + + if (port->p_power.devicetype) { + struct json *power_json = json_object_create(); + + json_object_put(power_json, "supported", + json_boolean_create(port->p_power.supported)); + json_object_put(power_json, "enabled", + json_boolean_create(port->p_power.enabled)); + json_object_put(power_json, "paircontrol", + json_boolean_create(port->p_power.paircontrol)); + json_object_put(port_json, "power", power_json); + } +} + static void lldp_print_neighbor(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex) { @@ -426,6 +736,9 @@ lldp_print_neighbor(struct ds *ds, struct lldp *lldp) OVS_REQUIRES(mutex) ds_put_format(ds, " %-20s%s\n", "PortDescr:", strlen(port->p_descr) ? port->p_descr : none_str); ds_put_format(ds, " %-20s%d\n", "TTL:", port->p_chassis->c_ttl); + + lldp_print_neighbor_port_dot3(ds, port); + lldp_print_neighbor_port_dot1(ds, port); } } } @@ -601,6 +914,9 @@ lldp_print_neighbor_json(struct json *interface_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); From patchwork Tue Jul 15 08:33:20 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Changliang Wu X-Patchwork-Id: 2111438 X-Patchwork-Delegate: aconole@redhat.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=smartx-com.20230601.gappssmtp.com header.i=@smartx-com.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=K9qniYcR; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::133; helo=smtp2.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=patchwork.ozlabs.org) Received: from smtp2.osuosl.org (smtp2.osuosl.org [IPv6:2605:bc80:3010::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4bhCBv57wSz1xrM for ; Tue, 15 Jul 2025 18:33:43 +1000 (AEST) Received: from localhost (localhost [127.0.0.1]) by smtp2.osuosl.org (Postfix) with ESMTP id 0E88440E81; Tue, 15 Jul 2025 08:33:53 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp2.osuosl.org ([127.0.0.1]) by localhost (smtp2.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id N_5n2T1EtOcT; Tue, 15 Jul 2025 08:33:51 +0000 (UTC) X-Comment: SPF check N/A for local connections - client-ip=140.211.9.56; helo=lists.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver= DKIM-Filter: OpenDKIM Filter v2.11.0 smtp2.osuosl.org BDB7F40E7C Authentication-Results: smtp2.osuosl.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=smartx-com.20230601.gappssmtp.com header.i=@smartx-com.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=K9qniYcR Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [140.211.9.56]) by smtp2.osuosl.org (Postfix) with ESMTPS id BDB7F40E7C; Tue, 15 Jul 2025 08:33:51 +0000 (UTC) Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id A8F8BC0017; Tue, 15 Jul 2025 08:33:51 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id 1B04BC0017 for ; Tue, 15 Jul 2025 08:33:51 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 57565614B5 for ; Tue, 15 Jul 2025 08:33:41 +0000 (UTC) X-Virus-Scanned: amavis at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavis, port 10024) with ESMTP id jdwGe71besNU for ; Tue, 15 Jul 2025 08:33:40 +0000 (UTC) Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=2607:f8b0:4864:20::731; helo=mail-qk1-x731.google.com; envelope-from=changliang.wu@smartx.com; receiver= DMARC-Filter: OpenDMARC Filter v1.4.2 smtp3.osuosl.org B66266107A Authentication-Results: smtp3.osuosl.org; dmarc=pass (p=none dis=none) header.from=smartx.com DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org B66266107A Authentication-Results: smtp3.osuosl.org; dkim=pass (2048-bit key) header.d=smartx-com.20230601.gappssmtp.com header.i=@smartx-com.20230601.gappssmtp.com header.a=rsa-sha256 header.s=20230601 header.b=K9qniYcR Received: from mail-qk1-x731.google.com (mail-qk1-x731.google.com [IPv6:2607:f8b0:4864:20::731]) by smtp3.osuosl.org (Postfix) with ESMTPS id B66266107A for ; Tue, 15 Jul 2025 08:33:38 +0000 (UTC) Received: by mail-qk1-x731.google.com with SMTP id af79cd13be357-7e182e4171bso255839485a.3 for ; Tue, 15 Jul 2025 01:33:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=smartx-com.20230601.gappssmtp.com; s=20230601; t=1752568417; x=1753173217; darn=openvswitch.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=xQbELVg0L67uX8xX2/Q91dH+aUU+PmxSBr3kc4gOSQM=; b=K9qniYcRU+b5GGvFW1crVZfqBomrfe07lSxluMGy10T6Z8AZ46Fr0DjVcUcOjvwbPK wbOWJwCOwhn8xRUUHTKA0Bx51mItydMiLjFTQ7dgr1sbqfZqbneceA6tmcmwAVZFo3aW fB+YCYwaFzgbcskMK1BGbUAzT8lmp4QGZNPfx37j0Ajmc2fJvY2dLQzJE2wTkAPHmnU2 X0z9xAAVxjKNFQIHnGPOB9cQn9jtZrtKjy9nt28C2i3YdgEg2aFseNN8vTh7WNpwNyTr u+KWwlvn7TgoH+CJtzfCbtDmr6Z9tOp/lfhRD8RTIzJQfBle0hR6MmSeUehuLs+6ZJDN 2Ucw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752568417; x=1753173217; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=xQbELVg0L67uX8xX2/Q91dH+aUU+PmxSBr3kc4gOSQM=; b=crAJ7En5pzqLAhBBkljgp+nbLjQO8JJN9n/8cakSTR426GWgzgu0TB15pgmBjVI+Yq NIriUXfzA+xvhlMYvdWR5XLaTt8y5hXjZ2dk7i4ydTi7e3pphlexGP8YyyzA5C4zsZYx H3LmodWlS3pXV6Y3A4QO0ihXM8FWF1hb52+LBPcb89aIPX7GGScf3uMLdQnL6cKTbyvC g26R2Fpf5CmorOS/PUCi9DSQW4dfnRrL9hcip6ZSE6gbGWqUvG3Htx0ieNkJi1Ksv85W lNNKrI9pfQgBQ/SoPSYRido6Mhr1JFZWxx1xpgj41TYATU5EgoMsYoxrdYw4CSGcnp7r maYg== X-Forwarded-Encrypted: i=1; AJvYcCUoCOd9+ooNUSMARA9hG1QwU/We3xuCLDPL9Ko3v85EC5nV/wwI5sX1MOK57IUQYsJNOeg=@openvswitch.org X-Gm-Message-State: AOJu0YzmX2EiPaYdUFrd84oVKF5NqtBPJE824DjDoMaxq0F7m7Zgc1ip rwZz8KwlhNtpi2Z01RGNrlq1uhu4NhZu95H1h8/QyCu88E3iPKJAXaTLJRS+najO3nM= X-Gm-Gg: ASbGnctqX/bhwW/j+bA+nmxLgO87eU5Lelmp9z10gMek8uHGa28m+uondo4P5EahelL L5PzUldR1gUMISLVGNn8lPgQyg3DhIuhhjQGCvuhvDyaCKtTvZCQe8ljE6SJuDMvayBQIncG+Nn k7ZEWtkxvKyQ6iwa95mmmCxP80M3BbqCRqE82TA76wrGpKq2or65ubOmr6bb25E/L3bMpjWpbD8 aWC/7+OBFqnU0+5ZQ5L0+XLk2qhCcnM831z8a8j3t1tuRtwwYrny6GhA82XaD44j56OmDExKcsr Lq51o5k61VRBozN2es20s1OMoDPKPK/CP9euS0WpMb8f7bYF3u4x6zZmG25eYJTFjgdRDq356NS /UKtIy9s8ke8iKYolg4WFMF0y2nTRrd78Y6RH21ZQ X-Google-Smtp-Source: AGHT+IHZWy99AoXmvAFFBBPsFJSPKBoeWHmcqBeE5ns32BTPcAgw0qmTmt5QIjDhfZK9IvkUjnboFw== X-Received: by 2002:a05:620a:19a3:b0:7e3:3ce3:aa3b with SMTP id af79cd13be357-7e33ce3b278mr87531085a.47.1752568416671; Tue, 15 Jul 2025 01:33:36 -0700 (PDT) Received: from localhost.localdomain ([45.8.186.102]) by smtp.gmail.com with ESMTPSA id af79cd13be357-7e32b48248csm187481585a.88.2025.07.15.01.33.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 15 Jul 2025 01:33:36 -0700 (PDT) From: Changliang Wu To: aconole@redhat.com, echaudro@redhat.com, i.maximets@ovn.org, dev@openvswitch.org Date: Tue, 15 Jul 2025 16:33:20 +0800 Message-ID: <20250715083320.3747342-4-changliang.wu@smartx.com> X-Mailer: git-send-email 2.43.5 In-Reply-To: <20250715083320.3747342-1-changliang.wu@smartx.com> References: <20250715083320.3747342-1-changliang.wu@smartx.com> MIME-Version: 1.0 Subject: [ovs-dev] [PATCH v9 3/3] tests: lldp: Add testcases for lldp/neighbor. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" Signed-off-by: Changliang Wu --- tests/automake.mk | 1 + tests/ovs-lldp.at | 227 +++++++++++++++++++++++++++++++++++++++++++++ tests/testsuite.at | 1 + 3 files changed, 229 insertions(+) create mode 100644 tests/ovs-lldp.at diff --git a/tests/automake.mk b/tests/automake.mk index 59f538761..a453a0c4b 100644 --- a/tests/automake.mk +++ b/tests/automake.mk @@ -68,6 +68,7 @@ TESTSUITE_AT = \ tests/tunnel.at \ tests/tunnel-push-pop.at \ tests/tunnel-push-pop-ipv6.at \ + tests/ovs-lldp.at \ tests/ovs-router.at \ tests/lockfile.at \ tests/reconnect.at \ diff --git a/tests/ovs-lldp.at b/tests/ovs-lldp.at new file mode 100644 index 000000000..f39bf18d8 --- /dev/null +++ b/tests/ovs-lldp.at @@ -0,0 +1,227 @@ +AT_BANNER([ovs-lldp]) + +AT_SETUP([lldp - check lldp neighbor display]) + +OVS_VSWITCHD_START([]) + +add_of_ports br0 1 +AT_CHECK([ + ovs-vsctl set Interface p1 type=dummy lldp:enable=true +], [0]) + +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \ +'0180c200000e38a91c18a12688cc020704aaaaaaaaaaaa0416054769676162697445746865726e6574312f302f313506020079081f4769676162697445746865726e6574312f302f313520496e746572666163650a0e46616b6553797374656d4e616d650c0e46616b6553797374656d446573630e0403140114100c0501c0a80001020000027b00fe060080c2010001fe070080c202020000fe100080c203000109564c414e2030303031fe060080c2060000fe090080c2070100000000fe0900120f01036c01001efe0c00120f0203010113000000fffe0600120f042800fe0900120f0301000000000000']) + +AT_CHECK([ovs-appctl lldp/neighbor p1], [0], [dnl +LLDP neighbor: +Interface: p1 + Chassis: + Chassis ID: aa:aa:aa:aa:aa:aa + SysName: FakeSystemName + SysDescr: FakeSystemDesc + MgmtIP: 192.168.0.1 + MgmtIface: 635 + Capability: Bridge, on + Capability: Router, on + Port: + PortID: GigabitEthernet1/0/15 + PortDescr: GigabitEthernet1/0/15 Interface + TTL: 121 + MFS: 10240 + PMD autoneg: supported: yes, enabled: yes + Adv: 10Base-T, HD: yes, FD: yes + Adv: 100Base-TX, HD: yes, FD: yes + Adv: 1000Base-T, HD: no, FD: yes + MAU oper type: 30 + MDI Power: supported: yes, enabled: no, pair control: no + VLAN: 1, pvid: yes, VLAN 0001 + PPVID: supported: yes,enabled no +]) + +AT_CHECK([ovs-appctl --format json --pretty lldp/neighbor p1 ], [0], [dnl +[{ + "lldp": { + "interface": { + "p1": { + "chassis": { + "FakeSystemName": { + "capability": [ + { + "enabled": true, + "type": "Bridge"}, + { + "enabled": true, + "type": "Router"}], + "descr": "FakeSystemDesc", + "id": { + "type": "mac", + "value": "aa:aa:aa:aa:aa:aa"}, + "mgmt-iface": [ + 635], + "mgmt-ip": [ + "192.168.0.1"]}}, + "port": { + "auto-negotiation": { + "current": 30, + "enabled": true, + "supported": true}, + "desc": "GigabitEthernet1/0/15 Interface", + "id": { + "type": "ifname", + "value": "GigabitEthernet1/0/15"}, + "mfs": 10240, + "power": { + "enabled": false, + "paircontrol": false, + "supported": true}, + "ttl": 121}, + "ppvid": { + "enabled": false, + "supported": true}, + "vlan": { + "pvid": true, + "value": "VLAN 0001", + "vlan-id": 1}}}}}] +]) + +AT_CHECK([ovs-appctl netdev-dummy/receive p1 \ +'0180c200000e38a91c18a11c88cc020704aaaaaaaaaaaa0415054769676162697445746865726e6574312f302f3506020079081e4769676162697445746865726e6574312f302f3520496e746572666163650a0e46616b6553797374656d4e616d650c0e46616b6553797374656d446573630e0403140114100c0501c0a80001020000027b00fe060080c2010001fe070080c202020000fe100080c203000109564c414e2030303031fe060080c2060000fe090080c2070100000000fe0900120f01036c01001efe0c00120f0203010113000000fffe0600120f042800fe0900120f0301000000000000']) + +AT_CHECK([ovs-appctl lldp/neighbor p1], [0], [dnl +LLDP neighbor: +Interface: p1 + Chassis: + Chassis ID: aa:aa:aa:aa:aa:aa + SysName: FakeSystemName + SysDescr: FakeSystemDesc + MgmtIP: 192.168.0.1 + MgmtIface: 635 + Capability: Bridge, on + Capability: Router, on + Port: + PortID: GigabitEthernet1/0/15 + PortDescr: GigabitEthernet1/0/15 Interface + TTL: 121 + MFS: 10240 + PMD autoneg: supported: yes, enabled: yes + Adv: 10Base-T, HD: yes, FD: yes + Adv: 100Base-TX, HD: yes, FD: yes + Adv: 1000Base-T, HD: no, FD: yes + MAU oper type: 30 + MDI Power: supported: yes, enabled: no, pair control: no + VLAN: 1, pvid: yes, VLAN 0001 + PPVID: supported: yes,enabled no + +Interface: p1 + Chassis: + Chassis ID: aa:aa:aa:aa:aa:aa + SysName: FakeSystemName + SysDescr: FakeSystemDesc + MgmtIP: 192.168.0.1 + MgmtIface: 635 + Capability: Bridge, on + Capability: Router, on + Port: + PortID: GigabitEthernet1/0/5 + PortDescr: GigabitEthernet1/0/5 Interface + TTL: 121 + MFS: 10240 + PMD autoneg: supported: yes, enabled: yes + Adv: 10Base-T, HD: yes, FD: yes + Adv: 100Base-TX, HD: yes, FD: yes + Adv: 1000Base-T, HD: no, FD: yes + MAU oper type: 30 + MDI Power: supported: yes, enabled: no, pair control: no + VLAN: 1, pvid: yes, VLAN 0001 + PPVID: supported: yes,enabled no +]) + +AT_CHECK([ovs-appctl --format json --pretty lldp/neighbor p1 ], [0], [dnl +[{ + "lldp": { + "interface": [ + { + "p1": { + "chassis": { + "FakeSystemName": { + "capability": [ + { + "enabled": true, + "type": "Bridge"}, + { + "enabled": true, + "type": "Router"}], + "descr": "FakeSystemDesc", + "id": { + "type": "mac", + "value": "aa:aa:aa:aa:aa:aa"}, + "mgmt-iface": [ + 635], + "mgmt-ip": [ + "192.168.0.1"]}}, + "port": { + "auto-negotiation": { + "current": 30, + "enabled": true, + "supported": true}, + "desc": "GigabitEthernet1/0/15 Interface", + "id": { + "type": "ifname", + "value": "GigabitEthernet1/0/15"}, + "mfs": 10240, + "power": { + "enabled": false, + "paircontrol": false, + "supported": true}, + "ttl": 121}, + "ppvid": { + "enabled": false, + "supported": true}, + "vlan": { + "pvid": true, + "value": "VLAN 0001", + "vlan-id": 1}}}, + { + "p1": { + "chassis": { + "FakeSystemName": { + "capability": [ + { + "enabled": true, + "type": "Bridge"}, + { + "enabled": true, + "type": "Router"}], + "descr": "FakeSystemDesc", + "id": { + "type": "mac", + "value": "aa:aa:aa:aa:aa:aa"}, + "mgmt-iface": [ + 635], + "mgmt-ip": [ + "192.168.0.1"]}}, + "port": { + "auto-negotiation": { + "current": 30, + "enabled": true, + "supported": true}, + "desc": "GigabitEthernet1/0/5 Interface", + "id": { + "type": "ifname", + "value": "GigabitEthernet1/0/5"}, + "mfs": 10240, + "power": { + "enabled": false, + "paircontrol": false, + "supported": true}, + "ttl": 121}, + "ppvid": { + "enabled": false, + "supported": true}, + "vlan": { + "pvid": true, + "value": "VLAN 0001", + "vlan-id": 1}}}]}}] +]) + +AT_CLEANUP \ No newline at end of file diff --git a/tests/testsuite.at b/tests/testsuite.at index 9d77a9f51..f80656076 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -66,6 +66,7 @@ m4_include([tests/ofproto-dpif.at]) m4_include([tests/bridge.at]) m4_include([tests/netdev-type.at]) m4_include([tests/ovsdb.at]) +m4_include([tests/ovs-lldp.at]) m4_include([tests/ovs-vsctl.at]) m4_include([tests/stp.at]) m4_include([tests/rstp.at])