From c48ca17aa82a9e2435c181ca56aca3dfb42fe47d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 25 Feb 2024 14:16:47 +0900 Subject: [PATCH] network/varlink: add varlink method to get LLDP neighbors MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The method provides the list of LLDP neighbors. Co-authored-by: Tomáš Pecka --- src/network/networkd-manager-varlink.c | 111 +++++++++++++++++++++++- src/shared/varlink-io.systemd.Network.c | 29 ++++++- 2 files changed, 138 insertions(+), 2 deletions(-) diff --git a/src/network/networkd-manager-varlink.c b/src/network/networkd-manager-varlink.c index 8aefb686c65..0c54e86aea8 100644 --- a/src/network/networkd-manager-varlink.c +++ b/src/network/networkd-manager-varlink.c @@ -2,6 +2,7 @@ #include +#include "lldp-rx-internal.h" #include "networkd-manager-varlink.h" #include "varlink.h" #include "varlink-io.systemd.Network.h" @@ -56,6 +57,113 @@ static int vl_method_get_namespace_id(Varlink *link, JsonVariant *parameters, Va JSON_BUILD_PAIR_CONDITION(nsid != UINT32_MAX, "NamespaceNSID", JSON_BUILD_UNSIGNED(nsid)))); } +typedef struct InterfaceInfo { + int ifindex; + const char *ifname; +} InterfaceInfo; + +static int dispatch_interface(Varlink *vlink, JsonVariant *parameters, Manager *manager, Link **ret) { + static const JsonDispatch dispatch_table[] = { + { "InterfaceIndex", _JSON_VARIANT_TYPE_INVALID, json_dispatch_int, offsetof(InterfaceInfo, ifindex), 0 }, + { "InterfaceName", JSON_VARIANT_STRING, json_dispatch_const_string, offsetof(InterfaceInfo, ifname), 0 }, + {} + }; + + InterfaceInfo info = {}; + Link *link = NULL; + int r; + + assert(vlink); + assert(manager); + + r = varlink_dispatch(vlink, parameters, dispatch_table, &info); + if (r != 0) + return r; + + if (info.ifindex < 0) + return varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex")); + if (info.ifindex > 0 && link_get_by_index(manager, info.ifindex, &link) < 0) + return varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceIndex")); + if (info.ifname) { + Link *link_by_name; + + if (link_get_by_name(manager, info.ifname, &link_by_name) < 0) + return varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceName")); + + if (link && link_by_name != link) + /* If both arguments are specified, then these must be consistent. */ + return varlink_error_invalid_parameter(vlink, JSON_VARIANT_STRING_CONST("InterfaceName")); + + link = link_by_name; + } + + /* If neither InterfaceIndex nor InterfaceName specified, this function returns NULL. */ + *ret = link; + return 0; +} + +static int link_append_lldp_neighbors(Link *link, JsonVariant *v, JsonVariant **array) { + assert(link); + assert(array); + + return json_variant_append_arrayb(array, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_INTEGER("InterfaceIndex", link->ifindex), + JSON_BUILD_PAIR_STRING("InterfaceName", link->ifname), + JSON_BUILD_PAIR_STRV_NON_EMPTY("InterfaceAlternativeNames", link->alternative_names), + JSON_BUILD_PAIR_CONDITION(json_variant_is_blank_array(v), "Neighbors", JSON_BUILD_EMPTY_ARRAY), + JSON_BUILD_PAIR_CONDITION(!json_variant_is_blank_array(v), "Neighbors", JSON_BUILD_VARIANT(v)))); +} + +static int vl_method_get_lldp_neighbors(Varlink *vlink, JsonVariant *parameters, VarlinkMethodFlags flags, Manager *manager) { + _cleanup_(json_variant_unrefp) JsonVariant *array = NULL; + Link *link = NULL; + int r; + + assert(vlink); + assert(manager); + + r = dispatch_interface(vlink, parameters, manager, &link); + if (r != 0) + return r; + + if (link) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + + if (link->lldp_rx) { + r = lldp_rx_build_neighbors_json(link->lldp_rx, &v); + if (r < 0) + return r; + } + + r = link_append_lldp_neighbors(link, v, &array); + if (r < 0) + return r; + } else + HASHMAP_FOREACH(link, manager->links_by_index) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + + if (!link->lldp_rx) + continue; + + r = lldp_rx_build_neighbors_json(link->lldp_rx, &v); + if (r < 0) + return r; + + if (json_variant_is_blank_array(v)) + continue; + + r = link_append_lldp_neighbors(link, v, &array); + if (r < 0) + return r; + } + + return varlink_replyb(vlink, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR_CONDITION(json_variant_is_blank_array(array), "Neighbors", JSON_BUILD_EMPTY_ARRAY), + JSON_BUILD_PAIR_CONDITION(!json_variant_is_blank_array(array), "Neighbors", JSON_BUILD_VARIANT(array)))); +} + int manager_connect_varlink(Manager *m) { _cleanup_(varlink_server_unrefp) VarlinkServer *s = NULL; int r; @@ -78,7 +186,8 @@ int manager_connect_varlink(Manager *m) { r = varlink_server_bind_method_many( s, "io.systemd.Network.GetStates", vl_method_get_states, - "io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id); + "io.systemd.Network.GetNamespaceId", vl_method_get_namespace_id, + "io.systemd.Network.GetLLDPNeighbors", vl_method_get_lldp_neighbors); if (r < 0) return log_error_errno(r, "Failed to register varlink methods: %m"); diff --git a/src/shared/varlink-io.systemd.Network.c b/src/shared/varlink-io.systemd.Network.c index feb1e52feb7..986f2cfc695 100644 --- a/src/shared/varlink-io.systemd.Network.c +++ b/src/shared/varlink-io.systemd.Network.c @@ -16,8 +16,35 @@ static VARLINK_DEFINE_METHOD( VARLINK_DEFINE_OUTPUT(NamespaceId, VARLINK_INT, 0), VARLINK_DEFINE_OUTPUT(NamespaceNSID, VARLINK_INT, VARLINK_NULLABLE)); +static VARLINK_DEFINE_STRUCT_TYPE( + LLDPNeighbor, + VARLINK_DEFINE_FIELD(ChassisID, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(RawChassisID, VARLINK_INT, VARLINK_ARRAY), + VARLINK_DEFINE_FIELD(PortID, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(RawPortID, VARLINK_INT, VARLINK_ARRAY), + VARLINK_DEFINE_FIELD(PortDescription, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(SystemName, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(SystemDescription, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD(EnabledCapabilities, VARLINK_INT, VARLINK_NULLABLE)); + +static VARLINK_DEFINE_STRUCT_TYPE( + LLDPNeighborsByInterface, + VARLINK_DEFINE_FIELD(InterfaceIndex, VARLINK_INT, 0), + VARLINK_DEFINE_FIELD(InterfaceName, VARLINK_STRING, 0), + VARLINK_DEFINE_FIELD(InterfaceAlternativeNames, VARLINK_STRING, VARLINK_ARRAY|VARLINK_NULLABLE), + VARLINK_DEFINE_FIELD_BY_TYPE(Neighbors, LLDPNeighbor, VARLINK_ARRAY)); + +static VARLINK_DEFINE_METHOD( + GetLLDPNeighbors, + VARLINK_DEFINE_INPUT(InterfaceIndex, VARLINK_INT, VARLINK_NULLABLE), + VARLINK_DEFINE_INPUT(InterfaceName, VARLINK_STRING, VARLINK_NULLABLE), + VARLINK_DEFINE_OUTPUT_BY_TYPE(Neighbors, LLDPNeighborsByInterface, VARLINK_ARRAY)); + VARLINK_DEFINE_INTERFACE( io_systemd_Network, "io.systemd.Network", &vl_method_GetStates, - &vl_method_GetNamespaceId); + &vl_method_GetNamespaceId, + &vl_method_GetLLDPNeighbors, + &vl_type_LLDPNeighbor, + &vl_type_LLDPNeighborsByInterface); -- 2.47.3