]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkctl.c
networkctl: add support to delete virtual netdevs
[thirdparty/systemd.git] / src / network / networkctl.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
ee8c4568 2
ee8c4568 3#include <getopt.h>
d37b7627 4#include <linux/if_addrlabel.h>
1693a943 5#include <net/if.h>
3f6fd1ba 6#include <stdbool.h>
ca78ad1d
ZJS
7#include <sys/stat.h>
8#include <sys/types.h>
9#include <unistd.h>
ee8c4568 10
914d6c09 11#include "sd-device.h"
3f6fd1ba 12#include "sd-hwdb.h"
34437b4f 13#include "sd-lldp.h"
3f6fd1ba
LP
14#include "sd-netlink.h"
15#include "sd-network.h"
ee8c4568 16
b5efdb8a 17#include "alloc-util.h"
3f6fd1ba 18#include "arphrd-list.h"
914d6c09 19#include "device-util.h"
3f6fd1ba 20#include "ether-addr-util.h"
34437b4f 21#include "fd-util.h"
81fd1dd3 22#include "hwdb-util.h"
ee8c4568 23#include "local-addresses.h"
8752c575 24#include "locale-util.h"
d37b7627 25#include "macro.h"
4e2ca442 26#include "main-func.h"
3f6fd1ba
LP
27#include "netlink-util.h"
28#include "pager.h"
6bedfcbb 29#include "parse-util.h"
294bf0c3 30#include "pretty-print.h"
9cd8c766 31#include "set.h"
db73295a 32#include "socket-util.h"
760877e9 33#include "sort-util.h"
34437b4f 34#include "sparse-endian.h"
d054f0a4 35#include "stdio-util.h"
8b43440b 36#include "string-table.h"
8752c575 37#include "string-util.h"
3f6fd1ba 38#include "strv.h"
2388b2f4 39#include "strxcpyx.h"
288a74cc 40#include "terminal-util.h"
3f6fd1ba 41#include "verbs.h"
ee8c4568 42
0221d68a 43static PagerFlags arg_pager_flags = 0;
ee8c4568 44static bool arg_legend = true;
9085f64a 45static bool arg_all = false;
ee8c4568 46
b55822c3 47static char *link_get_type_string(unsigned short iftype, sd_device *d) {
2c740afd 48 const char *t, *devtype;
ee8c4568
LP
49 char *p;
50
2c740afd
YW
51 if (d &&
52 sd_device_get_devtype(d, &devtype) >= 0 &&
53 !isempty(devtype))
54 return strdup(devtype);
ee8c4568
LP
55
56 t = arphrd_to_name(iftype);
b55822c3
JD
57 if (!t)
58 return NULL;
ee8c4568
LP
59
60 p = strdup(t);
61 if (!p)
b55822c3 62 return NULL;
ee8c4568
LP
63
64 ascii_strlower(p);
b55822c3 65 return p;
ee8c4568
LP
66}
67
7e5a080a
LP
68static void operational_state_to_color(const char *state, const char **on, const char **off) {
69 assert(on);
70 assert(off);
71
85323805 72 if (STRPTR_IN_SET(state, "routable", "enslaved")) {
7e5a080a
LP
73 *on = ansi_highlight_green();
74 *off = ansi_normal();
75 } else if (streq_ptr(state, "degraded")) {
76 *on = ansi_highlight_yellow();
77 *off = ansi_normal();
78 } else
79 *on = *off = "";
80}
81
82static void setup_state_to_color(const char *state, const char **on, const char **off) {
83 assert(on);
84 assert(off);
85
86 if (streq_ptr(state, "configured")) {
87 *on = ansi_highlight_green();
88 *off = ansi_normal();
89 } else if (streq_ptr(state, "configuring")) {
90 *on = ansi_highlight_yellow();
91 *off = ansi_normal();
1cf03a4f 92 } else if (STRPTR_IN_SET(state, "failed", "linger")) {
7e5a080a
LP
93 *on = ansi_highlight_red();
94 *off = ansi_normal();
95 } else
96 *on = *off = "";
97}
98
6d0c65ff 99typedef struct LinkInfo {
e997c4b0 100 char name[IFNAMSIZ+1];
6d0c65ff 101 int ifindex;
1c4a6088 102 unsigned short iftype;
b147503e
LP
103 struct ether_addr mac_address;
104 uint32_t mtu;
2c73f59b
SS
105 uint32_t min_mtu;
106 uint32_t max_mtu;
0307afc6
SS
107 uint32_t tx_queues;
108 uint32_t rx_queues;
b147503e
LP
109
110 bool has_mac_address:1;
111 bool has_mtu:1;
2c73f59b
SS
112 bool has_min_mtu:1;
113 bool has_max_mtu:1;
0307afc6
SS
114 bool has_tx_queues:1;
115 bool has_rx_queues:1;
6d0c65ff
LP
116} LinkInfo;
117
93bab288
YW
118static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
119 return CMP(a->ifindex, b->ifindex);
6d0c65ff
LP
120}
121
a6962904 122static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
e997c4b0 123 const char *name;
e997c4b0 124 uint16_t type;
a6962904 125 int ifindex, r;
6d0c65ff 126
e997c4b0
LP
127 assert(m);
128 assert(info);
6d0c65ff 129
e997c4b0
LP
130 r = sd_netlink_message_get_type(m, &type);
131 if (r < 0)
132 return r;
6d0c65ff 133
e997c4b0
LP
134 if (type != RTM_NEWLINK)
135 return 0;
6d0c65ff 136
a6962904 137 r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
e997c4b0
LP
138 if (r < 0)
139 return r;
6d0c65ff 140
e997c4b0
LP
141 r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name);
142 if (r < 0)
143 return r;
6d0c65ff 144
a6962904
YW
145 if (patterns) {
146 char str[DECIMAL_STR_MAX(int)];
147
148 xsprintf(str, "%i", ifindex);
149
150 if (!strv_fnmatch(patterns, str, 0) && !strv_fnmatch(patterns, name, 0))
151 return 0;
152 }
153
b147503e 154 r = sd_rtnl_message_link_get_type(m, &info->iftype);
e997c4b0
LP
155 if (r < 0)
156 return r;
6d0c65ff 157
2388b2f4 158 strscpy(info->name, sizeof info->name, name);
a6962904 159 info->ifindex = ifindex;
b147503e
LP
160
161 info->has_mac_address =
162 sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 &&
72e551f4 163 memcmp(&info->mac_address, &ETHER_ADDR_NULL, sizeof(struct ether_addr)) != 0;
b147503e
LP
164
165 info->has_mtu =
4015d106 166 sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu) >= 0 &&
b147503e 167 info->mtu > 0;
e997c4b0 168
2c73f59b
SS
169 info->has_min_mtu =
170 sd_netlink_message_read_u32(m, IFLA_MIN_MTU, &info->min_mtu) >= 0 &&
171 info->min_mtu > 0;
172
173 info->has_max_mtu =
174 sd_netlink_message_read_u32(m, IFLA_MAX_MTU, &info->max_mtu) >= 0 &&
175 info->min_mtu > 0;
176
0307afc6
SS
177 info->has_rx_queues =
178 sd_netlink_message_read_u32(m, IFLA_NUM_RX_QUEUES, &info->rx_queues) >= 0 &&
179 info->rx_queues > 0;
180
181 info->has_tx_queues =
182 sd_netlink_message_read_u32(m, IFLA_NUM_TX_QUEUES, &info->tx_queues) >= 0 &&
183 info->tx_queues > 0;
184
e997c4b0
LP
185 return 1;
186}
187
a6962904 188static int acquire_link_info(sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
4afd3348 189 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
7e5a080a
LP
190 _cleanup_free_ LinkInfo *links = NULL;
191 size_t allocated = 0, c = 0;
192 sd_netlink_message *i;
7d367b45
LP
193 int r;
194
b147503e 195 assert(rtnl);
7d367b45 196 assert(ret);
ee8c4568 197
ee8c4568
LP
198 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
199 if (r < 0)
200 return rtnl_log_create_error(r);
201
1c4baffc 202 r = sd_netlink_message_request_dump(req, true);
ee8c4568
LP
203 if (r < 0)
204 return rtnl_log_create_error(r);
205
1c4baffc 206 r = sd_netlink_call(rtnl, req, 0, &reply);
f647962d
MS
207 if (r < 0)
208 return log_error_errno(r, "Failed to enumerate links: %m");
ee8c4568 209
7e5a080a
LP
210 for (i = reply; i; i = sd_netlink_message_next(i)) {
211 if (!GREEDY_REALLOC(links, allocated, c+1))
212 return -ENOMEM;
7d367b45 213
a6962904 214 r = decode_link(i, links + c, patterns);
7e5a080a
LP
215 if (r < 0)
216 return r;
217 if (r > 0)
218 c++;
219 }
220
93bab288 221 typesafe_qsort(links, c, link_info_compare);
7e5a080a 222
1cc6c93a 223 *ret = TAKE_PTR(links);
7e5a080a
LP
224
225 return (int) c;
7d367b45 226}
ee8c4568 227
7d367b45 228static int list_links(int argc, char *argv[], void *userdata) {
b147503e 229 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
7d367b45 230 _cleanup_free_ LinkInfo *links = NULL;
b147503e
LP
231 int c, i, r;
232
233 r = sd_netlink_open(&rtnl);
234 if (r < 0)
235 return log_error_errno(r, "Failed to connect to netlink: %m");
7d367b45 236
a6962904 237 c = acquire_link_info(rtnl, argc > 1 ? argv + 1 : NULL, &links);
6d0c65ff 238 if (c < 0)
7d367b45
LP
239 return c;
240
0221d68a 241 (void) pager_open(arg_pager_flags);
7d367b45
LP
242
243 if (arg_legend)
c9cc0383 244 printf("%3s %-16s %-18s %-16s %-10s\n",
7d367b45
LP
245 "IDX",
246 "LINK",
247 "TYPE",
248 "OPERATIONAL",
249 "SETUP");
6d0c65ff
LP
250
251 for (i = 0; i < c; i++) {
ab1525bc 252 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
4afd3348 253 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
d57c365b
LP
254 const char *on_color_operational, *off_color_operational,
255 *on_color_setup, *off_color_setup;
7d6884b6 256 char devid[2 + DECIMAL_STR_MAX(int)];
ee8c4568 257 _cleanup_free_ char *t = NULL;
ee8c4568 258
4abd866d 259 (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
d57c365b
LP
260 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
261
33d5013d
LP
262 r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
263 if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
264 setup_state = strdup("unmanaged");
d57c365b 265 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
ee8c4568 266
691d4da9
LP
267 xsprintf(devid, "n%i", links[i].ifindex);
268 (void) sd_device_new_from_device_id(&d, devid);
ee8c4568 269
b55822c3 270 t = link_get_type_string(links[i].iftype, d);
ee8c4568 271
c9cc0383 272 printf("%3i %-16s %-18s %s%-16s%s %s%-10s%s\n",
d57c365b
LP
273 links[i].ifindex, links[i].name, strna(t),
274 on_color_operational, strna(operational_state), off_color_operational,
275 on_color_setup, strna(setup_state), off_color_setup);
ee8c4568
LP
276 }
277
278 if (arg_legend)
6d0c65ff 279 printf("\n%i links listed.\n", c);
ee8c4568
LP
280
281 return 0;
282}
283
c09da729 284/* IEEE Organizationally Unique Identifier vendor string */
b147503e 285static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) {
81fd1dd3 286 const char *description;
fbd0b64f 287 char modalias[STRLEN("OUI:XXYYXXYYXXYY") + 1], *desc;
81fd1dd3
TG
288 int r;
289
290 assert(ret);
c09da729 291
888943fc
LP
292 if (!hwdb)
293 return -EINVAL;
294
81fd1dd3
TG
295 if (!mac)
296 return -EINVAL;
297
c09da729
TG
298 /* skip commonly misused 00:00:00 (Xerox) prefix */
299 if (memcmp(mac, "\0\0\0", 3) == 0)
300 return -EINVAL;
301
d054f0a4
DM
302 xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR,
303 ETHER_ADDR_FORMAT_VAL(*mac));
c09da729 304
81fd1dd3
TG
305 r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
306 if (r < 0)
307 return r;
c09da729 308
81fd1dd3
TG
309 desc = strdup(description);
310 if (!desc)
311 return -ENOMEM;
c09da729 312
81fd1dd3
TG
313 *ret = desc;
314
315 return 0;
c09da729
TG
316}
317
69fb1176 318static int get_gateway_description(
1c4baffc 319 sd_netlink *rtnl,
81fd1dd3 320 sd_hwdb *hwdb,
69fb1176
LP
321 int ifindex,
322 int family,
323 union in_addr_union *gateway,
324 char **gateway_description) {
4afd3348 325 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
1c4baffc 326 sd_netlink_message *m;
c09da729
TG
327 int r;
328
329 assert(rtnl);
330 assert(ifindex >= 0);
4c701096 331 assert(IN_SET(family, AF_INET, AF_INET6));
c09da729
TG
332 assert(gateway);
333 assert(gateway_description);
334
335 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
336 if (r < 0)
337 return r;
338
1c4baffc 339 r = sd_netlink_message_request_dump(req, true);
c09da729
TG
340 if (r < 0)
341 return r;
342
1c4baffc 343 r = sd_netlink_call(rtnl, req, 0, &reply);
c09da729
TG
344 if (r < 0)
345 return r;
346
1c4baffc 347 for (m = reply; m; m = sd_netlink_message_next(m)) {
67a46833
YW
348 union in_addr_union gw = IN_ADDR_NULL;
349 struct ether_addr mac = ETHER_ADDR_NULL;
c09da729
TG
350 uint16_t type;
351 int ifi, fam;
352
1c4baffc 353 r = sd_netlink_message_get_errno(m);
c09da729
TG
354 if (r < 0) {
355 log_error_errno(r, "got error: %m");
356 continue;
357 }
358
1c4baffc 359 r = sd_netlink_message_get_type(m, &type);
c09da729
TG
360 if (r < 0) {
361 log_error_errno(r, "could not get type: %m");
362 continue;
363 }
364
365 if (type != RTM_NEWNEIGH) {
366 log_error("type is not RTM_NEWNEIGH");
367 continue;
368 }
369
370 r = sd_rtnl_message_neigh_get_family(m, &fam);
371 if (r < 0) {
372 log_error_errno(r, "could not get family: %m");
373 continue;
374 }
375
376 if (fam != family) {
377 log_error("family is not correct");
378 continue;
379 }
380
381 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
382 if (r < 0) {
144232a8 383 log_error_errno(r, "could not get ifindex: %m");
c09da729
TG
384 continue;
385 }
386
387 if (ifindex > 0 && ifi != ifindex)
388 continue;
389
390 switch (fam) {
391 case AF_INET:
1c4baffc 392 r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in);
c09da729
TG
393 if (r < 0)
394 continue;
395
396 break;
397 case AF_INET6:
1c4baffc 398 r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6);
c09da729
TG
399 if (r < 0)
400 continue;
401
402 break;
403 default:
404 continue;
405 }
406
407 if (!in_addr_equal(fam, &gw, gateway))
408 continue;
409
1c4baffc 410 r = sd_netlink_message_read_ether_addr(m, NDA_LLADDR, &mac);
c09da729
TG
411 if (r < 0)
412 continue;
413
414 r = ieee_oui(hwdb, &mac, gateway_description);
415 if (r < 0)
416 continue;
417
418 return 0;
419 }
420
421 return -ENODATA;
422}
423
69fb1176 424static int dump_gateways(
1c4baffc 425 sd_netlink *rtnl,
81fd1dd3 426 sd_hwdb *hwdb,
69fb1176
LP
427 const char *prefix,
428 int ifindex) {
b6a3ca6d
TG
429 _cleanup_free_ struct local_address *local = NULL;
430 int r, n, i;
c09da729 431
837f57da
LP
432 assert(rtnl);
433 assert(prefix);
434
b6a3ca6d
TG
435 n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
436 if (n < 0)
437 return n;
c09da729 438
b6a3ca6d
TG
439 for (i = 0; i < n; i++) {
440 _cleanup_free_ char *gateway = NULL, *description = NULL;
c09da729 441
b6a3ca6d 442 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
c09da729 443 if (r < 0)
b6a3ca6d 444 return r;
c09da729 445
69fb1176 446 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
c09da729 447 if (r < 0)
b6a3ca6d 448 log_debug_errno(r, "Could not get description of gateway: %m");
c09da729 449
1693a943
LP
450 printf("%*s%s",
451 (int) strlen(prefix),
452 i == 0 ? prefix : "",
453 gateway);
454
b6a3ca6d 455 if (description)
1693a943
LP
456 printf(" (%s)", description);
457
458 /* Show interface name for the entry if we show
459 * entries for all interfaces */
460 if (ifindex <= 0) {
461 char name[IF_NAMESIZE+1];
462
463 if (if_indextoname(local[i].ifindex, name)) {
464 fputs(" on ", stdout);
465 fputs(name, stdout);
466 } else
467 printf(" on %%%i", local[i].ifindex);
468 }
469
470 fputc('\n', stdout);
c09da729
TG
471 }
472
473 return 0;
474}
475
69fb1176 476static int dump_addresses(
1c4baffc 477 sd_netlink *rtnl,
69fb1176
LP
478 const char *prefix,
479 int ifindex) {
480
ee8c4568
LP
481 _cleanup_free_ struct local_address *local = NULL;
482 int r, n, i;
483
837f57da
LP
484 assert(rtnl);
485 assert(prefix);
486
1d050e1e 487 n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
ee8c4568
LP
488 if (n < 0)
489 return n;
490
491 for (i = 0; i < n; i++) {
492 _cleanup_free_ char *pretty = NULL;
493
494 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
495 if (r < 0)
496 return r;
497
1693a943 498 printf("%*s%s",
ee8c4568
LP
499 (int) strlen(prefix),
500 i == 0 ? prefix : "",
501 pretty);
1693a943
LP
502
503 if (ifindex <= 0) {
504 char name[IF_NAMESIZE+1];
505
506 if (if_indextoname(local[i].ifindex, name)) {
507 fputs(" on ", stdout);
508 fputs(name, stdout);
509 } else
510 printf(" on %%%i", local[i].ifindex);
511 }
512
513 fputc('\n', stdout);
ee8c4568
LP
514 }
515
516 return 0;
517}
518
d37b7627
SS
519static int dump_address_labels(sd_netlink *rtnl) {
520 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
521 sd_netlink_message *m;
522 int r;
523
524 assert(rtnl);
525
526 r = sd_rtnl_message_new_addrlabel(rtnl, &req, RTM_GETADDRLABEL, 0, AF_INET6);
527 if (r < 0)
528 return log_error_errno(r, "Could not allocate RTM_GETADDRLABEL message: %m");
529
530 r = sd_netlink_message_request_dump(req, true);
531 if (r < 0)
532 return r;
533
534 r = sd_netlink_call(rtnl, req, 0, &reply);
535 if (r < 0)
536 return r;
537
538 printf("%10s/%s %30s\n", "Prefix", "Prefixlen", "Label");
539
540 for (m = reply; m; m = sd_netlink_message_next(m)) {
541 _cleanup_free_ char *pretty = NULL;
67a46833 542 union in_addr_union prefix = IN_ADDR_NULL;
d37b7627
SS
543 uint8_t prefixlen;
544 uint32_t label;
545
546 r = sd_netlink_message_get_errno(m);
547 if (r < 0) {
548 log_error_errno(r, "got error: %m");
549 continue;
550 }
551
552 r = sd_netlink_message_read_u32(m, IFAL_LABEL, &label);
553 if (r < 0 && r != -ENODATA) {
554 log_error_errno(r, "Could not read IFAL_LABEL, ignoring: %m");
555 continue;
556 }
557
558 r = sd_netlink_message_read_in6_addr(m, IFAL_ADDRESS, &prefix.in6);
559 if (r < 0)
560 continue;
561
562 r = in_addr_to_string(AF_INET6, &prefix, &pretty);
563 if (r < 0)
564 continue;
565
566 r = sd_rtnl_message_addrlabel_get_prefixlen(m, &prefixlen);
567 if (r < 0)
568 continue;
569
570 printf("%10s/%-5u %30u\n", pretty, prefixlen, label);
571 }
572
573 return 0;
574}
575
576static int list_address_labels(int argc, char *argv[], void *userdata) {
577 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
578 int r;
579
580 r = sd_netlink_open(&rtnl);
581 if (r < 0)
582 return log_error_errno(r, "Failed to connect to netlink: %m");
583
584 dump_address_labels(rtnl);
585
586 return 0;
587}
588
837f57da
LP
589static int open_lldp_neighbors(int ifindex, FILE **ret) {
590 _cleanup_free_ char *p = NULL;
591 FILE *f;
592
593 if (asprintf(&p, "/run/systemd/netif/lldp/%i", ifindex) < 0)
594 return -ENOMEM;
595
596 f = fopen(p, "re");
597 if (!f)
598 return -errno;
599
600 *ret = f;
601 return 0;
602}
603
604static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) {
605 _cleanup_free_ void *raw = NULL;
606 size_t l;
607 le64_t u;
608 int r;
609
610 assert(f);
611 assert(ret);
612
613 l = fread(&u, 1, sizeof(u), f);
614 if (l == 0 && feof(f))
615 return 0;
616 if (l != sizeof(u))
617 return -EBADMSG;
618
d23c3e4c
FB
619 /* each LLDP packet is at most MTU size, but let's allow up to 4KiB just in case */
620 if (le64toh(u) >= 4096)
621 return -EBADMSG;
622
837f57da
LP
623 raw = new(uint8_t, le64toh(u));
624 if (!raw)
625 return -ENOMEM;
626
627 if (fread(raw, 1, le64toh(u), f) != le64toh(u))
628 return -EBADMSG;
629
630 r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u));
631 if (r < 0)
632 return r;
633
634 return 1;
635}
636
637static int dump_lldp_neighbors(const char *prefix, int ifindex) {
638 _cleanup_fclose_ FILE *f = NULL;
639 int r, c = 0;
640
641 assert(prefix);
642 assert(ifindex > 0);
643
644 r = open_lldp_neighbors(ifindex, &f);
645 if (r < 0)
646 return r;
647
648 for (;;) {
649 const char *system_name = NULL, *port_id = NULL, *port_description = NULL;
650 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
651
652 r = next_lldp_neighbor(f, &n);
653 if (r < 0)
654 return r;
655 if (r == 0)
656 break;
657
658 printf("%*s",
659 (int) strlen(prefix),
660 c == 0 ? prefix : "");
661
662 (void) sd_lldp_neighbor_get_system_name(n, &system_name);
663 (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
664 (void) sd_lldp_neighbor_get_port_description(n, &port_description);
665
666 printf("%s on port %s", strna(system_name), strna(port_id));
667
668 if (!isempty(port_description))
669 printf(" (%s)", port_description);
670
671 putchar('\n');
672
673 c++;
674 }
675
676 return c;
677}
678
b295beea
LP
679static void dump_ifindexes(const char *prefix, const int *ifindexes) {
680 unsigned c;
681
682 assert(prefix);
683
684 if (!ifindexes || ifindexes[0] <= 0)
685 return;
686
687 for (c = 0; ifindexes[c] > 0; c++) {
688 char name[IF_NAMESIZE+1];
689
690 printf("%*s",
691 (int) strlen(prefix),
692 c == 0 ? prefix : "");
693
694 if (if_indextoname(ifindexes[c], name))
695 fputs(name, stdout);
696 else
697 printf("%i", ifindexes[c]);
698
699 fputc('\n', stdout);
700 }
701}
702
ee8c4568
LP
703static void dump_list(const char *prefix, char **l) {
704 char **i;
705
dce83649
LP
706 if (strv_isempty(l))
707 return;
708
ee8c4568
LP
709 STRV_FOREACH(i, l) {
710 printf("%*s%s\n",
711 (int) strlen(prefix),
712 i == l ? prefix : "",
713 *i);
714 }
715}
716
69fb1176 717static int link_status_one(
1c4baffc 718 sd_netlink *rtnl,
81fd1dd3 719 sd_hwdb *hwdb,
b147503e
LP
720 const LinkInfo *info) {
721
3df9bec5 722 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
64d6c229 723 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
4afd3348 724 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
9085f64a 725 char devid[2 + DECIMAL_STR_MAX(int)];
373d9f17 726 _cleanup_free_ char *t = NULL, *network = NULL;
af5effc4 727 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
d57c365b
LP
728 const char *on_color_operational, *off_color_operational,
729 *on_color_setup, *off_color_setup;
b295beea 730 _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
b147503e 731 int r;
9085f64a
LP
732
733 assert(rtnl);
b147503e 734 assert(info);
9085f64a 735
b147503e 736 (void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
d57c365b
LP
737 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
738
33d5013d
LP
739 r = sd_network_link_get_setup_state(info->ifindex, &setup_state);
740 if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
741 setup_state = strdup("unmanaged");
d57c365b 742 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
9085f64a 743
b147503e
LP
744 (void) sd_network_link_get_dns(info->ifindex, &dns);
745 (void) sd_network_link_get_search_domains(info->ifindex, &search_domains);
746 (void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
747 (void) sd_network_link_get_ntp(info->ifindex, &ntp);
9085f64a 748
691d4da9 749 xsprintf(devid, "n%i", info->ifindex);
914d6c09 750
dce83649 751 (void) sd_device_new_from_device_id(&d, devid);
914d6c09 752
9085f64a 753 if (d) {
dce83649
LP
754 (void) sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
755 (void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
756 (void) sd_device_get_property_value(d, "ID_PATH", &path);
9085f64a 757
2c740afd 758 if (sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
dce83649 759 (void) sd_device_get_property_value(d, "ID_VENDOR", &vendor);
9085f64a 760
2c740afd 761 if (sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model) < 0)
dce83649 762 (void) sd_device_get_property_value(d, "ID_MODEL", &model);
9085f64a
LP
763 }
764
b55822c3 765 t = link_get_type_string(info->iftype, d);
b1acce80 766
4abd866d 767 (void) sd_network_link_get_network_file(info->ifindex, &network);
df3fb561 768
4abd866d
LP
769 (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
770 (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
0d4ad91d 771
9a6f746f 772 printf("%s%s%s %i: %s\n", on_color_operational, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off_color_operational, info->ifindex, info->name);
9085f64a 773
0307afc6
SS
774 printf(" Link File: %s\n"
775 " Network File: %s\n"
776 " Type: %s\n"
777 " State: %s%s%s (%s%s%s)\n",
af5effc4 778 strna(link),
373d9f17 779 strna(network),
9085f64a 780 strna(t),
d57c365b
LP
781 on_color_operational, strna(operational_state), off_color_operational,
782 on_color_setup, strna(setup_state), off_color_setup);
9085f64a
LP
783
784 if (path)
0307afc6 785 printf(" Path: %s\n", path);
9085f64a 786 if (driver)
0307afc6 787 printf(" Driver: %s\n", driver);
9085f64a 788 if (vendor)
0307afc6 789 printf(" Vendor: %s\n", vendor);
9085f64a 790 if (model)
0307afc6 791 printf(" Model: %s\n", model);
9085f64a 792
b147503e 793 if (info->has_mac_address) {
888943fc 794 _cleanup_free_ char *description = NULL;
db73295a 795 char ea[ETHER_ADDR_TO_STRING_MAX];
888943fc 796
4abd866d 797 (void) ieee_oui(hwdb, &info->mac_address, &description);
888943fc
LP
798
799 if (description)
0307afc6 800 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info->mac_address, ea), description);
888943fc 801 else
0307afc6 802 printf(" HW Address: %s\n", ether_addr_to_string(&info->mac_address, ea));
db73295a 803 }
9085f64a 804
b147503e 805 if (info->has_mtu)
0307afc6 806 printf(" MTU: %" PRIu32 "\n", info->mtu);
2c73f59b 807 if (info->has_min_mtu)
0307afc6 808 printf(" Minimum MTU: %" PRIu32 "\n", info->min_mtu);
2c73f59b 809 if (info->has_max_mtu)
0307afc6
SS
810 printf(" Maximum MTU: %" PRIu32 "\n", info->max_mtu);
811
812 if (info->has_tx_queues)
813 printf("Transmit Queue Length: %" PRIu32 "\n", info->tx_queues);
814 if (info->has_rx_queues)
815 printf(" Receive Queue Length: %" PRIu32 "\n", info->rx_queues);
9085f64a 816
0307afc6
SS
817 (void) dump_addresses(rtnl, " Address: ", info->ifindex);
818 (void) dump_gateways(rtnl, hwdb, " Gateway: ", info->ifindex);
9085f64a 819
0307afc6
SS
820 dump_list(" DNS: ", dns);
821 dump_list(" Search Domains: ", search_domains);
822 dump_list(" Route Domains: ", route_domains);
8eb9058d 823
0307afc6 824 dump_list(" NTP: ", ntp);
0d4ad91d 825
b295beea
LP
826 dump_ifindexes("Carrier Bound To: ", carrier_bound_to);
827 dump_ifindexes("Carrier Bound By: ", carrier_bound_by);
9085f64a 828
b147503e 829 (void) sd_network_link_get_timezone(info->ifindex, &tz);
64d6c229 830 if (tz)
0307afc6 831 printf(" Time Zone: %s\n", tz);
8eb9058d 832
0307afc6 833 (void) dump_lldp_neighbors(" Connected To: ", info->ifindex);
837f57da 834
9085f64a
LP
835 return 0;
836}
837
0070333f
LP
838static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
839 _cleanup_free_ char *operational_state = NULL;
840 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
841 const char *on_color_operational, *off_color_operational;
842
843 assert(rtnl);
844
4abd866d 845 (void) sd_network_get_operational_state(&operational_state);
0070333f
LP
846 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
847
848 printf("%s%s%s State: %s%s%s\n",
9a6f746f 849 on_color_operational, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off_color_operational,
0070333f
LP
850 on_color_operational, strna(operational_state), off_color_operational);
851
4abd866d
LP
852 (void) dump_addresses(rtnl, " Address: ", 0);
853 (void) dump_gateways(rtnl, hwdb, " Gateway: ", 0);
0070333f 854
4abd866d 855 (void) sd_network_get_dns(&dns);
0070333f
LP
856 dump_list(" DNS: ", dns);
857
4abd866d 858 (void) sd_network_get_search_domains(&search_domains);
0070333f
LP
859 dump_list("Search Domains: ", search_domains);
860
4abd866d 861 (void) sd_network_get_route_domains(&route_domains);
0070333f
LP
862 dump_list(" Route Domains: ", route_domains);
863
4abd866d 864 (void) sd_network_get_ntp(&ntp);
0070333f
LP
865 dump_list(" NTP: ", ntp);
866
867 return 0;
868}
869
266b5389 870static int link_status(int argc, char *argv[], void *userdata) {
4afd3348 871 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
b147503e
LP
872 _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
873 _cleanup_free_ LinkInfo *links = NULL;
874 int r, c, i;
ee8c4568 875
0221d68a 876 (void) pager_open(arg_pager_flags);
0070333f 877
1c4baffc 878 r = sd_netlink_open(&rtnl);
f647962d
MS
879 if (r < 0)
880 return log_error_errno(r, "Failed to connect to netlink: %m");
f7d68aa8 881
81fd1dd3
TG
882 r = sd_hwdb_new(&hwdb);
883 if (r < 0)
884 log_debug_errno(r, "Failed to open hardware database: %m");
69fb1176 885
b147503e 886 if (arg_all)
a6962904 887 c = acquire_link_info(rtnl, NULL, &links);
b147503e 888 else if (argc <= 1)
0070333f 889 return system_status(rtnl, hwdb);
b147503e 890 else
a6962904 891 c = acquire_link_info(rtnl, argv + 1, &links);
b147503e
LP
892 if (c < 0)
893 return c;
ee8c4568 894
b147503e
LP
895 for (i = 0; i < c; i++) {
896 if (i > 0)
897 fputc('\n', stdout);
ee8c4568 898
b147503e 899 link_status_one(rtnl, hwdb, links + i);
ee8c4568
LP
900 }
901
902 return 0;
903}
904
34437b4f
LP
905static char *lldp_capabilities_to_string(uint16_t x) {
906 static const char characters[] = {
907 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
908 };
909 char *ret;
910 unsigned i;
49699bac 911
34437b4f
LP
912 ret = new(char, ELEMENTSOF(characters) + 1);
913 if (!ret)
49699bac
SS
914 return NULL;
915
34437b4f
LP
916 for (i = 0; i < ELEMENTSOF(characters); i++)
917 ret[i] = (x & (1U << i)) ? characters[i] : '.';
49699bac 918
34437b4f
LP
919 ret[i] = 0;
920 return ret;
49699bac
SS
921}
922
4c3160f1
ZJS
923static void lldp_capabilities_legend(uint16_t x) {
924 unsigned w, i, cols = columns();
404d53a9 925 static const char* const table[] = {
4c3160f1
ZJS
926 "o - Other",
927 "p - Repeater",
928 "b - Bridge",
929 "w - WLAN Access Point",
930 "r - Router",
931 "t - Telephone",
932 "d - DOCSIS cable device",
933 "a - Station",
934 "c - Customer VLAN",
935 "s - Service VLAN",
936 "m - Two-port MAC Relay (TPMR)",
937 };
938
939 if (x == 0)
940 return;
941
942 printf("\nCapability Flags:\n");
943 for (w = 0, i = 0; i < ELEMENTSOF(table); i++)
944 if (x & (1U << i) || arg_all) {
945 bool newline;
946
947 newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols;
948 if (newline)
949 w = 0;
950 w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]);
951 }
952 puts("");
953}
954
49699bac 955static int link_lldp_status(int argc, char *argv[], void *userdata) {
b147503e 956 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
49699bac 957 _cleanup_free_ LinkInfo *links = NULL;
b147503e 958 int i, r, c, m = 0;
4c3160f1 959 uint16_t all = 0;
b147503e
LP
960
961 r = sd_netlink_open(&rtnl);
962 if (r < 0)
963 return log_error_errno(r, "Failed to connect to netlink: %m");
49699bac 964
a6962904 965 c = acquire_link_info(rtnl, argc > 1 ? argv + 1 : NULL, &links);
49699bac 966 if (c < 0)
7d367b45
LP
967 return c;
968
0221d68a 969 (void) pager_open(arg_pager_flags);
49699bac 970
19727828 971 if (arg_legend)
34437b4f
LP
972 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
973 "LINK",
974 "CHASSIS ID",
975 "SYSTEM NAME",
976 "CAPS",
977 "PORT ID",
978 "PORT DESCRIPTION");
49699bac 979
b147503e 980 for (i = 0; i < c; i++) {
34437b4f 981 _cleanup_fclose_ FILE *f = NULL;
49699bac 982
837f57da
LP
983 r = open_lldp_neighbors(links[i].ifindex, &f);
984 if (r == -ENOENT)
985 continue;
986 if (r < 0) {
987 log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex);
34437b4f
LP
988 continue;
989 }
49699bac 990
34437b4f 991 for (;;) {
d08191a2 992 _cleanup_free_ char *cid = NULL, *pid = NULL, *sname = NULL, *pdesc = NULL;
34437b4f
LP
993 const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL, *capabilities = NULL;
994 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
34437b4f 995 uint16_t cc;
49699bac 996
837f57da 997 r = next_lldp_neighbor(f, &n);
34437b4f 998 if (r < 0) {
837f57da 999 log_warning_errno(r, "Failed to read neighbor data: %m");
34437b4f 1000 break;
49699bac 1001 }
837f57da
LP
1002 if (r == 0)
1003 break;
34437b4f
LP
1004
1005 (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id);
1006 (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
1007 (void) sd_lldp_neighbor_get_system_name(n, &system_name);
1008 (void) sd_lldp_neighbor_get_port_description(n, &port_description);
1009
d08191a2
LP
1010 if (chassis_id) {
1011 cid = ellipsize(chassis_id, 17, 100);
1012 if (cid)
1013 chassis_id = cid;
1014 }
1015
1016 if (port_id) {
1017 pid = ellipsize(port_id, 17, 100);
1018 if (pid)
1019 port_id = pid;
1020 }
1021
1022 if (system_name) {
1023 sname = ellipsize(system_name, 16, 100);
1024 if (sname)
1025 system_name = sname;
1026 }
1027
1028 if (port_description) {
1029 pdesc = ellipsize(port_description, 16, 100);
1030 if (pdesc)
1031 port_description = pdesc;
1032 }
1033
4c3160f1 1034 if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) {
34437b4f 1035 capabilities = lldp_capabilities_to_string(cc);
4c3160f1
ZJS
1036 all |= cc;
1037 }
34437b4f
LP
1038
1039 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
1040 links[i].name,
1041 strna(chassis_id),
1042 strna(system_name),
1043 strna(capabilities),
1044 strna(port_id),
1045 strna(port_description));
b147503e
LP
1046
1047 m++;
49699bac
SS
1048 }
1049 }
1050
4c3160f1
ZJS
1051 if (arg_legend) {
1052 lldp_capabilities_legend(all);
1053 printf("\n%i neighbors listed.\n", m);
1054 }
49699bac
SS
1055
1056 return 0;
1057}
1058
9cd8c766
SS
1059static int link_delete_send_message(sd_netlink *rtnl, int index) {
1060 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
1061 int r;
1062
1063 assert(rtnl);
1064
1065 r = sd_rtnl_message_new_link(rtnl, &req, RTM_DELLINK, index);
1066 if (r < 0)
1067 return rtnl_log_create_error(r);
1068
1069 r = sd_netlink_call(rtnl, req, 0, NULL);
1070 if (r < 0)
1071 return r;
1072
1073 return 0;
1074}
1075
1076static int link_delete(int argc, char *argv[], void *userdata) {
1077 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
1078 _cleanup_set_free_ Set *indexes = NULL;
1079 char ifname[IFNAMSIZ] = "";
1080 int index, r, i;
1081 Iterator j;
1082
1083 r = sd_netlink_open(&rtnl);
1084 if (r < 0)
1085 return log_error_errno(r, "Failed to connect to netlink: %m");
1086
1087 indexes = set_new(NULL);
1088 if (!indexes)
1089 return log_oom();
1090
1091 for (i = 1; i < argc; i++) {
1092 r = parse_ifindex(argv[i], &index);
1093 if (r < 0) {
1094 index = (int) if_nametoindex(argv[i]);
1095 if (index <= 0)
1096 return log_error_errno(r, "Failed to resolve interface %s", argv[i]);
1097 }
1098
1099 r = set_put(indexes, INT_TO_PTR(index));
1100 if (r < 0)
1101 return log_oom();
1102 }
1103
1104 SET_FOREACH(index, indexes, j) {
1105 r = link_delete_send_message(rtnl, index);
1106 if (r < 0) {
1107 if (if_indextoname(index, ifname))
1108 return log_error_errno(r, "Failed to delete interface %s: %m", ifname);
1109 else
1110 return log_error_errno(r, "Failed to delete interface %d: %m", index);
1111 }
1112 }
1113
1114 return r;
1115}
1116
37ec0fdd
LP
1117static int help(void) {
1118 _cleanup_free_ char *link = NULL;
1119 int r;
1120
1121 r = terminal_urlify_man("networkctl", "1", &link);
1122 if (r < 0)
1123 return log_oom();
1124
ee8c4568
LP
1125 printf("%s [OPTIONS...]\n\n"
1126 "Query and control the networking subsystem.\n\n"
1127 " -h --help Show this help\n"
9085f64a
LP
1128 " --version Show package version\n"
1129 " --no-pager Do not pipe output into a pager\n"
1130 " --no-legend Do not show the headers and footers\n"
1131 " -a --all Show status for all links\n\n"
ee8c4568 1132 "Commands:\n"
a6962904
YW
1133 " list [PATTERN...] List links\n"
1134 " status [PATTERN...] Show link status\n"
1135 " lldp [PATTERN...] Show LLDP neighbors\n"
d37b7627 1136 " label Show current address label entries in the kernel\n"
9cd8c766 1137 " delete DEVICES Delete virtual netdevs\n"
37ec0fdd
LP
1138 "\nSee the %s for details.\n"
1139 , program_invocation_short_name
1140 , link
1141 );
1142
1143 return 0;
ee8c4568
LP
1144}
1145
1146static int parse_argv(int argc, char *argv[]) {
1147
1148 enum {
1149 ARG_VERSION = 0x100,
1150 ARG_NO_PAGER,
1151 ARG_NO_LEGEND,
1152 };
1153
1154 static const struct option options[] = {
1155 { "help", no_argument, NULL, 'h' },
1156 { "version", no_argument, NULL, ARG_VERSION },
1157 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1158 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
9085f64a 1159 { "all", no_argument, NULL, 'a' },
ee8c4568
LP
1160 {}
1161 };
1162
1163 int c;
1164
1165 assert(argc >= 0);
1166 assert(argv);
1167
9085f64a 1168 while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
ee8c4568
LP
1169
1170 switch (c) {
1171
1172 case 'h':
37ec0fdd 1173 return help();
ee8c4568
LP
1174
1175 case ARG_VERSION:
3f6fd1ba 1176 return version();
ee8c4568
LP
1177
1178 case ARG_NO_PAGER:
0221d68a 1179 arg_pager_flags |= PAGER_DISABLE;
ee8c4568
LP
1180 break;
1181
1182 case ARG_NO_LEGEND:
1183 arg_legend = false;
1184 break;
1185
9085f64a
LP
1186 case 'a':
1187 arg_all = true;
1188 break;
1189
ee8c4568
LP
1190 case '?':
1191 return -EINVAL;
1192
1193 default:
1194 assert_not_reached("Unhandled option");
1195 }
1196 }
1197
1198 return 1;
1199}
1200
1201static int networkctl_main(int argc, char *argv[]) {
15c3626e
YW
1202 static const Verb verbs[] = {
1203 { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links },
1204 { "status", VERB_ANY, VERB_ANY, 0, link_status },
1205 { "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status },
1206 { "label", VERB_ANY, VERB_ANY, 0, list_address_labels },
9cd8c766 1207 { "delete", 2, VERB_ANY, 0, link_delete },
266b5389 1208 {}
ee8c4568
LP
1209 };
1210
266b5389 1211 return dispatch_verb(argc, argv, verbs, NULL);
ee8c4568
LP
1212}
1213
58fb3678
LP
1214static void warn_networkd_missing(void) {
1215
1216 if (access("/run/systemd/netif/state", F_OK) >= 0)
1217 return;
1218
1219 fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
1220}
1221
4e2ca442 1222static int run(int argc, char* argv[]) {
ee8c4568
LP
1223 int r;
1224
1a043959 1225 log_show_color(true);
ee8c4568
LP
1226 log_parse_environment();
1227 log_open();
1228
1229 r = parse_argv(argc, argv);
1230 if (r <= 0)
4e2ca442 1231 return r;
ee8c4568 1232
58fb3678
LP
1233 warn_networkd_missing();
1234
4e2ca442 1235 return networkctl_main(argc, argv);
ee8c4568 1236}
4e2ca442
ZJS
1237
1238DEFINE_MAIN_FUNCTION(run);