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