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