Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 1 | From 1e805d15da85b85dfd54684557da1415b0294903 Mon Sep 17 00:00:00 2001 |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 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 | --- |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 9 | src/network/networkctl.c | 215 +++++++++++++++++++++++++-------------- |
| 10 | 1 file changed, 139 insertions(+), 76 deletions(-) |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 11 | |
| 12 | diff --git a/src/network/networkctl.c b/src/network/networkctl.c |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 13 | index 46c08b5549..a10f3f3fc7 100644 |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 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" |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 24 | @@ -62,6 +63,7 @@ |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 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 | |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 32 | @@ -2479,14 +2481,103 @@ static void lldp_capabilities_legend(uint16_t x) { |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 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 { |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 55 | + int neighbors_count; |
| 56 | + uint16_t capabilities_all; |
| 57 | + |
| 58 | + Table *table; |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 59 | + |
| 60 | + char *link_name; |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 61 | +} LLDPUserdata; |
| 62 | + |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 63 | +static void lldp_userdata_freep(LLDPUserdata* p) { |
| 64 | + table_unref(p->table); |
| 65 | +} |
| 66 | + |
| 67 | +static int lldp_neighbors_varlink_reply(Varlink *link, JsonVariant *parameters, const char *error_id, VarlinkReplyFlags flags, void *userdata) { |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 68 | + int r; |
| 69 | + _cleanup_free_ char *capabilities = NULL; |
| 70 | + LLDPUserdata *udata; |
| 71 | + _cleanup_(lldp_neighbor_entry_free) LLDPNeighborEntry entry = {}; |
| 72 | + |
| 73 | + static const JsonDispatch dispatch_table[] = { |
| 74 | + { "chassisId", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, chassis_id), 0 }, |
| 75 | + { "portId", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, port_id), 0 }, |
| 76 | + { "systemName", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, system_name), 0 }, |
| 77 | + { "enabledCapabilities", JSON_VARIANT_UNSIGNED, json_dispatch_uint32, offsetof(LLDPNeighborEntry, capabilities), 0 }, |
| 78 | + { "portDescription", JSON_VARIANT_STRING, json_dispatch_string, offsetof(LLDPNeighborEntry, port_description), 0 }, |
| 79 | + {} |
| 80 | + }; |
| 81 | + |
| 82 | + udata = userdata; |
| 83 | + |
| 84 | + assert(udata); |
| 85 | + assert(udata->link_name); |
| 86 | + |
| 87 | + r = json_dispatch(json_variant_by_key(parameters, "neighbor"), dispatch_table, NULL, 0, &entry); |
| 88 | + if (r < 0) |
| 89 | + return r; |
| 90 | + |
| 91 | + if (udata->table) { |
| 92 | + capabilities = lldp_capabilities_to_string(entry.capabilities); |
| 93 | + |
| 94 | + r = table_add_many(udata->table, |
| 95 | + TABLE_STRING, udata->link_name, |
| 96 | + TABLE_STRING, entry.chassis_id, |
| 97 | + TABLE_STRING, entry.system_name, |
| 98 | + TABLE_STRING, capabilities, |
| 99 | + TABLE_STRING, entry.port_id, |
| 100 | + TABLE_STRING, entry.port_description); |
| 101 | + if (r < 0) |
| 102 | + return table_log_add_error(r); |
| 103 | + } |
| 104 | + |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 105 | + udata->neighbors_count += 1; |
| 106 | + udata->capabilities_all |= entry.capabilities; |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 107 | + |
| 108 | + return 0; |
| 109 | +} |
| 110 | + |
| 111 | static int link_lldp_status(int argc, char *argv[], void *userdata) { |
| 112 | + static const char *address = "/run/systemd/netif/io.systemd.Network"; |
| 113 | + static const char *method = "io.systemd.Network.LLDPNeighbors"; |
| 114 | + |
| 115 | + int r, c; |
| 116 | + _cleanup_(varlink_flush_close_unrefp) Varlink *link = NULL; |
| 117 | _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; |
| 118 | _cleanup_(link_info_array_freep) LinkInfo *links = NULL; |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 119 | - _cleanup_(table_unrefp) Table *table = NULL; |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 120 | - int r, c, m = 0; |
| 121 | - uint16_t all = 0; |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 122 | + _cleanup_(lldp_userdata_freep) LLDPUserdata udata = {}; |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 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 | + |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 132 | + r = varlink_bind_reply(link, lldp_neighbors_varlink_reply); |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 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"); |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 139 | @@ -2497,103 +2588,75 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { |
| 140 | |
| 141 | pager_open(arg_pager_flags); |
| 142 | |
| 143 | - table = table_new("link", |
| 144 | - "chassis id", |
| 145 | - "system name", |
| 146 | - "caps", |
| 147 | - "port id", |
| 148 | - "port description"); |
| 149 | - if (!table) |
| 150 | + udata.table = table_new("link", |
| 151 | + "chassis id", |
| 152 | + "system name", |
| 153 | + "caps", |
| 154 | + "port id", |
| 155 | + "port description"); |
| 156 | + if (!udata.table) |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 157 | return log_oom(); |
| 158 | |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 159 | if (arg_full) |
| 160 | - table_set_width(table, 0); |
| 161 | + table_set_width(udata.table, 0); |
| 162 | |
| 163 | - table_set_header(table, arg_legend); |
| 164 | + table_set_header(udata.table, arg_legend); |
| 165 | |
| 166 | - assert_se(cell = table_get_cell(table, 0, 0)); |
| 167 | - table_set_minimum_width(table, cell, 16); |
| 168 | - table_set_maximum_width(table, cell, 16); |
| 169 | + assert_se(cell = table_get_cell(udata.table, 0, 0)); |
| 170 | + table_set_minimum_width(udata.table, cell, 16); |
| 171 | + table_set_maximum_width(udata.table, cell, 16); |
| 172 | |
| 173 | - assert_se(cell = table_get_cell(table, 0, 1)); |
| 174 | - table_set_minimum_width(table, cell, 17); |
| 175 | - table_set_maximum_width(table, cell, 17); |
| 176 | + assert_se(cell = table_get_cell(udata.table, 0, 1)); |
| 177 | + table_set_minimum_width(udata.table, cell, 17); |
| 178 | + table_set_maximum_width(udata.table, cell, 17); |
| 179 | |
| 180 | - assert_se(cell = table_get_cell(table, 0, 2)); |
| 181 | - table_set_minimum_width(table, cell, 16); |
| 182 | - table_set_maximum_width(table, cell, 16); |
| 183 | + assert_se(cell = table_get_cell(udata.table, 0, 2)); |
| 184 | + table_set_minimum_width(udata.table, cell, 16); |
| 185 | + table_set_maximum_width(udata.table, cell, 16); |
| 186 | |
| 187 | - assert_se(cell = table_get_cell(table, 0, 3)); |
| 188 | - table_set_minimum_width(table, cell, 11); |
| 189 | - table_set_maximum_width(table, cell, 11); |
| 190 | + assert_se(cell = table_get_cell(udata.table, 0, 3)); |
| 191 | + table_set_minimum_width(udata.table, cell, 11); |
| 192 | + table_set_maximum_width(udata.table, cell, 11); |
| 193 | |
| 194 | - assert_se(cell = table_get_cell(table, 0, 4)); |
| 195 | - table_set_minimum_width(table, cell, 17); |
| 196 | - table_set_maximum_width(table, cell, 17); |
| 197 | + assert_se(cell = table_get_cell(udata.table, 0, 4)); |
| 198 | + table_set_minimum_width(udata.table, cell, 17); |
| 199 | + table_set_maximum_width(udata.table, cell, 17); |
| 200 | |
| 201 | - assert_se(cell = table_get_cell(table, 0, 5)); |
| 202 | - table_set_minimum_width(table, cell, 16); |
| 203 | - table_set_maximum_width(table, cell, 16); |
| 204 | + assert_se(cell = table_get_cell(udata.table, 0, 5)); |
| 205 | + table_set_minimum_width(udata.table, cell, 16); |
| 206 | + table_set_maximum_width(udata.table, cell, 16); |
| 207 | |
| 208 | - if (table_set_empty_string(table, "n/a") < 0) |
| 209 | + if (table_set_empty_string(udata.table, "n/a") < 0) |
| 210 | return log_oom(); |
| 211 | |
Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 212 | - for (int i = 0; i < c; i++) { |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 213 | - _cleanup_fclose_ FILE *f = NULL; |
Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 214 | + varlink_set_userdata(link, &udata); |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 215 | |
| 216 | - r = open_lldp_neighbors(links[i].ifindex, &f); |
| 217 | - if (r == -ENOENT) |
| 218 | - continue; |
| 219 | - if (r < 0) { |
| 220 | - log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex); |
| 221 | - continue; |
| 222 | - } |
Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 223 | - |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 224 | - for (;;) { |
| 225 | - _cleanup_free_ char *capabilities = NULL; |
| 226 | - const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL; |
| 227 | - _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; |
| 228 | - uint16_t cc; |
Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 229 | - |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 230 | - r = next_lldp_neighbor(f, &n); |
| 231 | - if (r < 0) { |
| 232 | - log_warning_errno(r, "Failed to read neighbor data: %m"); |
| 233 | - break; |
| 234 | - } |
| 235 | - if (r == 0) |
| 236 | - break; |
Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 237 | + for (int i = 0; i < c; i++) { |
| 238 | + _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL; |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 239 | |
| 240 | - (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id); |
| 241 | - (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); |
| 242 | - (void) sd_lldp_neighbor_get_system_name(n, &system_name); |
| 243 | - (void) sd_lldp_neighbor_get_port_description(n, &port_description); |
Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 244 | + udata.link_name = links[i].name; |
| 245 | |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 246 | - if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) { |
| 247 | - capabilities = lldp_capabilities_to_string(cc); |
| 248 | - all |= cc; |
| 249 | - } |
Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 250 | + r = json_build(&cparams, JSON_BUILD_OBJECT( |
| 251 | + JSON_BUILD_PAIR("ifindex", JSON_BUILD_UNSIGNED(links[i].ifindex)))); |
| 252 | + if (r < 0) |
| 253 | + return r; |
| 254 | |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 255 | - r = table_add_many(table, |
| 256 | - TABLE_STRING, links[i].name, |
| 257 | - TABLE_STRING, chassis_id, |
| 258 | - TABLE_STRING, system_name, |
| 259 | - TABLE_STRING, capabilities, |
| 260 | - TABLE_STRING, port_id, |
| 261 | - TABLE_STRING, port_description); |
| 262 | - if (r < 0) |
| 263 | - return table_log_add_error(r); |
Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 264 | + r = varlink_observe(link, method, cparams); |
| 265 | + if (r < 0) |
| 266 | + return log_error_errno(r, "Failed to execute varlink call: %m"); |
| 267 | |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 268 | - m++; |
| 269 | - } |
| 270 | + r = varlink_observe_complete(link); |
| 271 | + if (r < 0) |
| 272 | + return r; |
| 273 | } |
| 274 | |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 275 | - r = table_print(table, NULL); |
| 276 | + r = table_print(udata.table, NULL); |
| 277 | if (r < 0) |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 278 | return table_log_print_error(r); |
| 279 | |
| 280 | if (arg_legend) { |
| 281 | - lldp_capabilities_legend(all); |
| 282 | - printf("\n%i neighbors listed.\n", m); |
Václav Kubernát | 8cd6156 | 2021-12-08 13:27:31 +0100 | [diff] [blame] | 283 | + lldp_capabilities_legend(udata.capabilities_all); |
| 284 | + printf("\n%i neighbors listed.\n", udata.neighbors_count); |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 285 | } |
| 286 | |
| 287 | return 0; |
| 288 | -- |
Tomáš Pecka | 5e07025 | 2022-05-20 20:41:21 +0200 | [diff] [blame] | 289 | 2.35.1 |
Tomáš Pecka | ae30176 | 2021-10-13 10:50:37 +0200 | [diff] [blame] | 290 | |