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