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