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