Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 1 | From e5b7f28a216ee1986c417f83132e3daf39ef5fd2 Mon Sep 17 00:00:00 2001 |
| 2 | From: Tomas Pecka <peckato1@users.noreply.github.com> |
| 3 | Date: Wed, 15 Sep 2021 14:42:34 +0200 |
| 4 | Subject: [PATCH 7/9] networkctl: lldp now uses varlink call |
| 5 | |
| 6 | `networkctl lldp` now uses varlink call to the networkd to query LLDP |
| 7 | neighbor data. |
| 8 | --- |
| 9 | src/network/networkctl.c | 157 ++++++++++++++++++++++++++++----------- |
| 10 | 1 file changed, 113 insertions(+), 44 deletions(-) |
| 11 | |
| 12 | diff --git a/src/network/networkctl.c b/src/network/networkctl.c |
| 13 | index a1d42cbe92..f98779da7e 100644 |
| 14 | --- a/src/network/networkctl.c |
| 15 | +++ b/src/network/networkctl.c |
| 16 | @@ -36,6 +36,7 @@ |
| 17 | #include "glob-util.h" |
| 18 | #include "hwdb-util.h" |
| 19 | #include "ipvlan-util.h" |
| 20 | +#include "json.h" |
| 21 | #include "local-addresses.h" |
| 22 | #include "locale-util.h" |
| 23 | #include "logs-show.h" |
| 24 | @@ -61,6 +62,7 @@ |
| 25 | #include "strxcpyx.h" |
| 26 | #include "terminal-util.h" |
| 27 | #include "unit-def.h" |
| 28 | +#include "varlink.h" |
| 29 | #include "verbs.h" |
| 30 | #include "wifi-util.h" |
| 31 | |
| 32 | @@ -2481,14 +2483,104 @@ static void lldp_capabilities_legend(uint16_t x) { |
| 33 | puts(""); |
| 34 | } |
| 35 | |
| 36 | +typedef struct LLDPNeighborEntry { |
| 37 | + uint32_t capabilities; |
| 38 | + char *chassis_id; |
| 39 | + char *port_id; |
| 40 | + char *system_name; |
| 41 | + char *port_description; |
| 42 | +} LLDPNeighborEntry; |
| 43 | + |
| 44 | +static void lldp_neighbor_entry_free(LLDPNeighborEntry *e) { |
| 45 | + if (!e) |
| 46 | + return; |
| 47 | + |
| 48 | + free(e->chassis_id); |
| 49 | + free(e->port_id); |
| 50 | + free(e->system_name); |
| 51 | + free(e->port_description); |
| 52 | +} |
| 53 | + |
| 54 | +typedef struct LLDPUserdata { |
| 55 | + int *neighbors_count; |
| 56 | + uint16_t *capabilities_all; |
| 57 | + |
| 58 | + char *link_name; |
| 59 | + Table *table; |
| 60 | +} LLDPUserdata; |
| 61 | + |
| 62 | +static int lldp_neighbours_varlink_reply(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata) { |
| 63 | + int r; |
| 64 | + _cleanup_free_ char *capabilities = NULL; |
| 65 | + LLDPUserdata *udata; |
| 66 | + _cleanup_(lldp_neighbor_entry_free) LLDPNeighborEntry entry = {}; |
| 67 | + |
| 68 | + static const JsonDispatch dispatch_table[] = { |
| 69 | + { "chassisId", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, chassis_id), 0 }, |
| 70 | + { "portId", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, port_id), 0 }, |
| 71 | + { "systemName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, system_name), 0 }, |
| 72 | + { "enabledCapabilities", JSON_VARIANT_UNSIGNED, json_dispatch_uint32, offsetof(LLDPNeighborEntry, capabilities), 0 }, |
| 73 | + { "portDescription", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, port_description), 0 }, |
| 74 | + {} |
| 75 | + }; |
| 76 | + |
| 77 | + udata = userdata; |
| 78 | + |
| 79 | + assert(udata); |
| 80 | + assert(udata->link_name); |
| 81 | + |
| 82 | + r = json_dispatch(json_variant_by_key(parameters, "neighbor"), dispatch_table, NULL, 0, &entry); |
| 83 | + if (r < 0) |
| 84 | + return r; |
| 85 | + |
| 86 | + if (udata->table) { |
| 87 | + capabilities = lldp_capabilities_to_string(entry.capabilities); |
| 88 | + |
| 89 | + r = table_add_many(udata->table, |
| 90 | + TABLE_STRING, udata->link_name, |
| 91 | + TABLE_STRING, entry.chassis_id, |
| 92 | + TABLE_STRING, entry.system_name, |
| 93 | + TABLE_STRING, capabilities, |
| 94 | + TABLE_STRING, entry.port_id, |
| 95 | + TABLE_STRING, entry.port_description); |
| 96 | + if (r < 0) |
| 97 | + return table_log_add_error(r); |
| 98 | + } |
| 99 | + |
| 100 | + if (udata->neighbors_count) |
| 101 | + *(udata->neighbors_count) += 1; |
| 102 | + |
| 103 | + if (udata->capabilities_all) |
| 104 | + *(udata->capabilities_all) |= entry.capabilities; |
| 105 | + |
| 106 | + return 0; |
| 107 | +} |
| 108 | + |
| 109 | static int link_lldp_status(int argc, char *argv[], void *userdata) { |
| 110 | + static const char *address = "/run/systemd/netif/io.systemd.Network"; |
| 111 | + static const char *method = "io.systemd.Network.LLDPNeighbors"; |
| 112 | + |
| 113 | + int r, c; |
| 114 | + _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL; |
| 115 | _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; |
| 116 | _cleanup_(link_info_array_freep) LinkInfo *links = NULL; |
| 117 | _cleanup_(table_unrefp) Table *table = NULL; |
| 118 | - int r, c, m = 0; |
| 119 | - uint16_t all = 0; |
| 120 | + int neighbors_count = 0; |
| 121 | + uint16_t capabilities_all = 0; |
| 122 | + LLDPUserdata udata = {}; |
| 123 | TableCell *cell; |
| 124 | |
| 125 | + r = varlink_connect_address(&link, address); |
| 126 | + if (r < 0) |
| 127 | + return log_error_errno(r, "Failed to connect to %s: %m", address); |
| 128 | + |
| 129 | + (void) varlink_set_description(link, "network"); |
| 130 | + (void) varlink_set_relative_timeout(link, USEC_INFINITY); |
| 131 | + |
| 132 | + r = varlink_bind_reply(link, lldp_neighbours_varlink_reply); |
| 133 | + if (r < 0) |
| 134 | + return log_error_errno(r, "Failed to bind reply callback: %m"); |
| 135 | + |
| 136 | r = sd_netlink_open(&rtnl); |
| 137 | if (r < 0) |
| 138 | return log_error_errno(r, "Failed to connect to netlink: %m"); |
| 139 | @@ -2540,53 +2632,30 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { |
| 140 | if (table_set_empty_string(table, "n/a") < 0) |
| 141 | return log_oom(); |
| 142 | |
| 143 | - for (int i = 0; i < c; i++) { |
| 144 | - _cleanup_fclose_ FILE *f = NULL; |
| 145 | + udata.table = table; |
| 146 | |
| 147 | - r = open_lldp_neighbors(links[i].ifindex, &f); |
| 148 | - if (r == -ENOENT) |
| 149 | - continue; |
| 150 | - if (r < 0) { |
| 151 | - log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex); |
| 152 | - continue; |
| 153 | - } |
| 154 | + udata.neighbors_count = &neighbors_count; |
| 155 | + udata.capabilities_all = &capabilities_all; |
| 156 | |
| 157 | - for (;;) { |
| 158 | - _cleanup_free_ char *capabilities = NULL; |
| 159 | - const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL; |
| 160 | - _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; |
| 161 | - uint16_t cc; |
| 162 | + varlink_set_userdata(link, &udata); |
| 163 | |
| 164 | - r = next_lldp_neighbor(f, &n); |
| 165 | - if (r < 0) { |
| 166 | - log_warning_errno(r, "Failed to read neighbor data: %m"); |
| 167 | - break; |
| 168 | - } |
| 169 | - if (r == 0) |
| 170 | - break; |
| 171 | + for (int i = 0; i < c; i++) { |
| 172 | + _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL; |
| 173 | |
| 174 | - (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id); |
| 175 | - (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); |
| 176 | - (void) sd_lldp_neighbor_get_system_name(n, &system_name); |
| 177 | - (void) sd_lldp_neighbor_get_port_description(n, &port_description); |
| 178 | + udata.link_name = links[i].name; |
| 179 | |
| 180 | - if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) { |
| 181 | - capabilities = lldp_capabilities_to_string(cc); |
| 182 | - all |= cc; |
| 183 | - } |
| 184 | + r = json_build(&cparams, JSON_BUILD_OBJECT( |
| 185 | + JSON_BUILD_PAIR("ifindex", JSON_BUILD_UNSIGNED(links[i].ifindex)))); |
| 186 | + if (r < 0) |
| 187 | + return r; |
| 188 | |
| 189 | - r = table_add_many(table, |
| 190 | - TABLE_STRING, links[i].name, |
| 191 | - TABLE_STRING, chassis_id, |
| 192 | - TABLE_STRING, system_name, |
| 193 | - TABLE_STRING, capabilities, |
| 194 | - TABLE_STRING, port_id, |
| 195 | - TABLE_STRING, port_description); |
| 196 | - if (r < 0) |
| 197 | - return table_log_add_error(r); |
| 198 | + r = varlink_observe(link, method, cparams); |
| 199 | + if (r < 0) |
| 200 | + return log_error_errno(r, "Failed to execute varlink call: %m"); |
| 201 | |
| 202 | - m++; |
| 203 | - } |
| 204 | + r = varlink_observe_complete(link); |
| 205 | + if (r < 0) |
| 206 | + return r; |
| 207 | } |
| 208 | |
| 209 | r = table_print(table, NULL); |
| 210 | @@ -2594,8 +2663,8 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { |
| 211 | return table_log_print_error(r); |
| 212 | |
| 213 | if (arg_legend) { |
| 214 | - lldp_capabilities_legend(all); |
| 215 | - printf("\n%i neighbors listed.\n", m); |
| 216 | + lldp_capabilities_legend(capabilities_all); |
| 217 | + printf("\n%i neighbors listed.\n", neighbors_count); |
| 218 | } |
| 219 | |
| 220 | return 0; |
| 221 | -- |
| 222 | 2.33.0 |
| 223 | |