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