| From 1e805d15da85b85dfd54684557da1415b0294903 Mon Sep 17 00:00:00 2001 |
| From: Tomas Pecka <peckato1@users.noreply.github.com> |
| Date: Wed, 15 Sep 2021 14:42:34 +0200 |
| Subject: [PATCH 7/9] networkctl: lldp now uses varlink call |
| |
| `networkctl lldp` now uses varlink call to the networkd to query LLDP |
| neighbor data. |
| --- |
| src/network/networkctl.c | 215 +++++++++++++++++++++++++-------------- |
| 1 file changed, 139 insertions(+), 76 deletions(-) |
| |
| diff --git a/src/network/networkctl.c b/src/network/networkctl.c |
| index 46c08b5549..a10f3f3fc7 100644 |
| --- a/src/network/networkctl.c |
| +++ b/src/network/networkctl.c |
| @@ -36,6 +36,7 @@ |
| #include "glob-util.h" |
| #include "hwdb-util.h" |
| #include "ipvlan-util.h" |
| +#include "json.h" |
| #include "local-addresses.h" |
| #include "locale-util.h" |
| #include "logs-show.h" |
| @@ -62,6 +63,7 @@ |
| #include "strxcpyx.h" |
| #include "terminal-util.h" |
| #include "unit-def.h" |
| +#include "varlink.h" |
| #include "verbs.h" |
| #include "wifi-util.h" |
| |
| @@ -2479,14 +2481,103 @@ static void lldp_capabilities_legend(uint16_t x) { |
| puts(""); |
| } |
| |
| +typedef struct LLDPNeighborEntry { |
| + uint32_t capabilities; |
| + char *chassis_id; |
| + char *port_id; |
| + char *system_name; |
| + char *port_description; |
| +} LLDPNeighborEntry; |
| + |
| +static void lldp_neighbor_entry_free(LLDPNeighborEntry *e) { |
| + if (!e) |
| + return; |
| + |
| + free(e->chassis_id); |
| + free(e->port_id); |
| + free(e->system_name); |
| + free(e->port_description); |
| +} |
| + |
| +typedef struct LLDPUserdata { |
| + int neighbors_count; |
| + uint16_t capabilities_all; |
| + |
| + Table *table; |
| + |
| + char *link_name; |
| +} LLDPUserdata; |
| + |
| +static void lldp_userdata_freep(LLDPUserdata* p) { |
| + table_unref(p->table); |
| +} |
| + |
| +static int lldp_neighbors_varlink_reply(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata) { |
| + int r; |
| + _cleanup_free_ char *capabilities = NULL; |
| + LLDPUserdata *udata; |
| + _cleanup_(lldp_neighbor_entry_free) LLDPNeighborEntry entry = {}; |
| + |
| + static const JsonDispatch dispatch_table[] = { |
| + { "chassisId", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, chassis_id), 0 }, |
| + { "portId", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, port_id), 0 }, |
| + { "systemName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, system_name), 0 }, |
| + { "enabledCapabilities", JSON_VARIANT_UNSIGNED, json_dispatch_uint32, offsetof(LLDPNeighborEntry, capabilities), 0 }, |
| + { "portDescription", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, port_description), 0 }, |
| + {} |
| + }; |
| + |
| + udata = userdata; |
| + |
| + assert(udata); |
| + assert(udata->link_name); |
| + |
| + r = json_dispatch(json_variant_by_key(parameters, "neighbor"), dispatch_table, NULL, 0, &entry); |
| + if (r < 0) |
| + return r; |
| + |
| + if (udata->table) { |
| + capabilities = lldp_capabilities_to_string(entry.capabilities); |
| + |
| + r = table_add_many(udata->table, |
| + TABLE_STRING, udata->link_name, |
| + TABLE_STRING, entry.chassis_id, |
| + TABLE_STRING, entry.system_name, |
| + TABLE_STRING, capabilities, |
| + TABLE_STRING, entry.port_id, |
| + TABLE_STRING, entry.port_description); |
| + if (r < 0) |
| + return table_log_add_error(r); |
| + } |
| + |
| + udata->neighbors_count += 1; |
| + udata->capabilities_all |= entry.capabilities; |
| + |
| + return 0; |
| +} |
| + |
| static int link_lldp_status(int argc, char *argv[], void *userdata) { |
| + static const char *address = "/run/systemd/netif/io.systemd.Network"; |
| + static const char *method = "io.systemd.Network.LLDPNeighbors"; |
| + |
| + int r, c; |
| + _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL; |
| _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; |
| _cleanup_(link_info_array_freep) LinkInfo *links = NULL; |
| - _cleanup_(table_unrefp) Table *table = NULL; |
| - int r, c, m = 0; |
| - uint16_t all = 0; |
| + _cleanup_(lldp_userdata_freep) LLDPUserdata udata = {}; |
| TableCell *cell; |
| |
| + r = varlink_connect_address(&link, address); |
| + if (r < 0) |
| + return log_error_errno(r, "Failed to connect to %s: %m", address); |
| + |
| + (void) varlink_set_description(link, "network"); |
| + (void) varlink_set_relative_timeout(link, USEC_INFINITY); |
| + |
| + r = varlink_bind_reply(link, lldp_neighbors_varlink_reply); |
| + if (r < 0) |
| + return log_error_errno(r, "Failed to bind reply callback: %m"); |
| + |
| r = sd_netlink_open(&rtnl); |
| if (r < 0) |
| return log_error_errno(r, "Failed to connect to netlink: %m"); |
| @@ -2497,103 +2588,75 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { |
| |
| pager_open(arg_pager_flags); |
| |
| - table = table_new("link", |
| - "chassis id", |
| - "system name", |
| - "caps", |
| - "port id", |
| - "port description"); |
| - if (!table) |
| + udata.table = table_new("link", |
| + "chassis id", |
| + "system name", |
| + "caps", |
| + "port id", |
| + "port description"); |
| + if (!udata.table) |
| return log_oom(); |
| |
| if (arg_full) |
| - table_set_width(table, 0); |
| + table_set_width(udata.table, 0); |
| |
| - table_set_header(table, arg_legend); |
| + table_set_header(udata.table, arg_legend); |
| |
| - assert_se(cell = table_get_cell(table, 0, 0)); |
| - table_set_minimum_width(table, cell, 16); |
| - table_set_maximum_width(table, cell, 16); |
| + assert_se(cell = table_get_cell(udata.table, 0, 0)); |
| + table_set_minimum_width(udata.table, cell, 16); |
| + table_set_maximum_width(udata.table, cell, 16); |
| |
| - assert_se(cell = table_get_cell(table, 0, 1)); |
| - table_set_minimum_width(table, cell, 17); |
| - table_set_maximum_width(table, cell, 17); |
| + assert_se(cell = table_get_cell(udata.table, 0, 1)); |
| + table_set_minimum_width(udata.table, cell, 17); |
| + table_set_maximum_width(udata.table, cell, 17); |
| |
| - assert_se(cell = table_get_cell(table, 0, 2)); |
| - table_set_minimum_width(table, cell, 16); |
| - table_set_maximum_width(table, cell, 16); |
| + assert_se(cell = table_get_cell(udata.table, 0, 2)); |
| + table_set_minimum_width(udata.table, cell, 16); |
| + table_set_maximum_width(udata.table, cell, 16); |
| |
| - assert_se(cell = table_get_cell(table, 0, 3)); |
| - table_set_minimum_width(table, cell, 11); |
| - table_set_maximum_width(table, cell, 11); |
| + assert_se(cell = table_get_cell(udata.table, 0, 3)); |
| + table_set_minimum_width(udata.table, cell, 11); |
| + table_set_maximum_width(udata.table, cell, 11); |
| |
| - assert_se(cell = table_get_cell(table, 0, 4)); |
| - table_set_minimum_width(table, cell, 17); |
| - table_set_maximum_width(table, cell, 17); |
| + assert_se(cell = table_get_cell(udata.table, 0, 4)); |
| + table_set_minimum_width(udata.table, cell, 17); |
| + table_set_maximum_width(udata.table, cell, 17); |
| |
| - assert_se(cell = table_get_cell(table, 0, 5)); |
| - table_set_minimum_width(table, cell, 16); |
| - table_set_maximum_width(table, cell, 16); |
| + assert_se(cell = table_get_cell(udata.table, 0, 5)); |
| + table_set_minimum_width(udata.table, cell, 16); |
| + table_set_maximum_width(udata.table, cell, 16); |
| |
| - if (table_set_empty_string(table, "n/a") < 0) |
| + if (table_set_empty_string(udata.table, "n/a") < 0) |
| return log_oom(); |
| |
| - for (int i = 0; i < c; i++) { |
| - _cleanup_fclose_ FILE *f = NULL; |
| + varlink_set_userdata(link, &udata); |
| |
| - r = open_lldp_neighbors(links[i].ifindex, &f); |
| - if (r == -ENOENT) |
| - continue; |
| - if (r < 0) { |
| - log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex); |
| - continue; |
| - } |
| - |
| - for (;;) { |
| - _cleanup_free_ char *capabilities = NULL; |
| - const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL; |
| - _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; |
| - uint16_t cc; |
| - |
| - r = next_lldp_neighbor(f, &n); |
| - if (r < 0) { |
| - log_warning_errno(r, "Failed to read neighbor data: %m"); |
| - break; |
| - } |
| - if (r == 0) |
| - break; |
| + for (int i = 0; i < c; i++) { |
| + _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL; |
| |
| - (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id); |
| - (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); |
| - (void) sd_lldp_neighbor_get_system_name(n, &system_name); |
| - (void) sd_lldp_neighbor_get_port_description(n, &port_description); |
| + udata.link_name = links[i].name; |
| |
| - if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) { |
| - capabilities = lldp_capabilities_to_string(cc); |
| - all |= cc; |
| - } |
| + r = json_build(&cparams, JSON_BUILD_OBJECT( |
| + JSON_BUILD_PAIR("ifindex", JSON_BUILD_UNSIGNED(links[i].ifindex)))); |
| + if (r < 0) |
| + return r; |
| |
| - r = table_add_many(table, |
| - TABLE_STRING, links[i].name, |
| - TABLE_STRING, chassis_id, |
| - TABLE_STRING, system_name, |
| - TABLE_STRING, capabilities, |
| - TABLE_STRING, port_id, |
| - TABLE_STRING, port_description); |
| - if (r < 0) |
| - return table_log_add_error(r); |
| + r = varlink_observe(link, method, cparams); |
| + if (r < 0) |
| + return log_error_errno(r, "Failed to execute varlink call: %m"); |
| |
| - m++; |
| - } |
| + r = varlink_observe_complete(link); |
| + if (r < 0) |
| + return r; |
| } |
| |
| - r = table_print(table, NULL); |
| + r = table_print(udata.table, NULL); |
| if (r < 0) |
| return table_log_print_error(r); |
| |
| if (arg_legend) { |
| - lldp_capabilities_legend(all); |
| - printf("\n%i neighbors listed.\n", m); |
| + lldp_capabilities_legend(udata.capabilities_all); |
| + printf("\n%i neighbors listed.\n", udata.neighbors_count); |
| } |
| |
| return 0; |
| -- |
| 2.35.1 |
| |