blob: 44d0f826e29fe131634d489eabc0efa6f8e1ad22 [file] [log] [blame]
Tomáš Pecka5e070252022-05-20 20:41:21 +02001From 1e805d15da85b85dfd54684557da1415b0294903 Mon Sep 17 00:00:00 2001
Tomáš Peckaae301762021-10-13 10:50:37 +02002From: Tomas Pecka <peckato1@users.noreply.github.com>
3Date: Wed, 15 Sep 2021 14:42:34 +0200
4Subject: [PATCH 7/9] networkctl: lldp now uses varlink call
5
6`networkctl lldp` now uses varlink call to the networkd to query LLDP
7neighbor data.
8---
Václav Kubernát8cd61562021-12-08 13:27:31 +01009 src/network/networkctl.c | 215 +++++++++++++++++++++++++--------------
10 1 file changed, 139 insertions(+), 76 deletions(-)
Tomáš Peckaae301762021-10-13 10:50:37 +020011
12diff --git a/src/network/networkctl.c b/src/network/networkctl.c
Václav Kubernát8cd61562021-12-08 13:27:31 +010013index 46c08b5549..a10f3f3fc7 100644
Tomáš Peckaae301762021-10-13 10:50:37 +020014--- 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át8cd61562021-12-08 13:27:31 +010024@@ -62,6 +63,7 @@
Tomáš Peckaae301762021-10-13 10:50:37 +020025 #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át8cd61562021-12-08 13:27:31 +010032@@ -2479,14 +2481,103 @@ static void lldp_capabilities_legend(uint16_t x) {
Tomáš Peckaae301762021-10-13 10:50:37 +020033 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át8cd61562021-12-08 13:27:31 +010055+ int neighbors_count;
56+ uint16_t capabilities_all;
57+
58+ Table *table;
Tomáš Peckaae301762021-10-13 10:50:37 +020059+
60+ char *link_name;
Tomáš Peckaae301762021-10-13 10:50:37 +020061+} LLDPUserdata;
62+
Václav Kubernát8cd61562021-12-08 13:27:31 +010063+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áš Peckaae301762021-10-13 10:50:37 +020068+ 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át8cd61562021-12-08 13:27:31 +0100105+ udata->neighbors_count += 1;
106+ udata->capabilities_all |= entry.capabilities;
Tomáš Peckaae301762021-10-13 10:50:37 +0200107+
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át8cd61562021-12-08 13:27:31 +0100119- _cleanup_(table_unrefp) Table *table = NULL;
Tomáš Peckaae301762021-10-13 10:50:37 +0200120- int r, c, m = 0;
121- uint16_t all = 0;
Václav Kubernát8cd61562021-12-08 13:27:31 +0100122+ _cleanup_(lldp_userdata_freep) LLDPUserdata udata = {};
Tomáš Peckaae301762021-10-13 10:50:37 +0200123 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át8cd61562021-12-08 13:27:31 +0100132+ r = varlink_bind_reply(link, lldp_neighbors_varlink_reply);
Tomáš Peckaae301762021-10-13 10:50:37 +0200133+ 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át8cd61562021-12-08 13:27:31 +0100139@@ -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áš Peckaae301762021-10-13 10:50:37 +0200157 return log_oom();
158
Václav Kubernát8cd61562021-12-08 13:27:31 +0100159 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áš Pecka5e070252022-05-20 20:41:21 +0200212- for (int i = 0; i < c; i++) {
Tomáš Peckaae301762021-10-13 10:50:37 +0200213- _cleanup_fclose_ FILE *f = NULL;
Tomáš Pecka5e070252022-05-20 20:41:21 +0200214+ varlink_set_userdata(link, &udata);
Tomáš Peckaae301762021-10-13 10:50:37 +0200215
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áš Pecka5e070252022-05-20 20:41:21 +0200223-
Tomáš Peckaae301762021-10-13 10:50:37 +0200224- 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áš Pecka5e070252022-05-20 20:41:21 +0200229-
Tomáš Peckaae301762021-10-13 10:50:37 +0200230- 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áš Pecka5e070252022-05-20 20:41:21 +0200237+ for (int i = 0; i < c; i++) {
238+ _cleanup_(json_variant_unrefp) JsonVariant *cparams = NULL;
Tomáš Peckaae301762021-10-13 10:50:37 +0200239
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áš Pecka5e070252022-05-20 20:41:21 +0200244+ udata.link_name = links[i].name;
245
Tomáš Peckaae301762021-10-13 10:50:37 +0200246- if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) {
247- capabilities = lldp_capabilities_to_string(cc);
248- all |= cc;
249- }
Tomáš Pecka5e070252022-05-20 20:41:21 +0200250+ 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áš Peckaae301762021-10-13 10:50:37 +0200255- 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áš Pecka5e070252022-05-20 20:41:21 +0200264+ r = varlink_observe(link, method, cparams);
265+ if (r < 0)
266+ return log_error_errno(r, "Failed to execute varlink call: %m");
267
Tomáš Peckaae301762021-10-13 10:50:37 +0200268- m++;
269- }
270+ r = varlink_observe_complete(link);
271+ if (r < 0)
272+ return r;
273 }
274
Václav Kubernát8cd61562021-12-08 13:27:31 +0100275- r = table_print(table, NULL);
276+ r = table_print(udata.table, NULL);
277 if (r < 0)
Tomáš Peckaae301762021-10-13 10:50:37 +0200278 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át8cd61562021-12-08 13:27:31 +0100283+ lldp_capabilities_legend(udata.capabilities_all);
284+ printf("\n%i neighbors listed.\n", udata.neighbors_count);
Tomáš Peckaae301762021-10-13 10:50:37 +0200285 }
286
287 return 0;
288--
Tomáš Pecka5e070252022-05-20 20:41:21 +02002892.35.1
Tomáš Peckaae301762021-10-13 10:50:37 +0200290