1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <arpa/inet.h>
4 #include <getopt.h>
5 #include <linux/if_addrlabel.h>
6 #include <net/if.h>
7 #include <stdbool.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include <linux/if_bridge.h>
12 #include <linux/if_tunnel.h>
13
14 #include "sd-bus.h"
15 #include "sd-device.h"
16 #include "sd-dhcp-client.h"
17 #include "sd-hwdb.h"
18 #include "sd-lldp-rx.h"
19 #include "sd-netlink.h"
20 #include "sd-network.h"
21
22 #include "alloc-util.h"
23 #include "bond-util.h"
24 #include "bridge-util.h"
25 #include "bus-common-errors.h"
26 #include "bus-error.h"
27 #include "bus-locator.h"
28 #include "device-util.h"
29 #include "escape.h"
30 #include "ether-addr-util.h"
31 #include "ethtool-util.h"
32 #include "fd-util.h"
33 #include "format-table.h"
34 #include "format-util.h"
35 #include "geneve-util.h"
36 #include "glob-util.h"
37 #include "hwdb-util.h"
38 #include "ipvlan-util.h"
39 #include "local-addresses.h"
40 #include "locale-util.h"
41 #include "logs-show.h"
42 #include "macro.h"
43 #include "macvlan-util.h"
44 #include "main-func.h"
45 #include "netif-util.h"
46 #include "netlink-util.h"
47 #include "network-internal.h"
48 #include "network-util.h"
49 #include "pager.h"
50 #include "parse-argument.h"
51 #include "parse-util.h"
52 #include "pretty-print.h"
53 #include "set.h"
54 #include "socket-netlink.h"
55 #include "socket-util.h"
56 #include "sort-util.h"
57 #include "sparse-endian.h"
58 #include "stdio-util.h"
59 #include "string-table.h"
60 #include "string-util.h"
61 #include "strv.h"
62 #include "strxcpyx.h"
63 #include "terminal-util.h"
64 #include "unit-def.h"
65 #include "verbs.h"
66 #include "wifi-util.h"
67
68 /* Kernel defines MODULE_NAME_LEN as 64 - sizeof(unsigned long). So, 64 is enough. */
69 #define NETDEV_KIND_MAX 64
70
71 /* use 128 kB for receive socket kernel queue, we shouldn't need more here */
72 #define RCVBUF_SIZE (128*1024)
73
74 static PagerFlags arg_pager_flags = 0;
75 static bool arg_legend = true;
76 static bool arg_all = false;
77 static bool arg_stats = false;
78 static bool arg_full = false;
79 static unsigned arg_lines = 10;
80 static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
81
get_description(sd_bus * bus,JsonVariant ** ret)82 static int get_description(sd_bus *bus, JsonVariant **ret) {
83 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
84 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
85 const char *text = NULL;
86 int r;
87
88 r = bus_call_method(bus, bus_network_mgr, "Describe", &error, &reply, NULL);
89 if (r < 0)
90 return log_error_errno(r, "Failed to get description: %s", bus_error_message(&error, r));
91
92 r = sd_bus_message_read(reply, "s", &text);
93 if (r < 0)
94 return bus_log_parse_error(r);
95
96 r = json_parse(text, 0, ret, NULL, NULL);
97 if (r < 0)
98 return log_error_errno(r, "Failed to parse JSON: %m");
99
100 return 0;
101 }
102
dump_manager_description(sd_bus * bus)103 static int dump_manager_description(sd_bus *bus) {
104 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
105 int r;
106
107 r = get_description(bus, &v);
108 if (r < 0)
109 return r;
110
111 json_variant_dump(v, arg_json_format_flags, NULL, NULL);
112 return 0;
113 }
114
dump_link_description(sd_bus * bus,char ** patterns)115 static int dump_link_description(sd_bus *bus, char **patterns) {
116 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
117 _cleanup_free_ bool *matched_patterns = NULL;
118 JsonVariant *i;
119 size_t c = 0;
120 int r;
121
122 r = get_description(bus, &v);
123 if (r < 0)
124 return r;
125
126 matched_patterns = new0(bool, strv_length(patterns));
127 if (!matched_patterns)
128 return log_oom();
129
130 JSON_VARIANT_ARRAY_FOREACH(i, json_variant_by_key(v, "Interfaces")) {
131 char ifindex_str[DECIMAL_STR_MAX(int64_t)];
132 const char *name;
133 int64_t index;
134 size_t pos;
135
136 name = json_variant_string(json_variant_by_key(i, "Name"));
137 index = json_variant_integer(json_variant_by_key(i, "Index"));
138 xsprintf(ifindex_str, "%ji", index);
139
140 if (!strv_fnmatch_full(patterns, ifindex_str, 0, &pos) &&
141 !strv_fnmatch_full(patterns, name, 0, &pos)) {
142 bool match = false;
143 JsonVariant *a;
144
145 JSON_VARIANT_ARRAY_FOREACH(a, json_variant_by_key(i, "AlternativeNames"))
146 if (strv_fnmatch_full(patterns, json_variant_string(a), 0, &pos)) {
147 match = true;
148 break;
149 }
150
151 if (!match)
152 continue;
153 }
154
155 matched_patterns[pos] = true;
156 json_variant_dump(i, arg_json_format_flags, NULL, NULL);
157 c++;
158 }
159
160 /* Look if we matched all our arguments that are not globs. It is OK for a glob to match
161 * nothing, but not for an exact argument. */
162 for (size_t pos = 0; pos < strv_length(patterns); pos++) {
163 if (matched_patterns[pos])
164 continue;
165
166 if (string_is_glob(patterns[pos]))
167 log_debug("Pattern \"%s\" doesn't match any interface, ignoring.",
168 patterns[pos]);
169 else
170 return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
171 "Interface \"%s\" not found.", patterns[pos]);
172 }
173
174 if (c == 0)
175 log_warning("No interfaces matched.");
176
177 return 0;
178 }
179
operational_state_to_color(const char * name,const char * state,const char ** on,const char ** off)180 static void operational_state_to_color(const char *name, const char *state, const char **on, const char **off) {
181 if (STRPTR_IN_SET(state, "routable", "enslaved") ||
182 (streq_ptr(name, "lo") && streq_ptr(state, "carrier"))) {
183 if (on)
184 *on = ansi_highlight_green();
185 if (off)
186 *off = ansi_normal();
187 } else if (streq_ptr(state, "degraded")) {
188 if (on)
189 *on = ansi_highlight_yellow();
190 if (off)
191 *off = ansi_normal();
192 } else {
193 if (on)
194 *on = "";
195 if (off)
196 *off = "";
197 }
198 }
199
setup_state_to_color(const char * state,const char ** on,const char ** off)200 static void setup_state_to_color(const char *state, const char **on, const char **off) {
201 if (streq_ptr(state, "configured")) {
202 if (on)
203 *on = ansi_highlight_green();
204 if (off)
205 *off = ansi_normal();
206 } else if (streq_ptr(state, "configuring")) {
207 if (on)
208 *on = ansi_highlight_yellow();
209 if (off)
210 *off = ansi_normal();
211 } else if (STRPTR_IN_SET(state, "failed", "linger")) {
212 if (on)
213 *on = ansi_highlight_red();
214 if (off)
215 *off = ansi_normal();
216 } else {
217 if (on)
218 *on = "";
219 if (off)
220 *off = "";
221 }
222 }
223
online_state_to_color(const char * state,const char ** on,const char ** off)224 static void online_state_to_color(const char *state, const char **on, const char **off) {
225 if (streq_ptr(state, "online")) {
226 if (on)
227 *on = ansi_highlight_green();
228 if (off)
229 *off = ansi_normal();
230 } else if (streq_ptr(state, "partial")) {
231 if (on)
232 *on = ansi_highlight_yellow();
233 if (off)
234 *off = ansi_normal();
235 } else {
236 if (on)
237 *on = "";
238 if (off)
239 *off = "";
240 }
241 }
242
243 typedef struct VxLanInfo {
244 uint32_t vni;
245 uint32_t link;
246
247 int local_family;
248 int group_family;
249
250 union in_addr_union local;
251 union in_addr_union group;
252
253 uint16_t dest_port;
254
255 uint8_t proxy;
256 uint8_t learning;
257 uint8_t rsc;
258 uint8_t l2miss;
259 uint8_t l3miss;
260 uint8_t tos;
261 uint8_t ttl;
262 } VxLanInfo;
263
264 typedef struct LinkInfo {
265 char name[IFNAMSIZ+1];
266 char *netdev_kind;
267 sd_device *sd_device;
268 int ifindex;
269 unsigned short iftype;
270 struct hw_addr_data hw_address;
271 struct hw_addr_data permanent_hw_address;
272 uint32_t master;
273 uint32_t mtu;
274 uint32_t min_mtu;
275 uint32_t max_mtu;
276 uint32_t tx_queues;
277 uint32_t rx_queues;
278 uint8_t addr_gen_mode;
279 char *qdisc;
280 char **alternative_names;
281
282 union {
283 struct rtnl_link_stats64 stats64;
284 struct rtnl_link_stats stats;
285 };
286
287 uint64_t tx_bitrate;
288 uint64_t rx_bitrate;
289
290 /* bridge info */
291 uint32_t forward_delay;
292 uint32_t hello_time;
293 uint32_t max_age;
294 uint32_t ageing_time;
295 uint32_t stp_state;
296 uint32_t cost;
297 uint16_t priority;
298 uint8_t mcast_igmp_version;
299 uint8_t port_state;
300
301 /* vxlan info */
302 VxLanInfo vxlan_info;
303
304 /* vlan info */
305 uint16_t vlan_id;
306
307 /* tunnel info */
308 uint8_t ttl;
309 uint8_t tos;
310 uint8_t inherit;
311 uint8_t df;
312 uint8_t csum;
313 uint8_t csum6_tx;
314 uint8_t csum6_rx;
315 uint16_t tunnel_port;
316 uint32_t vni;
317 uint32_t label;
318 union in_addr_union local;
319 union in_addr_union remote;
320
321 /* bonding info */
322 uint8_t mode;
323 uint32_t miimon;
324 uint32_t updelay;
325 uint32_t downdelay;
326
327 /* macvlan and macvtap info */
328 uint32_t macvlan_mode;
329
330 /* ipvlan info */
331 uint16_t ipvlan_mode;
332 uint16_t ipvlan_flags;
333
334 /* ethtool info */
335 int autonegotiation;
336 uint64_t speed;
337 Duplex duplex;
338 NetDevPort port;
339
340 /* wlan info */
341 enum nl80211_iftype wlan_iftype;
342 char *ssid;
343 struct ether_addr bssid;
344
345 bool has_hw_address:1;
346 bool has_permanent_hw_address:1;
347 bool has_tx_queues:1;
348 bool has_rx_queues:1;
349 bool has_stats64:1;
350 bool has_stats:1;
351 bool has_bitrates:1;
352 bool has_ethtool_link_info:1;
353 bool has_wlan_link_info:1;
354 bool has_tunnel_ipv4:1;
355 bool has_ipv6_address_generation_mode:1;
356
357 bool needs_freeing:1;
358 } LinkInfo;
359
link_info_compare(const LinkInfo * a,const LinkInfo * b)360 static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
361 return CMP(a->ifindex, b->ifindex);
362 }
363
link_info_array_free(LinkInfo * array)364 static LinkInfo* link_info_array_free(LinkInfo *array) {
365 for (unsigned i = 0; array && array[i].needs_freeing; i++) {
366 sd_device_unref(array[i].sd_device);
367 free(array[i].netdev_kind);
368 free(array[i].ssid);
369 free(array[i].qdisc);
370 strv_free(array[i].alternative_names);
371 }
372
373 return mfree(array);
374 }
375 DEFINE_TRIVIAL_CLEANUP_FUNC(LinkInfo*, link_info_array_free);
376
decode_netdev(sd_netlink_message * m,LinkInfo * info)377 static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
378 int r;
379
380 assert(m);
381 assert(info);
382
383 r = sd_netlink_message_enter_container(m, IFLA_LINKINFO);
384 if (r < 0)
385 return r;
386
387 r = sd_netlink_message_read_string_strdup(m, IFLA_INFO_KIND, &info->netdev_kind);
388 if (r < 0) {
389 (void) sd_netlink_message_exit_container(m);
390 return r;
391 }
392
393 r = sd_netlink_message_enter_container(m, IFLA_INFO_DATA);
394 if (r < 0)
395 return r;
396
397 if (streq(info->netdev_kind, "bridge")) {
398 (void) sd_netlink_message_read_u32(m, IFLA_BR_FORWARD_DELAY, &info->forward_delay);
399 (void) sd_netlink_message_read_u32(m, IFLA_BR_HELLO_TIME, &info->hello_time);
400 (void) sd_netlink_message_read_u32(m, IFLA_BR_MAX_AGE, &info->max_age);
401 (void) sd_netlink_message_read_u32(m, IFLA_BR_AGEING_TIME, &info->ageing_time);
402 (void) sd_netlink_message_read_u32(m, IFLA_BR_STP_STATE, &info->stp_state);
403 (void) sd_netlink_message_read_u32(m, IFLA_BRPORT_COST, &info->cost);
404 (void) sd_netlink_message_read_u16(m, IFLA_BR_PRIORITY, &info->priority);
405 (void) sd_netlink_message_read_u8(m, IFLA_BR_MCAST_IGMP_VERSION, &info->mcast_igmp_version);
406 (void) sd_netlink_message_read_u8(m, IFLA_BRPORT_STATE, &info->port_state);
407 } if (streq(info->netdev_kind, "bond")) {
408 (void) sd_netlink_message_read_u8(m, IFLA_BOND_MODE, &info->mode);
409 (void) sd_netlink_message_read_u32(m, IFLA_BOND_MIIMON, &info->miimon);
410 (void) sd_netlink_message_read_u32(m, IFLA_BOND_DOWNDELAY, &info->downdelay);
411 (void) sd_netlink_message_read_u32(m, IFLA_BOND_UPDELAY, &info->updelay);
412 } else if (streq(info->netdev_kind, "vxlan")) {
413 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_ID, &info->vxlan_info.vni);
414
415 r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_GROUP, &info->vxlan_info.group.in);
416 if (r >= 0)
417 info->vxlan_info.group_family = AF_INET;
418 else {
419 r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_GROUP6, &info->vxlan_info.group.in6);
420 if (r >= 0)
421 info->vxlan_info.group_family = AF_INET6;
422 }
423
424 r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_LOCAL, &info->vxlan_info.local.in);
425 if (r >= 0)
426 info->vxlan_info.local_family = AF_INET;
427 else {
428 r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_LOCAL6, &info->vxlan_info.local.in6);
429 if (r >= 0)
430 info->vxlan_info.local_family = AF_INET6;
431 }
432
433 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_LINK, &info->vxlan_info.link);
434 (void) sd_netlink_message_read_u16(m, IFLA_VXLAN_PORT, &info->vxlan_info.dest_port);
435 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_PROXY, &info->vxlan_info.proxy);
436 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_LEARNING, &info->vxlan_info.learning);
437 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_RSC, &info->vxlan_info.rsc);
438 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L3MISS, &info->vxlan_info.l3miss);
439 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L2MISS, &info->vxlan_info.l2miss);
440 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TOS, &info->vxlan_info.tos);
441 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TTL, &info->vxlan_info.ttl);
442 } else if (streq(info->netdev_kind, "vlan"))
443 (void) sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &info->vlan_id);
444 else if (STR_IN_SET(info->netdev_kind, "ipip", "sit")) {
445 (void) sd_netlink_message_read_in_addr(m, IFLA_IPTUN_LOCAL, &info->local.in);
446 (void) sd_netlink_message_read_in_addr(m, IFLA_IPTUN_REMOTE, &info->remote.in);
447 } else if (streq(info->netdev_kind, "geneve")) {
448 (void) sd_netlink_message_read_u32(m, IFLA_GENEVE_ID, &info->vni);
449
450 r = sd_netlink_message_read_in_addr(m, IFLA_GENEVE_REMOTE, &info->remote.in);
451 if (r >= 0)
452 info->has_tunnel_ipv4 = true;
453 else
454 (void) sd_netlink_message_read_in6_addr(m, IFLA_GENEVE_REMOTE6, &info->remote.in6);
455
456 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_TTL, &info->ttl);
457 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_TTL_INHERIT, &info->inherit);
458 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_TOS, &info->tos);
459 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_DF, &info->df);
460 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_UDP_CSUM, &info->csum);
461 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, &info->csum6_tx);
462 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, &info->csum6_rx);
463 (void) sd_netlink_message_read_u16(m, IFLA_GENEVE_PORT, &info->tunnel_port);
464 (void) sd_netlink_message_read_u32(m, IFLA_GENEVE_LABEL, &info->label);
465 } else if (STR_IN_SET(info->netdev_kind, "gre", "gretap", "erspan")) {
466 (void) sd_netlink_message_read_in_addr(m, IFLA_GRE_LOCAL, &info->local.in);
467 (void) sd_netlink_message_read_in_addr(m, IFLA_GRE_REMOTE, &info->remote.in);
468 } else if (STR_IN_SET(info->netdev_kind, "ip6gre", "ip6gretap", "ip6erspan")) {
469 (void) sd_netlink_message_read_in6_addr(m, IFLA_GRE_LOCAL, &info->local.in6);
470 (void) sd_netlink_message_read_in6_addr(m, IFLA_GRE_REMOTE, &info->remote.in6);
471 } else if (streq(info->netdev_kind, "vti")) {
472 (void) sd_netlink_message_read_in_addr(m, IFLA_VTI_LOCAL, &info->local.in);
473 (void) sd_netlink_message_read_in_addr(m, IFLA_VTI_REMOTE, &info->remote.in);
474 } else if (streq(info->netdev_kind, "vti6")) {
475 (void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_LOCAL, &info->local.in6);
476 (void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_REMOTE, &info->remote.in6);
477 } else if (STR_IN_SET(info->netdev_kind, "macvlan", "macvtap"))
478 (void) sd_netlink_message_read_u32(m, IFLA_MACVLAN_MODE, &info->macvlan_mode);
479 else if (streq(info->netdev_kind, "ipvlan")) {
480 (void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_MODE, &info->ipvlan_mode);
481 (void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_FLAGS, &info->ipvlan_flags);
482 }
483
484 (void) sd_netlink_message_exit_container(m);
485 (void) sd_netlink_message_exit_container(m);
486
487 return 0;
488 }
489
decode_link(sd_netlink_message * m,LinkInfo * info,char ** patterns,bool matched_patterns[])490 static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns, bool matched_patterns[]) {
491 _cleanup_strv_free_ char **altnames = NULL;
492 const char *name, *qdisc;
493 int ifindex, r;
494 uint16_t type;
495
496 assert(m);
497 assert(info);
498
499 r = sd_netlink_message_get_type(m, &type);
500 if (r < 0)
501 return r;
502
503 if (type != RTM_NEWLINK)
504 return 0;
505
506 r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
507 if (r < 0)
508 return r;
509
510 r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name);
511 if (r < 0)
512 return r;
513
514 r = sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &altnames);
515 if (r < 0 && r != -ENODATA)
516 return r;
517
518 if (patterns) {
519 char str[DECIMAL_STR_MAX(int)];
520 size_t pos;
521
522 assert(matched_patterns);
523
524 xsprintf(str, "%i", ifindex);
525 if (!strv_fnmatch_full(patterns, str, 0, &pos) &&
526 !strv_fnmatch_full(patterns, name, 0, &pos)) {
527 bool match = false;
528
529 STRV_FOREACH(p, altnames)
530 if (strv_fnmatch_full(patterns, *p, 0, &pos)) {
531 match = true;
532 break;
533 }
534 if (!match)
535 return 0;
536 }
537
538 matched_patterns[pos] = true;
539 }
540
541 r = sd_rtnl_message_link_get_type(m, &info->iftype);
542 if (r < 0)
543 return r;
544
545 strscpy(info->name, sizeof info->name, name);
546 info->ifindex = ifindex;
547 info->alternative_names = TAKE_PTR(altnames);
548
549 info->has_hw_address =
550 netlink_message_read_hw_addr(m, IFLA_ADDRESS, &info->hw_address) >= 0 &&
551 info->hw_address.length > 0;
552
553 info->has_permanent_hw_address =
554 (netlink_message_read_hw_addr(m, IFLA_PERM_ADDRESS, &info->permanent_hw_address) >= 0 ||
555 ethtool_get_permanent_hw_addr(NULL, info->name, &info->permanent_hw_address) >= 0) &&
556 !hw_addr_is_null(&info->permanent_hw_address) &&
557 !hw_addr_equal(&info->permanent_hw_address, &info->hw_address);
558
559 (void) sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu);
560 (void) sd_netlink_message_read_u32(m, IFLA_MIN_MTU, &info->min_mtu);
561 (void) sd_netlink_message_read_u32(m, IFLA_MAX_MTU, &info->max_mtu);
562
563 info->has_rx_queues =
564 sd_netlink_message_read_u32(m, IFLA_NUM_RX_QUEUES, &info->rx_queues) >= 0 &&
565 info->rx_queues > 0;
566
567 info->has_tx_queues =
568 sd_netlink_message_read_u32(m, IFLA_NUM_TX_QUEUES, &info->tx_queues) >= 0 &&
569 info->tx_queues > 0;
570
571 if (sd_netlink_message_read(m, IFLA_STATS64, sizeof info->stats64, &info->stats64) >= 0)
572 info->has_stats64 = true;
573 else if (sd_netlink_message_read(m, IFLA_STATS, sizeof info->stats, &info->stats) >= 0)
574 info->has_stats = true;
575
576 r = sd_netlink_message_read_string(m, IFLA_QDISC, &qdisc);
577 if (r >= 0) {
578 info->qdisc = strdup(qdisc);
579 if (!info->qdisc)
580 return log_oom();
581 }
582
583 (void) sd_netlink_message_read_u32(m, IFLA_MASTER, &info->master);
584
585 r = sd_netlink_message_enter_container(m, IFLA_AF_SPEC);
586 if (r >= 0) {
587 r = sd_netlink_message_enter_container(m, AF_INET6);
588 if (r >= 0) {
589 r = sd_netlink_message_read_u8(m, IFLA_INET6_ADDR_GEN_MODE, &info->addr_gen_mode);
590 if (r >= 0 && IN_SET(info->addr_gen_mode,
591 IN6_ADDR_GEN_MODE_EUI64,
592 IN6_ADDR_GEN_MODE_NONE,
593 IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
594 IN6_ADDR_GEN_MODE_RANDOM))
595 info->has_ipv6_address_generation_mode = true;
596
597 (void) sd_netlink_message_exit_container(m);
598 }
599 (void) sd_netlink_message_exit_container(m);
600 }
601
602 /* fill kind info */
603 (void) decode_netdev(m, info);
604
605 return 1;
606 }
607
link_get_property(sd_bus * bus,const LinkInfo * link,sd_bus_error * error,sd_bus_message ** reply,const char * iface,const char * propname)608 static int link_get_property(
609 sd_bus *bus,
610 const LinkInfo *link,
611 sd_bus_error *error,
612 sd_bus_message **reply,
613 const char *iface,
614 const char *propname) {
615
616 char ifindex_str[DECIMAL_STR_MAX(int)];
617 _cleanup_free_ char *path = NULL;
618 int r;
619
620 xsprintf(ifindex_str, "%i", link->ifindex);
621
622 r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex_str, &path);
623 if (r < 0)
624 return r;
625
626 return sd_bus_call_method(
627 bus,
628 "org.freedesktop.network1",
629 path,
630 "org.freedesktop.DBus.Properties",
631 "Get",
632 error,
633 reply,
634 "ss",
635 iface,
636 propname);
637 }
638
acquire_link_bitrates(sd_bus * bus,LinkInfo * link)639 static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
640 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
641 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
642 int r;
643
644 r = link_get_property(bus, link, &error, &reply, "org.freedesktop.network1.Link", "BitRates");
645 if (r < 0) {
646 bool quiet = sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY,
647 BUS_ERROR_SPEED_METER_INACTIVE);
648
649 return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING,
650 r, "Failed to query link bit rates: %s", bus_error_message(&error, r));
651 }
652
653 r = sd_bus_message_enter_container(reply, 'v', "(tt)");
654 if (r < 0)
655 return bus_log_parse_error(r);
656
657 r = sd_bus_message_read(reply, "(tt)", &link->tx_bitrate, &link->rx_bitrate);
658 if (r < 0)
659 return bus_log_parse_error(r);
660
661 r = sd_bus_message_exit_container(reply);
662 if (r < 0)
663 return bus_log_parse_error(r);
664
665 link->has_bitrates = link->tx_bitrate != UINT64_MAX && link->rx_bitrate != UINT64_MAX;
666
667 return 0;
668 }
669
acquire_ether_link_info(int * fd,LinkInfo * link)670 static void acquire_ether_link_info(int *fd, LinkInfo *link) {
671 if (ethtool_get_link_info(fd, link->name,
672 &link->autonegotiation,
673 &link->speed,
674 &link->duplex,
675 &link->port) >= 0)
676 link->has_ethtool_link_info = true;
677 }
678
acquire_wlan_link_info(LinkInfo * link)679 static void acquire_wlan_link_info(LinkInfo *link) {
680 _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
681 const char *type = NULL;
682 int r, k = 0;
683
684 if (link->sd_device)
685 (void) sd_device_get_devtype(link->sd_device, &type);
686 if (!streq_ptr(type, "wlan"))
687 return;
688
689 r = sd_genl_socket_open(&genl);
690 if (r < 0) {
691 log_debug_errno(r, "Failed to open generic netlink socket: %m");
692 return;
693 }
694
695 (void) sd_netlink_inc_rcvbuf(genl, RCVBUF_SIZE);
696
697 r = wifi_get_interface(genl, link->ifindex, &link->wlan_iftype, &link->ssid);
698 if (r < 0)
699 log_debug_errno(r, "%s: failed to query ssid: %m", link->name);
700
701 if (link->wlan_iftype == NL80211_IFTYPE_STATION) {
702 k = wifi_get_station(genl, link->ifindex, &link->bssid);
703 if (k < 0)
704 log_debug_errno(k, "%s: failed to query bssid: %m", link->name);
705 }
706
707 link->has_wlan_link_info = r > 0 || k > 0;
708 }
709
acquire_link_info(sd_bus * bus,sd_netlink * rtnl,char ** patterns,LinkInfo ** ret)710 static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
711 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
712 _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
713 _cleanup_close_ int fd = -1;
714 size_t c = 0;
715 int r;
716
717 assert(rtnl);
718 assert(ret);
719
720 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
721 if (r < 0)
722 return rtnl_log_create_error(r);
723
724 r = sd_netlink_message_request_dump(req, true);
725 if (r < 0)
726 return rtnl_log_create_error(r);
727
728 r = sd_netlink_call(rtnl, req, 0, &reply);
729 if (r < 0)
730 return log_error_errno(r, "Failed to enumerate links: %m");
731
732 _cleanup_free_ bool *matched_patterns = NULL;
733 if (patterns) {
734 matched_patterns = new0(bool, strv_length(patterns));
735 if (!matched_patterns)
736 return log_oom();
737 }
738
739 for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) {
740 if (!GREEDY_REALLOC0(links, c + 2)) /* We keep one trailing one as marker */
741 return -ENOMEM;
742
743 r = decode_link(i, links + c, patterns, matched_patterns);
744 if (r < 0)
745 return r;
746 if (r == 0)
747 continue;
748
749 links[c].needs_freeing = true;
750
751 (void) sd_device_new_from_ifindex(&links[c].sd_device, links[c].ifindex);
752
753 acquire_ether_link_info(&fd, &links[c]);
754 acquire_wlan_link_info(&links[c]);
755
756 c++;
757 }
758
759 /* Look if we matched all our arguments that are not globs. It
760 * is OK for a glob to match nothing, but not for an exact argument. */
761 for (size_t pos = 0; pos < strv_length(patterns); pos++) {
762 if (matched_patterns[pos])
763 continue;
764
765 if (string_is_glob(patterns[pos]))
766 log_debug("Pattern \"%s\" doesn't match any interface, ignoring.",
767 patterns[pos]);
768 else
769 return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
770 "Interface \"%s\" not found.", patterns[pos]);
771 }
772
773 typesafe_qsort(links, c, link_info_compare);
774
775 if (bus)
776 for (size_t j = 0; j < c; j++)
777 (void) acquire_link_bitrates(bus, links + j);
778
779 *ret = TAKE_PTR(links);
780
781 if (patterns && c == 0)
782 log_warning("No interfaces matched.");
783
784 return (int) c;
785 }
786
list_links(int argc,char * argv[],void * userdata)787 static int list_links(int argc, char *argv[], void *userdata) {
788 sd_bus *bus = ASSERT_PTR(userdata);
789 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
790 _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
791 _cleanup_(table_unrefp) Table *table = NULL;
792 TableCell *cell;
793 int c, r;
794
795 if (arg_json_format_flags != JSON_FORMAT_OFF) {
796 if (arg_all || argc <= 1)
797 return dump_manager_description(bus);
798 else
799 return dump_link_description(bus, strv_skip(argv, 1));
800 }
801
802 r = sd_netlink_open(&rtnl);
803 if (r < 0)
804 return log_error_errno(r, "Failed to connect to netlink: %m");
805
806 c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
807 if (c < 0)
808 return c;
809
810 pager_open(arg_pager_flags);
811
812 table = table_new("idx", "link", "type", "operational", "setup");
813 if (!table)
814 return log_oom();
815
816 if (arg_full)
817 table_set_width(table, 0);
818
819 table_set_header(table, arg_legend);
820 if (table_set_empty_string(table, "n/a") < 0)
821 return log_oom();
822
823 assert_se(cell = table_get_cell(table, 0, 0));
824 (void) table_set_minimum_width(table, cell, 3);
825 (void) table_set_weight(table, cell, 0);
826 (void) table_set_ellipsize_percent(table, cell, 100);
827 (void) table_set_align_percent(table, cell, 100);
828
829 assert_se(cell = table_get_cell(table, 0, 1));
830 (void) table_set_ellipsize_percent(table, cell, 100);
831
832 for (int i = 0; i < c; i++) {
833 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
834 const char *on_color_operational, *on_color_setup;
835 _cleanup_free_ char *t = NULL;
836
837 (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
838 operational_state_to_color(links[i].name, operational_state, &on_color_operational, NULL);
839
840 r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
841 if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
842 setup_state = strdup("unmanaged");
843 setup_state_to_color(setup_state, &on_color_setup, NULL);
844
845 r = net_get_type_string(links[i].sd_device, links[i].iftype, &t);
846 if (r == -ENOMEM)
847 return log_oom();
848
849 r = table_add_many(table,
850 TABLE_INT, links[i].ifindex,
851 TABLE_STRING, links[i].name,
852 TABLE_STRING, t,
853 TABLE_STRING, operational_state,
854 TABLE_SET_COLOR, on_color_operational,
855 TABLE_STRING, setup_state,
856 TABLE_SET_COLOR, on_color_setup);
857 if (r < 0)
858 return table_log_add_error(r);
859 }
860
861 r = table_print(table, NULL);
862 if (r < 0)
863 return table_log_print_error(r);
864
865 if (arg_legend)
866 printf("\n%i links listed.\n", c);
867
868 return 0;
869 }
870
871 /* IEEE Organizationally Unique Identifier vendor string */
ieee_oui(sd_hwdb * hwdb,const struct ether_addr * mac,char ** ret)872 static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) {
873 const char *description;
874 char modalias[STRLEN("OUI:XXYYXXYYXXYY") + 1], *desc;
875 int r;
876
877 assert(ret);
878
879 if (!hwdb)
880 return -EINVAL;
881
882 if (!mac)
883 return -EINVAL;
884
885 /* skip commonly misused 00:00:00 (Xerox) prefix */
886 if (memcmp(mac, "\0\0\0", 3) == 0)
887 return -EINVAL;
888
889 xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR,
890 ETHER_ADDR_FORMAT_VAL(*mac));
891
892 r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
893 if (r < 0)
894 return r;
895
896 desc = strdup(description);
897 if (!desc)
898 return -ENOMEM;
899
900 *ret = desc;
901
902 return 0;
903 }
904
get_gateway_description(sd_netlink * rtnl,sd_hwdb * hwdb,int ifindex,int family,union in_addr_union * gateway,char ** gateway_description)905 static int get_gateway_description(
906 sd_netlink *rtnl,
907 sd_hwdb *hwdb,
908 int ifindex,
909 int family,
910 union in_addr_union *gateway,
911 char **gateway_description) {
912 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
913 int r;
914
915 assert(rtnl);
916 assert(ifindex >= 0);
917 assert(IN_SET(family, AF_INET, AF_INET6));
918 assert(gateway);
919 assert(gateway_description);
920
921 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
922 if (r < 0)
923 return r;
924
925 r = sd_netlink_message_request_dump(req, true);
926 if (r < 0)
927 return r;
928
929 r = sd_netlink_call(rtnl, req, 0, &reply);
930 if (r < 0)
931 return r;
932
933 for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
934 union in_addr_union gw = IN_ADDR_NULL;
935 struct ether_addr mac = ETHER_ADDR_NULL;
936 uint16_t type;
937 int ifi, fam;
938
939 r = sd_netlink_message_get_errno(m);
940 if (r < 0) {
941 log_error_errno(r, "got error: %m");
942 continue;
943 }
944
945 r = sd_netlink_message_get_type(m, &type);
946 if (r < 0) {
947 log_error_errno(r, "could not get type: %m");
948 continue;
949 }
950
951 if (type != RTM_NEWNEIGH) {
952 log_error("type is not RTM_NEWNEIGH");
953 continue;
954 }
955
956 r = sd_rtnl_message_neigh_get_family(m, &fam);
957 if (r < 0) {
958 log_error_errno(r, "could not get family: %m");
959 continue;
960 }
961
962 if (fam != family) {
963 log_error("family is not correct");
964 continue;
965 }
966
967 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
968 if (r < 0) {
969 log_error_errno(r, "could not get ifindex: %m");
970 continue;
971 }
972
973 if (ifindex > 0 && ifi != ifindex)
974 continue;
975
976 switch (fam) {
977 case AF_INET:
978 r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in);
979 if (r < 0)
980 continue;
981
982 break;
983 case AF_INET6:
984 r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6);
985 if (r < 0)
986 continue;
987
988 break;
989 default:
990 continue;
991 }
992
993 if (!in_addr_equal(fam, &gw, gateway))
994 continue;
995
996 r = sd_netlink_message_read(m, NDA_LLADDR, sizeof(mac), &mac);
997 if (r < 0)
998 continue;
999
1000 r = ieee_oui(hwdb, &mac, gateway_description);
1001 if (r < 0)
1002 continue;
1003
1004 return 0;
1005 }
1006
1007 return -ENODATA;
1008 }
1009
dump_list(Table * table,const char * prefix,char * const * l)1010 static int dump_list(Table *table, const char *prefix, char * const *l) {
1011 int r;
1012
1013 if (strv_isempty(l))
1014 return 0;
1015
1016 r = table_add_many(table,
1017 TABLE_EMPTY,
1018 TABLE_STRING, prefix,
1019 TABLE_STRV, l);
1020 if (r < 0)
1021 return table_log_add_error(r);
1022
1023 return 0;
1024 }
1025
dump_gateways(sd_netlink * rtnl,sd_hwdb * hwdb,Table * table,int ifindex)1026 static int dump_gateways(
1027 sd_netlink *rtnl,
1028 sd_hwdb *hwdb,
1029 Table *table,
1030 int ifindex) {
1031 _cleanup_free_ struct local_address *local = NULL;
1032 _cleanup_strv_free_ char **buf = NULL;
1033 int r, n;
1034
1035 assert(rtnl);
1036 assert(table);
1037
1038 n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
1039 if (n <= 0)
1040 return n;
1041
1042 for (int i = 0; i < n; i++) {
1043 _cleanup_free_ char *gateway = NULL, *description = NULL;
1044
1045 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
1046 if (r < 0)
1047 return log_oom();
1048
1049 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
1050 if (r < 0)
1051 log_debug_errno(r, "Could not get description of gateway, ignoring: %m");
1052
1053 if (description) {
1054 if (!strextend(&gateway, " (", description, ")"))
1055 return log_oom();
1056 }
1057
1058 /* Show interface name for the entry if we show entries for all interfaces */
1059 r = strv_extendf(&buf, "%s%s%s",
1060 gateway,
1061 ifindex <= 0 ? " on " : "",
1062 ifindex <= 0 ? FORMAT_IFNAME_FULL(local[i].ifindex, FORMAT_IFNAME_IFINDEX_WITH_PERCENT) : "");
1063 if (r < 0)
1064 return log_oom();
1065 }
1066
1067 return dump_list(table, "Gateway:", buf);
1068 }
1069
dump_addresses(sd_netlink * rtnl,sd_dhcp_lease * lease,Table * table,int ifindex)1070 static int dump_addresses(
1071 sd_netlink *rtnl,
1072 sd_dhcp_lease *lease,
1073 Table *table,
1074 int ifindex) {
1075
1076 _cleanup_free_ struct local_address *local = NULL;
1077 _cleanup_strv_free_ char **buf = NULL;
1078 struct in_addr dhcp4_address = {};
1079 int r, n;
1080
1081 assert(rtnl);
1082 assert(table);
1083
1084 n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
1085 if (n <= 0)
1086 return n;
1087
1088 if (lease)
1089 (void) sd_dhcp_lease_get_address(lease, &dhcp4_address);
1090
1091 for (int i = 0; i < n; i++) {
1092 _cleanup_free_ char *pretty = NULL;
1093
1094 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
1095 if (r < 0)
1096 return r;
1097
1098 if (local[i].family == AF_INET && in4_addr_equal(&local[i].address.in, &dhcp4_address)) {
1099 struct in_addr server_address;
1100 char *p, s[INET_ADDRSTRLEN];
1101
1102 r = sd_dhcp_lease_get_server_identifier(lease, &server_address);
1103 if (r >= 0 && inet_ntop(AF_INET, &server_address, s, sizeof(s)))
1104 p = strjoin(pretty, " (DHCP4 via ", s, ")");
1105 else
1106 p = strjoin(pretty, " (DHCP4)");
1107 if (!p)
1108 return log_oom();
1109
1110 free_and_replace(pretty, p);
1111 }
1112
1113 r = strv_extendf(&buf, "%s%s%s",
1114 pretty,
1115 ifindex <= 0 ? " on " : "",
1116 ifindex <= 0 ? FORMAT_IFNAME_FULL(local[i].ifindex, FORMAT_IFNAME_IFINDEX_WITH_PERCENT) : "");
1117 if (r < 0)
1118 return log_oom();
1119 }
1120
1121 return dump_list(table, "Address:", buf);
1122 }
1123
dump_address_labels(sd_netlink * rtnl)1124 static int dump_address_labels(sd_netlink *rtnl) {
1125 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
1126 _cleanup_(table_unrefp) Table *table = NULL;
1127 TableCell *cell;
1128 int r;
1129
1130 assert(rtnl);
1131
1132 r = sd_rtnl_message_new_addrlabel(rtnl, &req, RTM_GETADDRLABEL, 0, AF_INET6);
1133 if (r < 0)
1134 return log_error_errno(r, "Could not allocate RTM_GETADDRLABEL message: %m");
1135
1136 r = sd_netlink_message_request_dump(req, true);
1137 if (r < 0)
1138 return r;
1139
1140 r = sd_netlink_call(rtnl, req, 0, &reply);
1141 if (r < 0)
1142 return r;
1143
1144 table = table_new("label", "prefix/prefixlen");
1145 if (!table)
1146 return log_oom();
1147
1148 if (arg_full)
1149 table_set_width(table, 0);
1150
1151 r = table_set_sort(table, (size_t) 0);
1152 if (r < 0)
1153 return r;
1154
1155 assert_se(cell = table_get_cell(table, 0, 0));
1156 (void) table_set_align_percent(table, cell, 100);
1157 (void) table_set_ellipsize_percent(table, cell, 100);
1158
1159 assert_se(cell = table_get_cell(table, 0, 1));
1160 (void) table_set_align_percent(table, cell, 100);
1161
1162 for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
1163 _cleanup_free_ char *pretty = NULL;
1164 union in_addr_union prefix = IN_ADDR_NULL;
1165 uint8_t prefixlen;
1166 uint32_t label;
1167
1168 r = sd_netlink_message_get_errno(m);
1169 if (r < 0) {
1170 log_error_errno(r, "got error: %m");
1171 continue;
1172 }
1173
1174 r = sd_netlink_message_read_u32(m, IFAL_LABEL, &label);
1175 if (r < 0 && r != -ENODATA) {
1176 log_error_errno(r, "Could not read IFAL_LABEL, ignoring: %m");
1177 continue;
1178 }
1179
1180 r = sd_netlink_message_read_in6_addr(m, IFAL_ADDRESS, &prefix.in6);
1181 if (r < 0)
1182 continue;
1183
1184 r = in_addr_to_string(AF_INET6, &prefix, &pretty);
1185 if (r < 0)
1186 continue;
1187
1188 r = sd_rtnl_message_addrlabel_get_prefixlen(m, &prefixlen);
1189 if (r < 0)
1190 continue;
1191
1192 r = table_add_cell(table, NULL, TABLE_UINT32, &label);
1193 if (r < 0)
1194 return table_log_add_error(r);
1195
1196 r = table_add_cell_stringf(table, NULL, "%s/%u", pretty, prefixlen);
1197 if (r < 0)
1198 return table_log_add_error(r);
1199 }
1200
1201 r = table_print(table, NULL);
1202 if (r < 0)
1203 return table_log_print_error(r);
1204
1205 return 0;
1206 }
1207
list_address_labels(int argc,char * argv[],void * userdata)1208 static int list_address_labels(int argc, char *argv[], void *userdata) {
1209 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
1210 int r;
1211
1212 r = sd_netlink_open(&rtnl);
1213 if (r < 0)
1214 return log_error_errno(r, "Failed to connect to netlink: %m");
1215
1216 dump_address_labels(rtnl);
1217
1218 return 0;
1219 }
1220
open_lldp_neighbors(int ifindex,FILE ** ret)1221 static int open_lldp_neighbors(int ifindex, FILE **ret) {
1222 char p[STRLEN("/run/systemd/netif/lldp/") + DECIMAL_STR_MAX(int)];
1223 FILE *f;
1224
1225 xsprintf(p, "/run/systemd/netif/lldp/%i", ifindex);
1226 f = fopen(p, "re");
1227 if (!f)
1228 return -errno;
1229
1230 *ret = f;
1231 return 0;
1232 }
1233
next_lldp_neighbor(FILE * f,sd_lldp_neighbor ** ret)1234 static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) {
1235 _cleanup_free_ void *raw = NULL;
1236 size_t l;
1237 le64_t u;
1238 int r;
1239
1240 assert(f);
1241 assert(ret);
1242
1243 l = fread(&u, 1, sizeof(u), f);
1244 if (l == 0 && feof(f))
1245 return 0;
1246 if (l != sizeof(u))
1247 return -EBADMSG;
1248
1249 /* each LLDP packet is at most MTU size, but let's allow up to 4KiB just in case */
1250 if (le64toh(u) >= 4096)
1251 return -EBADMSG;
1252
1253 raw = new(uint8_t, le64toh(u));
1254 if (!raw)
1255 return -ENOMEM;
1256
1257 if (fread(raw, 1, le64toh(u), f) != le64toh(u))
1258 return -EBADMSG;
1259
1260 r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u));
1261 if (r < 0)
1262 return r;
1263
1264 return 1;
1265 }
1266
dump_lldp_neighbors(Table * table,const char * prefix,int ifindex)1267 static int dump_lldp_neighbors(Table *table, const char *prefix, int ifindex) {
1268 _cleanup_strv_free_ char **buf = NULL;
1269 _cleanup_fclose_ FILE *f = NULL;
1270 int r;
1271
1272 assert(table);
1273 assert(prefix);
1274 assert(ifindex > 0);
1275
1276 r = open_lldp_neighbors(ifindex, &f);
1277 if (r == -ENOENT)
1278 return 0;
1279 if (r < 0)
1280 return r;
1281
1282 for (;;) {
1283 const char *system_name = NULL, *port_id = NULL, *port_description = NULL;
1284 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
1285
1286 r = next_lldp_neighbor(f, &n);
1287 if (r < 0)
1288 return r;
1289 if (r == 0)
1290 break;
1291
1292 (void) sd_lldp_neighbor_get_system_name(n, &system_name);
1293 (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
1294 (void) sd_lldp_neighbor_get_port_description(n, &port_description);
1295
1296 r = strv_extendf(&buf, "%s on port %s%s%s%s",
1297 strna(system_name),
1298 strna(port_id),
1299 isempty(port_description) ? "" : " (",
1300 strempty(port_description),
1301 isempty(port_description) ? "" : ")");
1302 if (r < 0)
1303 return log_oom();
1304 }
1305
1306 return dump_list(table, prefix, buf);
1307 }
1308
dump_dhcp_leases(Table * table,const char * prefix,sd_bus * bus,const LinkInfo * link)1309 static int dump_dhcp_leases(Table *table, const char *prefix, sd_bus *bus, const LinkInfo *link) {
1310 _cleanup_strv_free_ char **buf = NULL;
1311 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1312 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1313 int r;
1314
1315 r = link_get_property(bus, link, &error, &reply, "org.freedesktop.network1.DHCPServer", "Leases");
1316 if (r < 0) {
1317 bool quiet = sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY);
1318
1319 log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING,
1320 r, "Failed to query link DHCP leases: %s", bus_error_message(&error, r));
1321 return 0;
1322 }
1323
1324 r = sd_bus_message_enter_container(reply, 'v', "a(uayayayayt)");
1325 if (r < 0)
1326 return bus_log_parse_error(r);
1327
1328 r = sd_bus_message_enter_container(reply, 'a', "(uayayayayt)");
1329 if (r < 0)
1330 return bus_log_parse_error(r);
1331
1332 while ((r = sd_bus_message_enter_container(reply, 'r', "uayayayayt")) > 0) {
1333 _cleanup_free_ char *id = NULL, *ip = NULL;
1334 const void *client_id, *addr, *gtw, *hwaddr;
1335 size_t client_id_sz, sz;
1336 uint64_t expiration;
1337 uint32_t family;
1338
1339 r = sd_bus_message_read(reply, "u", &family);
1340 if (r < 0)
1341 return bus_log_parse_error(r);
1342
1343 r = sd_bus_message_read_array(reply, 'y', &client_id, &client_id_sz);
1344 if (r < 0)
1345 return bus_log_parse_error(r);
1346
1347 r = sd_bus_message_read_array(reply, 'y', &addr, &sz);
1348 if (r < 0 || sz != 4)
1349 return bus_log_parse_error(r);
1350
1351 r = sd_bus_message_read_array(reply, 'y', >w, &sz);
1352 if (r < 0 || sz != 4)
1353 return bus_log_parse_error(r);
1354
1355 r = sd_bus_message_read_array(reply, 'y', &hwaddr, &sz);
1356 if (r < 0)
1357 return bus_log_parse_error(r);
1358
1359 r = sd_bus_message_read_basic(reply, 't', &expiration);
1360 if (r < 0)
1361 return bus_log_parse_error(r);
1362
1363 r = sd_dhcp_client_id_to_string(client_id, client_id_sz, &id);
1364 if (r < 0)
1365 return bus_log_parse_error(r);
1366
1367 r = in_addr_to_string(family, addr, &ip);
1368 if (r < 0)
1369 return bus_log_parse_error(r);
1370
1371 r = strv_extendf(&buf, "%s (to %s)", ip, id);
1372 if (r < 0)
1373 return log_oom();
1374
1375 r = sd_bus_message_exit_container(reply);
1376 if (r < 0)
1377 return bus_log_parse_error(r);
1378 }
1379 if (r < 0)
1380 return bus_log_parse_error(r);
1381
1382 r = sd_bus_message_exit_container(reply);
1383 if (r < 0)
1384 return bus_log_parse_error(r);
1385
1386 r = sd_bus_message_exit_container(reply);
1387 if (r < 0)
1388 return bus_log_parse_error(r);
1389
1390 if (strv_isempty(buf)) {
1391 r = strv_extendf(&buf, "none");
1392 if (r < 0)
1393 return log_oom();
1394 }
1395
1396 return dump_list(table, prefix, buf);
1397 }
1398
dump_ifindexes(Table * table,const char * prefix,const int * ifindexes)1399 static int dump_ifindexes(Table *table, const char *prefix, const int *ifindexes) {
1400 int r;
1401
1402 assert(prefix);
1403
1404 if (!ifindexes || ifindexes[0] <= 0)
1405 return 0;
1406
1407 for (unsigned c = 0; ifindexes[c] > 0; c++) {
1408 r = table_add_many(table,
1409 TABLE_EMPTY,
1410 TABLE_STRING, c == 0 ? prefix : "",
1411 TABLE_IFINDEX, ifindexes[c]);
1412 if (r < 0)
1413 return table_log_add_error(r);
1414 }
1415
1416 return 0;
1417 }
1418
1419 #define DUMP_STATS_ONE(name, val_name) \
1420 r = table_add_many(table, \
1421 TABLE_EMPTY, \
1422 TABLE_STRING, name ":"); \
1423 if (r < 0) \
1424 return table_log_add_error(r); \
1425 r = table_add_cell(table, NULL, \
1426 info->has_stats64 ? TABLE_UINT64 : TABLE_UINT32, \
1427 info->has_stats64 ? (void*) &info->stats64.val_name : (void*) &info->stats.val_name); \
1428 if (r < 0) \
1429 return table_log_add_error(r);
1430
dump_statistics(Table * table,const LinkInfo * info)1431 static int dump_statistics(Table *table, const LinkInfo *info) {
1432 int r;
1433
1434 if (!arg_stats)
1435 return 0;
1436
1437 if (!info->has_stats64 && !info->has_stats)
1438 return 0;
1439
1440 DUMP_STATS_ONE("Rx Packets", rx_packets);
1441 DUMP_STATS_ONE("Tx Packets", tx_packets);
1442 DUMP_STATS_ONE("Rx Bytes", rx_bytes);
1443 DUMP_STATS_ONE("Tx Bytes", tx_bytes);
1444 DUMP_STATS_ONE("Rx Errors", rx_errors);
1445 DUMP_STATS_ONE("Tx Errors", tx_errors);
1446 DUMP_STATS_ONE("Rx Dropped", rx_dropped);
1447 DUMP_STATS_ONE("Tx Dropped", tx_dropped);
1448 DUMP_STATS_ONE("Multicast Packets", multicast);
1449 DUMP_STATS_ONE("Collisions", collisions);
1450
1451 return 0;
1452 }
1453
dump_hw_address(Table * table,sd_hwdb * hwdb,const char * field,const struct hw_addr_data * addr)1454 static int dump_hw_address(Table *table, sd_hwdb *hwdb, const char *field, const struct hw_addr_data *addr) {
1455 _cleanup_free_ char *description = NULL;
1456 int r;
1457
1458 assert(table);
1459 assert(field);
1460 assert(addr);
1461
1462 if (addr->length == ETH_ALEN)
1463 (void) ieee_oui(hwdb, &addr->ether, &description);
1464
1465 r = table_add_many(table,
1466 TABLE_EMPTY,
1467 TABLE_STRING, field);
1468 if (r < 0)
1469 return table_log_add_error(r);
1470
1471 r = table_add_cell_stringf(table, NULL, "%s%s%s%s",
1472 HW_ADDR_TO_STR(addr),
1473 description ? " (" : "",
1474 strempty(description),
1475 description ? ")" : "");
1476 if (r < 0)
1477 return table_log_add_error(r);
1478
1479 return 0;
1480 }
1481
get_output_flags(void)1482 static OutputFlags get_output_flags(void) {
1483 return
1484 arg_all * OUTPUT_SHOW_ALL |
1485 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1486 colors_enabled() * OUTPUT_COLOR;
1487 }
1488
show_logs(const LinkInfo * info)1489 static int show_logs(const LinkInfo *info) {
1490 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
1491 int r;
1492
1493 if (arg_lines == 0)
1494 return 0;
1495
1496 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
1497 if (r < 0)
1498 return log_error_errno(r, "Failed to open journal: %m");
1499
1500 r = add_match_this_boot(j, NULL);
1501 if (r < 0)
1502 return log_error_errno(r, "Failed to add boot matches: %m");
1503
1504 if (info) {
1505 char m1[STRLEN("_KERNEL_DEVICE=n") + DECIMAL_STR_MAX(int)];
1506 const char *m2, *m3;
1507
1508 /* kernel */
1509 xsprintf(m1, "_KERNEL_DEVICE=n%i", info->ifindex);
1510 /* networkd */
1511 m2 = strjoina("INTERFACE=", info->name);
1512 /* udevd */
1513 m3 = strjoina("DEVICE=", info->name);
1514
1515 (void)(
1516 (r = sd_journal_add_match(j, m1, 0)) ||
1517 (r = sd_journal_add_disjunction(j)) ||
1518 (r = sd_journal_add_match(j, m2, 0)) ||
1519 (r = sd_journal_add_disjunction(j)) ||
1520 (r = sd_journal_add_match(j, m3, 0))
1521 );
1522 if (r < 0)
1523 return log_error_errno(r, "Failed to add link matches: %m");
1524 } else {
1525 r = add_matches_for_unit(j, "systemd-networkd.service");
1526 if (r < 0)
1527 return log_error_errno(r, "Failed to add unit matches: %m");
1528
1529 r = add_matches_for_unit(j, "systemd-networkd-wait-online.service");
1530 if (r < 0)
1531 return log_error_errno(r, "Failed to add unit matches: %m");
1532 }
1533
1534 return show_journal(
1535 stdout,
1536 j,
1537 OUTPUT_SHORT,
1538 0,
1539 0,
1540 arg_lines,
1541 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
1542 NULL);
1543 }
1544
link_status_one(sd_bus * bus,sd_netlink * rtnl,sd_hwdb * hwdb,const LinkInfo * info)1545 static int link_status_one(
1546 sd_bus *bus,
1547 sd_netlink *rtnl,
1548 sd_hwdb *hwdb,
1549 const LinkInfo *info) {
1550
1551 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL;
1552 _cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL,
1553 *setup_state = NULL, *operational_state = NULL, *online_state = NULL, *activation_policy = NULL;
1554 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL,
1555 *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup, *on_color_online;
1556 _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
1557 _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
1558 _cleanup_(table_unrefp) Table *table = NULL;
1559 TableCell *cell;
1560 int r;
1561
1562 assert(rtnl);
1563 assert(info);
1564
1565 (void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
1566 operational_state_to_color(info->name, operational_state, &on_color_operational, &off_color_operational);
1567
1568 (void) sd_network_link_get_online_state(info->ifindex, &online_state);
1569 online_state_to_color(online_state, &on_color_online, NULL);
1570
1571 r = sd_network_link_get_setup_state(info->ifindex, &setup_state);
1572 if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
1573 setup_state = strdup("unmanaged");
1574 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
1575
1576 (void) sd_network_link_get_dns(info->ifindex, &dns);
1577 (void) sd_network_link_get_search_domains(info->ifindex, &search_domains);
1578 (void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
1579 (void) sd_network_link_get_ntp(info->ifindex, &ntp);
1580 (void) sd_network_link_get_sip(info->ifindex, &sip);
1581
1582 if (info->sd_device) {
1583 (void) sd_device_get_property_value(info->sd_device, "ID_NET_LINK_FILE", &link);
1584 (void) sd_device_get_property_value(info->sd_device, "ID_NET_DRIVER", &driver);
1585 (void) sd_device_get_property_value(info->sd_device, "ID_PATH", &path);
1586
1587 if (sd_device_get_property_value(info->sd_device, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
1588 (void) sd_device_get_property_value(info->sd_device, "ID_VENDOR", &vendor);
1589
1590 if (sd_device_get_property_value(info->sd_device, "ID_MODEL_FROM_DATABASE", &model) < 0)
1591 (void) sd_device_get_property_value(info->sd_device, "ID_MODEL", &model);
1592 }
1593
1594 r = net_get_type_string(info->sd_device, info->iftype, &t);
1595 if (r == -ENOMEM)
1596 return log_oom();
1597
1598 (void) sd_network_link_get_network_file(info->ifindex, &network);
1599
1600 (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
1601 (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
1602
1603 char lease_file[STRLEN("/run/systemd/netif/leases/") + DECIMAL_STR_MAX(int)];
1604 xsprintf(lease_file, "/run/systemd/netif/leases/%i", info->ifindex);
1605
1606 (void) dhcp_lease_load(&lease, lease_file);
1607
1608 table = table_new("dot", "key", "value");
1609 if (!table)
1610 return log_oom();
1611
1612 if (arg_full)
1613 table_set_width(table, 0);
1614
1615 assert_se(cell = table_get_cell(table, 0, 0));
1616 (void) table_set_ellipsize_percent(table, cell, 100);
1617
1618 assert_se(cell = table_get_cell(table, 0, 1));
1619 (void) table_set_ellipsize_percent(table, cell, 100);
1620
1621 table_set_header(table, false);
1622
1623 r = table_add_many(table,
1624 TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
1625 TABLE_SET_COLOR, on_color_operational);
1626 if (r < 0)
1627 return table_log_add_error(r);
1628 r = table_add_cell_stringf(table, &cell, "%i: %s", info->ifindex, info->name);
1629 if (r < 0)
1630 return table_log_add_error(r);
1631 (void) table_set_align_percent(table, cell, 0);
1632
1633 r = table_add_many(table,
1634 TABLE_EMPTY,
1635 TABLE_EMPTY,
1636 TABLE_STRING, "Link File:",
1637 TABLE_SET_ALIGN_PERCENT, 100,
1638 TABLE_STRING, strna(link),
1639 TABLE_EMPTY,
1640 TABLE_STRING, "Network File:",
1641 TABLE_STRING, strna(network),
1642 TABLE_EMPTY,
1643 TABLE_STRING, "Type:",
1644 TABLE_STRING, strna(t),
1645 TABLE_EMPTY,
1646 TABLE_STRING, "Kind:",
1647 TABLE_STRING, strna(info->netdev_kind),
1648 TABLE_EMPTY,
1649 TABLE_STRING, "State:");
1650 if (r < 0)
1651 return table_log_add_error(r);
1652 r = table_add_cell_stringf(table, NULL, "%s%s%s (%s%s%s)",
1653 on_color_operational, strna(operational_state), off_color_operational,
1654 on_color_setup, strna(setup_state), off_color_setup);
1655 if (r < 0)
1656 return table_log_add_error(r);
1657
1658 r = table_add_many(table,
1659 TABLE_EMPTY,
1660 TABLE_STRING, "Online state:",
1661 TABLE_STRING, online_state ?: "unknown",
1662 TABLE_SET_COLOR, on_color_online);
1663 if (r < 0)
1664 return table_log_add_error(r);
1665
1666 strv_sort(info->alternative_names);
1667 r = dump_list(table, "Alternative Names:", info->alternative_names);
1668 if (r < 0)
1669 return r;
1670
1671 if (path) {
1672 r = table_add_many(table,
1673 TABLE_EMPTY,
1674 TABLE_STRING, "Path:",
1675 TABLE_STRING, path);
1676 if (r < 0)
1677 return table_log_add_error(r);
1678 }
1679 if (driver) {
1680 r = table_add_many(table,
1681 TABLE_EMPTY,
1682 TABLE_STRING, "Driver:",
1683 TABLE_STRING, driver);
1684 if (r < 0)
1685 return table_log_add_error(r);
1686 }
1687 if (vendor) {
1688 r = table_add_many(table,
1689 TABLE_EMPTY,
1690 TABLE_STRING, "Vendor:",
1691 TABLE_STRING, vendor);
1692 if (r < 0)
1693 return table_log_add_error(r);
1694 }
1695 if (model) {
1696 r = table_add_many(table,
1697 TABLE_EMPTY,
1698 TABLE_STRING, "Model:",
1699 TABLE_STRING, model);
1700 if (r < 0)
1701 return table_log_add_error(r);
1702 }
1703
1704 if (info->has_hw_address) {
1705 r = dump_hw_address(table, hwdb, "Hardware Address:", &info->hw_address);
1706 if (r < 0)
1707 return r;
1708 }
1709
1710 if (info->has_permanent_hw_address) {
1711 r = dump_hw_address(table, hwdb, "Permanent Hardware Address:", &info->permanent_hw_address);
1712 if (r < 0)
1713 return r;
1714 }
1715
1716 if (info->mtu > 0) {
1717 char min_str[DECIMAL_STR_MAX(uint32_t)], max_str[DECIMAL_STR_MAX(uint32_t)];
1718
1719 xsprintf(min_str, "%" PRIu32, info->min_mtu);
1720 xsprintf(max_str, "%" PRIu32, info->max_mtu);
1721
1722 r = table_add_many(table,
1723 TABLE_EMPTY,
1724 TABLE_STRING, "MTU:");
1725 if (r < 0)
1726 return table_log_add_error(r);
1727 r = table_add_cell_stringf(table, NULL, "%" PRIu32 "%s%s%s%s%s%s%s",
1728 info->mtu,
1729 info->min_mtu > 0 || info->max_mtu > 0 ? " (" : "",
1730 info->min_mtu > 0 ? "min: " : "",
1731 info->min_mtu > 0 ? min_str : "",
1732 info->min_mtu > 0 && info->max_mtu > 0 ? ", " : "",
1733 info->max_mtu > 0 ? "max: " : "",
1734 info->max_mtu > 0 ? max_str : "",
1735 info->min_mtu > 0 || info->max_mtu > 0 ? ")" : "");
1736 if (r < 0)
1737 return table_log_add_error(r);
1738 }
1739
1740 if (info->qdisc) {
1741 r = table_add_many(table,
1742 TABLE_EMPTY,
1743 TABLE_STRING, "QDisc:",
1744 TABLE_STRING, info->qdisc);
1745 if (r < 0)
1746 return table_log_add_error(r);
1747 }
1748
1749 if (info->master > 0) {
1750 r = table_add_many(table,
1751 TABLE_EMPTY,
1752 TABLE_STRING, "Master:",
1753 TABLE_IFINDEX, info->master);
1754 if (r < 0)
1755 return table_log_add_error(r);
1756 }
1757
1758 if (info->has_ipv6_address_generation_mode) {
1759 static const struct {
1760 const char *mode;
1761 } mode_table[] = {
1762 { "eui64" },
1763 { "none" },
1764 { "stable-privacy" },
1765 { "random" },
1766 };
1767
1768 r = table_add_many(table,
1769 TABLE_EMPTY,
1770 TABLE_STRING, "IPv6 Address Generation Mode:",
1771 TABLE_STRING, mode_table[info->addr_gen_mode]);
1772 if (r < 0)
1773 return table_log_add_error(r);
1774 }
1775
1776 if (streq_ptr(info->netdev_kind, "bridge")) {
1777 r = table_add_many(table,
1778 TABLE_EMPTY,
1779 TABLE_STRING, "Forward Delay:",
1780 TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->forward_delay),
1781 TABLE_EMPTY,
1782 TABLE_STRING, "Hello Time:",
1783 TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->hello_time),
1784 TABLE_EMPTY,
1785 TABLE_STRING, "Max Age:",
1786 TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->max_age),
1787 TABLE_EMPTY,
1788 TABLE_STRING, "Ageing Time:",
1789 TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->ageing_time),
1790 TABLE_EMPTY,
1791 TABLE_STRING, "Priority:",
1792 TABLE_UINT16, info->priority,
1793 TABLE_EMPTY,
1794 TABLE_STRING, "STP:",
1795 TABLE_BOOLEAN, info->stp_state > 0,
1796 TABLE_EMPTY,
1797 TABLE_STRING, "Multicast IGMP Version:",
1798 TABLE_UINT8, info->mcast_igmp_version,
1799 TABLE_EMPTY,
1800 TABLE_STRING, "Cost:",
1801 TABLE_UINT32, info->cost);
1802 if (r < 0)
1803 return table_log_add_error(r);
1804
1805 if (info->port_state <= BR_STATE_BLOCKING)
1806 r = table_add_many(table,
1807 TABLE_EMPTY,
1808 TABLE_STRING, "Port State:",
1809 TABLE_STRING, bridge_state_to_string(info->port_state));
1810 } else if (streq_ptr(info->netdev_kind, "bond")) {
1811 r = table_add_many(table,
1812 TABLE_EMPTY,
1813 TABLE_STRING, "Mode:",
1814 TABLE_STRING, bond_mode_to_string(info->mode),
1815 TABLE_EMPTY,
1816 TABLE_STRING, "Miimon:",
1817 TABLE_TIMESPAN_MSEC, info->miimon * USEC_PER_MSEC,
1818 TABLE_EMPTY,
1819 TABLE_STRING, "Updelay:",
1820 TABLE_TIMESPAN_MSEC, info->updelay * USEC_PER_MSEC,
1821 TABLE_EMPTY,
1822 TABLE_STRING, "Downdelay:",
1823 TABLE_TIMESPAN_MSEC, info->downdelay * USEC_PER_MSEC);
1824 if (r < 0)
1825 return table_log_add_error(r);
1826
1827 } else if (streq_ptr(info->netdev_kind, "vxlan")) {
1828 char ttl[CONST_MAX(STRLEN("auto") + 1, DECIMAL_STR_MAX(uint8_t))];
1829
1830 if (info->vxlan_info.vni > 0) {
1831 r = table_add_many(table,
1832 TABLE_EMPTY,
1833 TABLE_STRING, "VNI:",
1834 TABLE_UINT32, info->vxlan_info.vni);
1835 if (r < 0)
1836 return table_log_add_error(r);
1837 }
1838
1839 if (IN_SET(info->vxlan_info.group_family, AF_INET, AF_INET6)) {
1840 const char *p;
1841
1842 r = in_addr_is_multicast(info->vxlan_info.group_family, &info->vxlan_info.group);
1843 if (r <= 0)
1844 p = "Remote:";
1845 else
1846 p = "Group:";
1847
1848 r = table_add_many(table,
1849 TABLE_EMPTY,
1850 TABLE_STRING, p,
1851 info->vxlan_info.group_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
1852 &info->vxlan_info.group);
1853 if (r < 0)
1854 return table_log_add_error(r);
1855 }
1856
1857 if (IN_SET(info->vxlan_info.local_family, AF_INET, AF_INET6)) {
1858 r = table_add_many(table,
1859 TABLE_EMPTY,
1860 TABLE_STRING, "Local:",
1861 info->vxlan_info.local_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
1862 &info->vxlan_info.local);
1863 if (r < 0)
1864 return table_log_add_error(r);
1865 }
1866
1867 if (info->vxlan_info.dest_port > 0) {
1868 r = table_add_many(table,
1869 TABLE_EMPTY,
1870 TABLE_STRING, "Destination Port:",
1871 TABLE_UINT16, be16toh(info->vxlan_info.dest_port));
1872 if (r < 0)
1873 return table_log_add_error(r);
1874 }
1875
1876 if (info->vxlan_info.link > 0) {
1877 r = table_add_many(table,
1878 TABLE_EMPTY,
1879 TABLE_STRING, "Underlying Device:",
1880 TABLE_IFINDEX, info->vxlan_info.link);
1881 if (r < 0)
1882 return table_log_add_error(r);
1883 }
1884
1885 r = table_add_many(table,
1886 TABLE_EMPTY,
1887 TABLE_STRING, "Learning:",
1888 TABLE_BOOLEAN, info->vxlan_info.learning);
1889 if (r < 0)
1890 return table_log_add_error(r);
1891
1892 r = table_add_many(table,
1893 TABLE_EMPTY,
1894 TABLE_STRING, "RSC:",
1895 TABLE_BOOLEAN, info->vxlan_info.rsc);
1896 if (r < 0)
1897 return table_log_add_error(r);
1898
1899 r = table_add_many(table,
1900 TABLE_EMPTY,
1901 TABLE_STRING, "L3MISS:",
1902 TABLE_BOOLEAN, info->vxlan_info.l3miss);
1903 if (r < 0)
1904 return table_log_add_error(r);
1905
1906 r = table_add_many(table,
1907 TABLE_EMPTY,
1908 TABLE_STRING, "L2MISS:",
1909 TABLE_BOOLEAN, info->vxlan_info.l2miss);
1910 if (r < 0)
1911 return table_log_add_error(r);
1912
1913 if (info->vxlan_info.tos > 1) {
1914 r = table_add_many(table,
1915 TABLE_EMPTY,
1916 TABLE_STRING, "TOS:",
1917 TABLE_UINT8, info->vxlan_info.tos);
1918 if (r < 0)
1919 return table_log_add_error(r);
1920 }
1921
1922 if (info->vxlan_info.ttl > 0)
1923 xsprintf(ttl, "%" PRIu8, info->vxlan_info.ttl);
1924 else
1925 strcpy(ttl, "auto");
1926
1927 r = table_add_many(table,
1928 TABLE_EMPTY,
1929 TABLE_STRING, "TTL:",
1930 TABLE_STRING, ttl);
1931 if (r < 0)
1932 return table_log_add_error(r);
1933 } else if (streq_ptr(info->netdev_kind, "vlan") && info->vlan_id > 0) {
1934 r = table_add_many(table,
1935 TABLE_EMPTY,
1936 TABLE_STRING, "VLan Id:",
1937 TABLE_UINT16, info->vlan_id);
1938 if (r < 0)
1939 return table_log_add_error(r);
1940 } else if (STRPTR_IN_SET(info->netdev_kind, "ipip", "sit", "gre", "gretap", "erspan", "vti")) {
1941 if (in_addr_is_set(AF_INET, &info->local)) {
1942 r = table_add_many(table,
1943 TABLE_EMPTY,
1944 TABLE_STRING, "Local:",
1945 TABLE_IN_ADDR, &info->local);
1946 if (r < 0)
1947 return table_log_add_error(r);
1948 }
1949
1950 if (in_addr_is_set(AF_INET, &info->remote)) {
1951 r = table_add_many(table,
1952 TABLE_EMPTY,
1953 TABLE_STRING, "Remote:",
1954 TABLE_IN_ADDR, &info->remote);
1955 if (r < 0)
1956 return table_log_add_error(r);
1957 }
1958 } else if (STRPTR_IN_SET(info->netdev_kind, "ip6gre", "ip6gretap", "ip6erspan", "vti6")) {
1959 if (in_addr_is_set(AF_INET6, &info->local)) {
1960 r = table_add_many(table,
1961 TABLE_EMPTY,
1962 TABLE_STRING, "Local:",
1963 TABLE_IN6_ADDR, &info->local);
1964 if (r < 0)
1965 return table_log_add_error(r);
1966 }
1967
1968 if (in_addr_is_set(AF_INET6, &info->remote)) {
1969 r = table_add_many(table,
1970 TABLE_EMPTY,
1971 TABLE_STRING, "Remote:",
1972 TABLE_IN6_ADDR, &info->remote);
1973 if (r < 0)
1974 return table_log_add_error(r);
1975 }
1976 } else if (streq_ptr(info->netdev_kind, "geneve")) {
1977 r = table_add_many(table,
1978 TABLE_EMPTY,
1979 TABLE_STRING, "VNI:",
1980 TABLE_UINT32, info->vni);
1981 if (r < 0)
1982 return table_log_add_error(r);
1983
1984 if (info->has_tunnel_ipv4 && in_addr_is_set(AF_INET, &info->remote)) {
1985 r = table_add_many(table,
1986 TABLE_EMPTY,
1987 TABLE_STRING, "Remote:",
1988 TABLE_IN_ADDR, &info->remote);
1989 if (r < 0)
1990 return table_log_add_error(r);
1991 } else if (in_addr_is_set(AF_INET6, &info->remote)) {
1992 r = table_add_many(table,
1993 TABLE_EMPTY,
1994 TABLE_STRING, "Remote:",
1995 TABLE_IN6_ADDR, &info->remote);
1996 if (r < 0)
1997 return table_log_add_error(r);
1998 }
1999
2000 if (info->ttl > 0) {
2001 r = table_add_many(table,
2002 TABLE_EMPTY,
2003 TABLE_STRING, "TTL:",
2004 TABLE_UINT8, info->ttl);
2005 if (r < 0)
2006 return table_log_add_error(r);
2007 }
2008
2009 if (info->tos > 0) {
2010 r = table_add_many(table,
2011 TABLE_EMPTY,
2012 TABLE_STRING, "TOS:",
2013 TABLE_UINT8, info->tos);
2014 if (r < 0)
2015 return table_log_add_error(r);
2016 }
2017
2018 r = table_add_many(table,
2019 TABLE_EMPTY,
2020 TABLE_STRING, "Port:",
2021 TABLE_UINT16, info->tunnel_port);
2022 if (r < 0)
2023 return table_log_add_error(r);
2024
2025 r = table_add_many(table,
2026 TABLE_EMPTY,
2027 TABLE_STRING, "Inherit:",
2028 TABLE_STRING, geneve_df_to_string(info->inherit));
2029 if (r < 0)
2030 return table_log_add_error(r);
2031
2032 if (info->df > 0) {
2033 r = table_add_many(table,
2034 TABLE_EMPTY,
2035 TABLE_STRING, "IPDoNotFragment:",
2036 TABLE_UINT8, info->df);
2037 if (r < 0)
2038 return table_log_add_error(r);
2039 }
2040
2041 r = table_add_many(table,
2042 TABLE_EMPTY,
2043 TABLE_STRING, "UDPChecksum:",
2044 TABLE_BOOLEAN, info->csum);
2045 if (r < 0)
2046 return table_log_add_error(r);
2047
2048 r = table_add_many(table,
2049 TABLE_EMPTY,
2050 TABLE_STRING, "UDP6ZeroChecksumTx:",
2051 TABLE_BOOLEAN, info->csum6_tx);
2052 if (r < 0)
2053 return table_log_add_error(r);
2054
2055 r = table_add_many(table,
2056 TABLE_EMPTY,
2057 TABLE_STRING, "UDP6ZeroChecksumRx:",
2058 TABLE_BOOLEAN, info->csum6_rx);
2059 if (r < 0)
2060 return table_log_add_error(r);
2061
2062 if (info->label > 0) {
2063 r = table_add_many(table,
2064 TABLE_EMPTY,
2065 TABLE_STRING, "FlowLabel:",
2066 TABLE_UINT32, info->label);
2067 if (r < 0)
2068 return table_log_add_error(r);
2069 }
2070 } else if (STRPTR_IN_SET(info->netdev_kind, "macvlan", "macvtap")) {
2071 r = table_add_many(table,
2072 TABLE_EMPTY,
2073 TABLE_STRING, "Mode:",
2074 TABLE_STRING, macvlan_mode_to_string(info->macvlan_mode));
2075 if (r < 0)
2076 return table_log_add_error(r);
2077 } else if (streq_ptr(info->netdev_kind, "ipvlan")) {
2078 _cleanup_free_ char *p = NULL, *s = NULL;
2079
2080 if (info->ipvlan_flags & IPVLAN_F_PRIVATE)
2081 p = strdup("private");
2082 else if (info->ipvlan_flags & IPVLAN_F_VEPA)
2083 p = strdup("vepa");
2084 else
2085 p = strdup("bridge");
2086 if (!p)
2087 log_oom();
2088
2089 s = strjoin(ipvlan_mode_to_string(info->ipvlan_mode), " (", p, ")");
2090 if (!s)
2091 return log_oom();
2092
2093 r = table_add_many(table,
2094 TABLE_EMPTY,
2095 TABLE_STRING, "Mode:",
2096 TABLE_STRING, s);
2097 if (r < 0)
2098 return table_log_add_error(r);
2099 }
2100
2101 if (info->has_wlan_link_info) {
2102 _cleanup_free_ char *esc = NULL;
2103
2104 r = table_add_many(table,
2105 TABLE_EMPTY,
2106 TABLE_STRING, "WiFi access point:");
2107 if (r < 0)
2108 return table_log_add_error(r);
2109
2110 if (info->ssid)
2111 esc = cescape(info->ssid);
2112
2113 r = table_add_cell_stringf(table, NULL, "%s (%s)",
2114 strnull(esc),
2115 ETHER_ADDR_TO_STR(&info->bssid));
2116 if (r < 0)
2117 return table_log_add_error(r);
2118 }
2119
2120 if (info->has_bitrates) {
2121 r = table_add_many(table,
2122 TABLE_EMPTY,
2123 TABLE_STRING, "Bit Rate (Tx/Rx):");
2124 if (r < 0)
2125 return table_log_add_error(r);
2126 r = table_add_cell_stringf(table, NULL, "%sbps/%sbps",
2127 FORMAT_BYTES_FULL(info->tx_bitrate, 0),
2128 FORMAT_BYTES_FULL(info->rx_bitrate, 0));
2129 if (r < 0)
2130 return table_log_add_error(r);
2131 }
2132
2133 if (info->has_tx_queues || info->has_rx_queues) {
2134 r = table_add_many(table,
2135 TABLE_EMPTY,
2136 TABLE_STRING, "Queue Length (Tx/Rx):");
2137 if (r < 0)
2138 return table_log_add_error(r);
2139 r = table_add_cell_stringf(table, NULL, "%" PRIu32 "/%" PRIu32, info->tx_queues, info->rx_queues);
2140 if (r < 0)
2141 return table_log_add_error(r);
2142 }
2143
2144 if (info->has_ethtool_link_info) {
2145 const char *duplex = duplex_to_string(info->duplex);
2146 const char *port = port_to_string(info->port);
2147
2148 if (IN_SET(info->autonegotiation, AUTONEG_DISABLE, AUTONEG_ENABLE)) {
2149 r = table_add_many(table,
2150 TABLE_EMPTY,
2151 TABLE_STRING, "Auto negotiation:",
2152 TABLE_BOOLEAN, info->autonegotiation == AUTONEG_ENABLE);
2153 if (r < 0)
2154 return table_log_add_error(r);
2155 }
2156
2157 if (info->speed > 0) {
2158 r = table_add_many(table,
2159 TABLE_EMPTY,
2160 TABLE_STRING, "Speed:",
2161 TABLE_BPS, info->speed);
2162 if (r < 0)
2163 return table_log_add_error(r);
2164 }
2165
2166 if (duplex) {
2167 r = table_add_many(table,
2168 TABLE_EMPTY,
2169 TABLE_STRING, "Duplex:",
2170 TABLE_STRING, duplex);
2171 if (r < 0)
2172 return table_log_add_error(r);
2173 }
2174
2175 if (port) {
2176 r = table_add_many(table,
2177 TABLE_EMPTY,
2178 TABLE_STRING, "Port:",
2179 TABLE_STRING, port);
2180 if (r < 0)
2181 return table_log_add_error(r);
2182 }
2183 }
2184
2185 r = dump_addresses(rtnl, lease, table, info->ifindex);
2186 if (r < 0)
2187 return r;
2188 r = dump_gateways(rtnl, hwdb, table, info->ifindex);
2189 if (r < 0)
2190 return r;
2191 r = dump_list(table, "DNS:", dns);
2192 if (r < 0)
2193 return r;
2194 r = dump_list(table, "Search Domains:", search_domains);
2195 if (r < 0)
2196 return r;
2197 r = dump_list(table, "Route Domains:", route_domains);
2198 if (r < 0)
2199 return r;
2200 r = dump_list(table, "NTP:", ntp);
2201 if (r < 0)
2202 return r;
2203 r = dump_list(table, "SIP:", sip);
2204 if (r < 0)
2205 return r;
2206 r = dump_ifindexes(table, "Carrier Bound To:", carrier_bound_to);
2207 if (r < 0)
2208 return r;
2209 r = dump_ifindexes(table, "Carrier Bound By:", carrier_bound_by);
2210 if (r < 0)
2211 return r;
2212
2213 r = sd_network_link_get_activation_policy(info->ifindex, &activation_policy);
2214 if (r >= 0) {
2215 r = table_add_many(table,
2216 TABLE_EMPTY,
2217 TABLE_STRING, "Activation Policy:",
2218 TABLE_STRING, activation_policy);
2219 if (r < 0)
2220 return table_log_add_error(r);
2221 }
2222
2223 r = sd_network_link_get_required_for_online(info->ifindex);
2224 if (r >= 0) {
2225 r = table_add_many(table,
2226 TABLE_EMPTY,
2227 TABLE_STRING, "Required For Online:",
2228 TABLE_BOOLEAN, r);
2229 if (r < 0)
2230 return table_log_add_error(r);
2231 }
2232
2233 if (lease) {
2234 const void *client_id;
2235 size_t client_id_len;
2236 const char *tz;
2237
2238 r = sd_dhcp_lease_get_timezone(lease, &tz);
2239 if (r >= 0) {
2240 r = table_add_many(table,
2241 TABLE_EMPTY,
2242 TABLE_STRING, "Time Zone:",
2243 TABLE_STRING, tz);
2244 if (r < 0)
2245 return table_log_add_error(r);
2246 }
2247
2248 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
2249 if (r >= 0) {
2250 _cleanup_free_ char *id = NULL;
2251
2252 r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id);
2253 if (r >= 0) {
2254 r = table_add_many(table,
2255 TABLE_EMPTY,
2256 TABLE_STRING, "DHCP4 Client ID:",
2257 TABLE_STRING, id);
2258 if (r < 0)
2259 return table_log_add_error(r);
2260 }
2261 }
2262 }
2263
2264 r = sd_network_link_get_dhcp6_client_iaid_string(info->ifindex, &iaid);
2265 if (r >= 0) {
2266 r = table_add_many(table,
2267 TABLE_EMPTY,
2268 TABLE_STRING, "DHCP6 Client IAID:",
2269 TABLE_STRING, iaid);
2270 if (r < 0)
2271 return table_log_add_error(r);
2272 }
2273
2274 r = sd_network_link_get_dhcp6_client_duid_string(info->ifindex, &duid);
2275 if (r >= 0) {
2276 r = table_add_many(table,
2277 TABLE_EMPTY,
2278 TABLE_STRING, "DHCP6 Client DUID:",
2279 TABLE_STRING, duid);
2280 if (r < 0)
2281 return table_log_add_error(r);
2282 }
2283
2284 r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
2285 if (r < 0)
2286 return r;
2287
2288 r = dump_dhcp_leases(table, "Offered DHCP leases:", bus, info);
2289 if (r < 0)
2290 return r;
2291
2292 r = dump_statistics(table, info);
2293 if (r < 0)
2294 return r;
2295
2296 r = table_print(table, NULL);
2297 if (r < 0)
2298 return table_log_print_error(r);
2299
2300 return show_logs(info);
2301 }
2302
system_status(sd_netlink * rtnl,sd_hwdb * hwdb)2303 static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
2304 _cleanup_free_ char *operational_state = NULL, *online_state = NULL;
2305 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
2306 const char *on_color_operational, *on_color_online;
2307 _cleanup_(table_unrefp) Table *table = NULL;
2308 TableCell *cell;
2309 int r;
2310
2311 assert(rtnl);
2312
2313 (void) sd_network_get_operational_state(&operational_state);
2314 operational_state_to_color(NULL, operational_state, &on_color_operational, NULL);
2315
2316 (void) sd_network_get_online_state(&online_state);
2317 online_state_to_color(online_state, &on_color_online, NULL);
2318
2319 table = table_new("dot", "key", "value");
2320 if (!table)
2321 return log_oom();
2322
2323 if (arg_full)
2324 table_set_width(table, 0);
2325
2326 assert_se(cell = table_get_cell(table, 0, 0));
2327 (void) table_set_ellipsize_percent(table, cell, 100);
2328
2329 assert_se(cell = table_get_cell(table, 0, 1));
2330 (void) table_set_align_percent(table, cell, 100);
2331 (void) table_set_ellipsize_percent(table, cell, 100);
2332
2333 table_set_header(table, false);
2334
2335 r = table_add_many(table,
2336 TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
2337 TABLE_SET_COLOR, on_color_operational,
2338 TABLE_STRING, "State:",
2339 TABLE_STRING, strna(operational_state),
2340 TABLE_SET_COLOR, on_color_operational,
2341 TABLE_EMPTY,
2342 TABLE_STRING, "Online state:",
2343 TABLE_STRING, online_state ?: "unknown",
2344 TABLE_SET_COLOR, on_color_online);
2345 if (r < 0)
2346 return table_log_add_error(r);
2347
2348 r = dump_addresses(rtnl, NULL, table, 0);
2349 if (r < 0)
2350 return r;
2351 r = dump_gateways(rtnl, hwdb, table, 0);
2352 if (r < 0)
2353 return r;
2354
2355 (void) sd_network_get_dns(&dns);
2356 r = dump_list(table, "DNS:", dns);
2357 if (r < 0)
2358 return r;
2359
2360 (void) sd_network_get_search_domains(&search_domains);
2361 r = dump_list(table, "Search Domains:", search_domains);
2362 if (r < 0)
2363 return r;
2364
2365 (void) sd_network_get_route_domains(&route_domains);
2366 r = dump_list(table, "Route Domains:", route_domains);
2367 if (r < 0)
2368 return r;
2369
2370 (void) sd_network_get_ntp(&ntp);
2371 r = dump_list(table, "NTP:", ntp);
2372 if (r < 0)
2373 return r;
2374
2375 r = table_print(table, NULL);
2376 if (r < 0)
2377 return table_log_print_error(r);
2378
2379 return show_logs(NULL);
2380 }
2381
link_status(int argc,char * argv[],void * userdata)2382 static int link_status(int argc, char *argv[], void *userdata) {
2383 sd_bus *bus = ASSERT_PTR(userdata);
2384 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2385 _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
2386 _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
2387 int r, c;
2388
2389 if (arg_json_format_flags != JSON_FORMAT_OFF) {
2390 if (arg_all || argc <= 1)
2391 return dump_manager_description(bus);
2392 else
2393 return dump_link_description(bus, strv_skip(argv, 1));
2394 }
2395
2396 pager_open(arg_pager_flags);
2397
2398 r = sd_netlink_open(&rtnl);
2399 if (r < 0)
2400 return log_error_errno(r, "Failed to connect to netlink: %m");
2401
2402 r = sd_hwdb_new(&hwdb);
2403 if (r < 0)
2404 log_debug_errno(r, "Failed to open hardware database: %m");
2405
2406 if (arg_all)
2407 c = acquire_link_info(bus, rtnl, NULL, &links);
2408 else if (argc <= 1)
2409 return system_status(rtnl, hwdb);
2410 else
2411 c = acquire_link_info(bus, rtnl, argv + 1, &links);
2412 if (c < 0)
2413 return c;
2414
2415 for (int i = 0; i < c; i++) {
2416 if (i > 0)
2417 fputc('\n', stdout);
2418
2419 link_status_one(bus, rtnl, hwdb, links + i);
2420 }
2421
2422 return 0;
2423 }
2424
lldp_capabilities_to_string(uint16_t x)2425 static char *lldp_capabilities_to_string(uint16_t x) {
2426 static const char characters[] = {
2427 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
2428 };
2429 char *ret;
2430 unsigned i;
2431
2432 ret = new(char, ELEMENTSOF(characters) + 1);
2433 if (!ret)
2434 return NULL;
2435
2436 for (i = 0; i < ELEMENTSOF(characters); i++)
2437 ret[i] = (x & (1U << i)) ? characters[i] : '.';
2438
2439 ret[i] = 0;
2440 return ret;
2441 }
2442
lldp_capabilities_legend(uint16_t x)2443 static void lldp_capabilities_legend(uint16_t x) {
2444 unsigned cols = columns();
2445 static const char* const table[] = {
2446 "o - Other",
2447 "p - Repeater",
2448 "b - Bridge",
2449 "w - WLAN Access Point",
2450 "r - Router",
2451 "t - Telephone",
2452 "d - DOCSIS cable device",
2453 "a - Station",
2454 "c - Customer VLAN",
2455 "s - Service VLAN",
2456 "m - Two-port MAC Relay (TPMR)",
2457 };
2458
2459 if (x == 0)
2460 return;
2461
2462 printf("\nCapability Flags:\n");
2463 for (unsigned w = 0, i = 0; i < ELEMENTSOF(table); i++)
2464 if (x & (1U << i) || arg_all) {
2465 bool newline;
2466
2467 newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols;
2468 if (newline)
2469 w = 0;
2470 w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]);
2471 }
2472 puts("");
2473 }
2474
link_lldp_status(int argc,char * argv[],void * userdata)2475 static int link_lldp_status(int argc, char *argv[], void *userdata) {
2476 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2477 _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
2478 _cleanup_(table_unrefp) Table *table = NULL;
2479 int r, c, m = 0;
2480 uint16_t all = 0;
2481 TableCell *cell;
2482
2483 r = sd_netlink_open(&rtnl);
2484 if (r < 0)
2485 return log_error_errno(r, "Failed to connect to netlink: %m");
2486
2487 c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
2488 if (c < 0)
2489 return c;
2490
2491 pager_open(arg_pager_flags);
2492
2493 table = table_new("link",
2494 "chassis-id",
2495 "system-name",
2496 "caps",
2497 "port-id",
2498 "port-description");
2499 if (!table)
2500 return log_oom();
2501
2502 if (arg_full)
2503 table_set_width(table, 0);
2504
2505 table_set_header(table, arg_legend);
2506
2507 assert_se(cell = table_get_cell(table, 0, 3));
2508 table_set_minimum_width(table, cell, 11);
2509
2510 for (int i = 0; i < c; i++) {
2511 _cleanup_fclose_ FILE *f = NULL;
2512
2513 r = open_lldp_neighbors(links[i].ifindex, &f);
2514 if (r == -ENOENT)
2515 continue;
2516 if (r < 0) {
2517 log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex);
2518 continue;
2519 }
2520
2521 for (;;) {
2522 const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL;
2523 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
2524 _cleanup_free_ char *capabilities = NULL;
2525 uint16_t cc;
2526
2527 r = next_lldp_neighbor(f, &n);
2528 if (r < 0) {
2529 log_warning_errno(r, "Failed to read neighbor data: %m");
2530 break;
2531 }
2532 if (r == 0)
2533 break;
2534
2535 (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id);
2536 (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
2537 (void) sd_lldp_neighbor_get_system_name(n, &system_name);
2538 (void) sd_lldp_neighbor_get_port_description(n, &port_description);
2539
2540 if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) {
2541 capabilities = lldp_capabilities_to_string(cc);
2542 all |= cc;
2543 }
2544
2545 r = table_add_many(table,
2546 TABLE_STRING, links[i].name,
2547 TABLE_STRING, strna(chassis_id),
2548 TABLE_STRING, strna(system_name),
2549 TABLE_STRING, strna(capabilities),
2550 TABLE_STRING, strna(port_id),
2551 TABLE_STRING, strna(port_description));
2552 if (r < 0)
2553 return table_log_add_error(r);
2554
2555 m++;
2556 }
2557 }
2558
2559 r = table_print(table, NULL);
2560 if (r < 0)
2561 return table_log_print_error(r);
2562
2563 if (arg_legend) {
2564 lldp_capabilities_legend(all);
2565 printf("\n%i neighbors listed.\n", m);
2566 }
2567
2568 return 0;
2569 }
2570
link_delete_send_message(sd_netlink * rtnl,int index)2571 static int link_delete_send_message(sd_netlink *rtnl, int index) {
2572 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
2573 int r;
2574
2575 assert(rtnl);
2576
2577 r = sd_rtnl_message_new_link(rtnl, &req, RTM_DELLINK, index);
2578 if (r < 0)
2579 return rtnl_log_create_error(r);
2580
2581 r = sd_netlink_call(rtnl, req, 0, NULL);
2582 if (r < 0)
2583 return r;
2584
2585 return 0;
2586 }
2587
link_up_down_send_message(sd_netlink * rtnl,char * command,int index)2588 static int link_up_down_send_message(sd_netlink *rtnl, char *command, int index) {
2589 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
2590 int r;
2591
2592 assert(rtnl);
2593
2594 r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, index);
2595 if (r < 0)
2596 return rtnl_log_create_error(r);
2597
2598 if (streq(command, "up"))
2599 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
2600 else
2601 r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
2602 if (r < 0)
2603 return log_error_errno(r, "Could not set link flags: %m");
2604
2605 r = sd_netlink_call(rtnl, req, 0, NULL);
2606 if (r < 0)
2607 return r;
2608
2609 return 0;
2610 }
2611
link_up_down(int argc,char * argv[],void * userdata)2612 static int link_up_down(int argc, char *argv[], void *userdata) {
2613 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2614 _cleanup_set_free_ Set *indexes = NULL;
2615 int index, r;
2616 void *p;
2617
2618 r = sd_netlink_open(&rtnl);
2619 if (r < 0)
2620 return log_error_errno(r, "Failed to connect to netlink: %m");
2621
2622 indexes = set_new(NULL);
2623 if (!indexes)
2624 return log_oom();
2625
2626 for (int i = 1; i < argc; i++) {
2627 index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2628 if (index < 0)
2629 return index;
2630
2631 r = set_put(indexes, INT_TO_PTR(index));
2632 if (r < 0)
2633 return log_oom();
2634 }
2635
2636 SET_FOREACH(p, indexes) {
2637 index = PTR_TO_INT(p);
2638 r = link_up_down_send_message(rtnl, argv[0], index);
2639 if (r < 0)
2640 return log_error_errno(r, "Failed to bring %s interface %s: %m",
2641 argv[0], FORMAT_IFNAME_FULL(index, FORMAT_IFNAME_IFINDEX));
2642 }
2643
2644 return r;
2645 }
2646
link_delete(int argc,char * argv[],void * userdata)2647 static int link_delete(int argc, char *argv[], void *userdata) {
2648 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2649 _cleanup_set_free_ Set *indexes = NULL;
2650 int index, r;
2651 void *p;
2652
2653 r = sd_netlink_open(&rtnl);
2654 if (r < 0)
2655 return log_error_errno(r, "Failed to connect to netlink: %m");
2656
2657 indexes = set_new(NULL);
2658 if (!indexes)
2659 return log_oom();
2660
2661 for (int i = 1; i < argc; i++) {
2662 index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2663 if (index < 0)
2664 return index;
2665
2666 r = set_put(indexes, INT_TO_PTR(index));
2667 if (r < 0)
2668 return log_oom();
2669 }
2670
2671 SET_FOREACH(p, indexes) {
2672 index = PTR_TO_INT(p);
2673 r = link_delete_send_message(rtnl, index);
2674 if (r < 0)
2675 return log_error_errno(r, "Failed to delete interface %s: %m",
2676 FORMAT_IFNAME_FULL(index, FORMAT_IFNAME_IFINDEX));
2677 }
2678
2679 return r;
2680 }
2681
link_renew_one(sd_bus * bus,int index,const char * name)2682 static int link_renew_one(sd_bus *bus, int index, const char *name) {
2683 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2684 int r;
2685
2686 r = bus_call_method(bus, bus_network_mgr, "RenewLink", &error, NULL, "i", index);
2687 if (r < 0)
2688 return log_error_errno(r, "Failed to renew dynamic configuration of interface %s: %s",
2689 name, bus_error_message(&error, r));
2690
2691 return 0;
2692 }
2693
link_renew(int argc,char * argv[],void * userdata)2694 static int link_renew(int argc, char *argv[], void *userdata) {
2695 sd_bus *bus = ASSERT_PTR(userdata);
2696 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2697 int index, k = 0, r;
2698
2699 for (int i = 1; i < argc; i++) {
2700 index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2701 if (index < 0)
2702 return index;
2703
2704 r = link_renew_one(bus, index, argv[i]);
2705 if (r < 0 && k >= 0)
2706 k = r;
2707 }
2708
2709 return k;
2710 }
2711
link_force_renew_one(sd_bus * bus,int index,const char * name)2712 static int link_force_renew_one(sd_bus *bus, int index, const char *name) {
2713 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2714 int r;
2715
2716 r = bus_call_method(bus, bus_network_mgr, "ForceRenewLink", &error, NULL, "i", index);
2717 if (r < 0)
2718 return log_error_errno(r, "Failed to force renew dynamic configuration of interface %s: %s",
2719 name, bus_error_message(&error, r));
2720
2721 return 0;
2722 }
2723
link_force_renew(int argc,char * argv[],void * userdata)2724 static int link_force_renew(int argc, char *argv[], void *userdata) {
2725 sd_bus *bus = ASSERT_PTR(userdata);
2726 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2727 int k = 0, r;
2728
2729 for (int i = 1; i < argc; i++) {
2730 int index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2731 if (index < 0)
2732 return index;
2733
2734 r = link_force_renew_one(bus, index, argv[i]);
2735 if (r < 0 && k >= 0)
2736 k = r;
2737 }
2738
2739 return k;
2740 }
2741
verb_reload(int argc,char * argv[],void * userdata)2742 static int verb_reload(int argc, char *argv[], void *userdata) {
2743 sd_bus *bus = ASSERT_PTR(userdata);
2744 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2745 int r;
2746
2747 r = bus_call_method(bus, bus_network_mgr, "Reload", &error, NULL, NULL);
2748 if (r < 0)
2749 return log_error_errno(r, "Failed to reload network settings: %m");
2750
2751 return 0;
2752 }
2753
verb_reconfigure(int argc,char * argv[],void * userdata)2754 static int verb_reconfigure(int argc, char *argv[], void *userdata) {
2755 sd_bus *bus = ASSERT_PTR(userdata);
2756 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2757 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2758 _cleanup_set_free_ Set *indexes = NULL;
2759 int index, r;
2760 void *p;
2761
2762 indexes = set_new(NULL);
2763 if (!indexes)
2764 return log_oom();
2765
2766 for (int i = 1; i < argc; i++) {
2767 index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2768 if (index < 0)
2769 return index;
2770
2771 r = set_put(indexes, INT_TO_PTR(index));
2772 if (r < 0)
2773 return log_oom();
2774 }
2775
2776 SET_FOREACH(p, indexes) {
2777 index = PTR_TO_INT(p);
2778 r = bus_call_method(bus, bus_network_mgr, "ReconfigureLink", &error, NULL, "i", index);
2779 if (r < 0)
2780 return log_error_errno(r, "Failed to reconfigure network interface %s: %m",
2781 FORMAT_IFNAME_FULL(index, FORMAT_IFNAME_IFINDEX));
2782 }
2783
2784 return 0;
2785 }
2786
help(void)2787 static int help(void) {
2788 _cleanup_free_ char *link = NULL;
2789 int r;
2790
2791 r = terminal_urlify_man("networkctl", "1", &link);
2792 if (r < 0)
2793 return log_oom();
2794
2795 printf("%s [OPTIONS...] COMMAND\n\n"
2796 "%sQuery and control the networking subsystem.%s\n"
2797 "\nCommands:\n"
2798 " list [PATTERN...] List links\n"
2799 " status [PATTERN...] Show link status\n"
2800 " lldp [PATTERN...] Show LLDP neighbors\n"
2801 " label Show current address label entries in the kernel\n"
2802 " delete DEVICES... Delete virtual netdevs\n"
2803 " up DEVICES... Bring devices up\n"
2804 " down DEVICES... Bring devices down\n"
2805 " renew DEVICES... Renew dynamic configurations\n"
2806 " forcerenew DEVICES... Trigger DHCP reconfiguration of all connected clients\n"
2807 " reconfigure DEVICES... Reconfigure interfaces\n"
2808 " reload Reload .network and .netdev files\n"
2809 "\nOptions:\n"
2810 " -h --help Show this help\n"
2811 " --version Show package version\n"
2812 " --no-pager Do not pipe output into a pager\n"
2813 " --no-legend Do not show the headers and footers\n"
2814 " -a --all Show status for all links\n"
2815 " -s --stats Show detailed link statistics\n"
2816 " -l --full Do not ellipsize output\n"
2817 " -n --lines=INTEGER Number of journal entries to show\n"
2818 " --json=pretty|short|off\n"
2819 " Generate JSON output\n"
2820 "\nSee the %s for details.\n",
2821 program_invocation_short_name,
2822 ansi_highlight(),
2823 ansi_normal(),
2824 link);
2825
2826 return 0;
2827 }
2828
parse_argv(int argc,char * argv[])2829 static int parse_argv(int argc, char *argv[]) {
2830
2831 enum {
2832 ARG_VERSION = 0x100,
2833 ARG_NO_PAGER,
2834 ARG_NO_LEGEND,
2835 ARG_JSON,
2836 };
2837
2838 static const struct option options[] = {
2839 { "help", no_argument, NULL, 'h' },
2840 { "version", no_argument, NULL, ARG_VERSION },
2841 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
2842 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
2843 { "all", no_argument, NULL, 'a' },
2844 { "stats", no_argument, NULL, 's' },
2845 { "full", no_argument, NULL, 'l' },
2846 { "lines", required_argument, NULL, 'n' },
2847 { "json", required_argument, NULL, ARG_JSON },
2848 {}
2849 };
2850
2851 int c, r;
2852
2853 assert(argc >= 0);
2854 assert(argv);
2855
2856 while ((c = getopt_long(argc, argv, "hasln:", options, NULL)) >= 0) {
2857
2858 switch (c) {
2859
2860 case 'h':
2861 return help();
2862
2863 case ARG_VERSION:
2864 return version();
2865
2866 case ARG_NO_PAGER:
2867 arg_pager_flags |= PAGER_DISABLE;
2868 break;
2869
2870 case ARG_NO_LEGEND:
2871 arg_legend = false;
2872 break;
2873
2874 case 'a':
2875 arg_all = true;
2876 break;
2877
2878 case 's':
2879 arg_stats = true;
2880 break;
2881
2882 case 'l':
2883 arg_full = true;
2884 break;
2885
2886 case 'n':
2887 if (safe_atou(optarg, &arg_lines) < 0)
2888 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2889 "Failed to parse lines '%s'", optarg);
2890 break;
2891
2892 case ARG_JSON:
2893 r = parse_json_argument(optarg, &arg_json_format_flags);
2894 if (r <= 0)
2895 return r;
2896 break;
2897
2898 case '?':
2899 return -EINVAL;
2900
2901 default:
2902 assert_not_reached();
2903 }
2904 }
2905
2906 return 1;
2907 }
2908
networkctl_main(sd_bus * bus,int argc,char * argv[])2909 static int networkctl_main(sd_bus *bus, int argc, char *argv[]) {
2910 static const Verb verbs[] = {
2911 { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links },
2912 { "status", VERB_ANY, VERB_ANY, 0, link_status },
2913 { "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status },
2914 { "label", 1, 1, 0, list_address_labels },
2915 { "delete", 2, VERB_ANY, 0, link_delete },
2916 { "up", 2, VERB_ANY, 0, link_up_down },
2917 { "down", 2, VERB_ANY, 0, link_up_down },
2918 { "renew", 2, VERB_ANY, 0, link_renew },
2919 { "forcerenew", 2, VERB_ANY, 0, link_force_renew },
2920 { "reconfigure", 2, VERB_ANY, 0, verb_reconfigure },
2921 { "reload", 1, 1, 0, verb_reload },
2922 {}
2923 };
2924
2925 return dispatch_verb(argc, argv, verbs, bus);
2926 }
2927
check_netns_match(sd_bus * bus)2928 static int check_netns_match(sd_bus *bus) {
2929 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2930 struct stat st;
2931 uint64_t id;
2932 int r;
2933
2934 r = sd_bus_get_property_trivial(
2935 bus,
2936 "org.freedesktop.network1",
2937 "/org/freedesktop/network1",
2938 "org.freedesktop.network1.Manager",
2939 "NamespaceId",
2940 &error,
2941 't',
2942 &id);
2943 if (r < 0) {
2944 log_debug_errno(r, "Failed to query network namespace of networkd, ignoring: %s", bus_error_message(&error, r));
2945 return 0;
2946 }
2947 if (id == 0) {
2948 log_debug("systemd-networkd.service not running in a network namespace (?), skipping netns check.");
2949 return 0;
2950 }
2951
2952 if (stat("/proc/self/ns/net", &st) < 0)
2953 return log_error_errno(r, "Failed to determine our own network namespace ID: %m");
2954
2955 if (id != st.st_ino)
2956 return log_error_errno(SYNTHETIC_ERRNO(EREMOTE),
2957 "networkctl must be invoked in same network namespace as systemd-networkd.service.");
2958
2959 return 0;
2960 }
2961
warn_networkd_missing(void)2962 static void warn_networkd_missing(void) {
2963
2964 if (access("/run/systemd/netif/state", F_OK) >= 0)
2965 return;
2966
2967 fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
2968 }
2969
run(int argc,char * argv[])2970 static int run(int argc, char* argv[]) {
2971 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2972 int r;
2973
2974 log_setup();
2975
2976 r = parse_argv(argc, argv);
2977 if (r <= 0)
2978 return r;
2979
2980 r = sd_bus_open_system(&bus);
2981 if (r < 0)
2982 return log_error_errno(r, "Failed to connect system bus: %m");
2983
2984 r = check_netns_match(bus);
2985 if (r < 0)
2986 return r;
2987
2988 warn_networkd_missing();
2989
2990 return networkctl_main(bus, argc, argv);
2991 }
2992
2993 DEFINE_MAIN_FUNCTION(run);
2994