]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkctl.c
networkd: add support for Uplink Failure Detection
[thirdparty/systemd.git] / src / network / networkctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdbool.h>
23 #include <getopt.h>
24 #include <net/if.h>
25
26 #include "sd-network.h"
27 #include "sd-rtnl.h"
28 #include "sd-hwdb.h"
29 #include "libudev.h"
30
31 #include "strv.h"
32 #include "build.h"
33 #include "util.h"
34 #include "pager.h"
35 #include "lldp.h"
36 #include "rtnl-util.h"
37 #include "udev-util.h"
38 #include "hwdb-util.h"
39 #include "arphrd-list.h"
40 #include "local-addresses.h"
41 #include "socket-util.h"
42 #include "ether-addr-util.h"
43 #include "verbs.h"
44
45 static bool arg_no_pager = false;
46 static bool arg_legend = true;
47 static bool arg_all = false;
48
49 static void pager_open_if_enabled(void) {
50
51 if (arg_no_pager)
52 return;
53
54 pager_open(false);
55 }
56
57 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
58 const char *t;
59 char *p;
60
61 if (iftype == ARPHRD_ETHER && d) {
62 const char *devtype, *id = NULL;
63 /* WLANs have iftype ARPHRD_ETHER, but we want
64 * to show a more useful type string for
65 * them */
66
67 devtype = udev_device_get_devtype(d);
68 if (streq_ptr(devtype, "wlan"))
69 id = "wlan";
70 else if (streq_ptr(devtype, "wwan"))
71 id = "wwan";
72
73 if (id) {
74 p = strdup(id);
75 if (!p)
76 return -ENOMEM;
77
78 *ret = p;
79 return 1;
80 }
81 }
82
83 t = arphrd_to_name(iftype);
84 if (!t) {
85 *ret = NULL;
86 return 0;
87 }
88
89 p = strdup(t);
90 if (!p)
91 return -ENOMEM;
92
93 ascii_strlower(p);
94 *ret = p;
95
96 return 0;
97 }
98
99 typedef struct LinkInfo {
100 const char *name;
101 int ifindex;
102 unsigned iftype;
103 } LinkInfo;
104
105 static int link_info_compare(const void *a, const void *b) {
106 const LinkInfo *x = a, *y = b;
107
108 return x->ifindex - y->ifindex;
109 }
110
111 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
112 _cleanup_free_ LinkInfo *links = NULL;
113 size_t size = 0, c = 0;
114 sd_rtnl_message *i;
115 int r;
116
117 for (i = m; i; i = sd_rtnl_message_next(i)) {
118 const char *name;
119 unsigned iftype;
120 uint16_t type;
121 int ifindex;
122
123 r = sd_rtnl_message_get_type(i, &type);
124 if (r < 0)
125 return r;
126
127 if (type != RTM_NEWLINK)
128 continue;
129
130 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
131 if (r < 0)
132 return r;
133
134 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
135 if (r < 0)
136 return r;
137
138 r = sd_rtnl_message_link_get_type(i, &iftype);
139 if (r < 0)
140 return r;
141
142 if (!GREEDY_REALLOC(links, size, c+1))
143 return -ENOMEM;
144
145 links[c].name = name;
146 links[c].ifindex = ifindex;
147 links[c].iftype = iftype;
148 c++;
149 }
150
151 qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
152
153 *ret = links;
154 links = NULL;
155
156 return (int) c;
157 }
158
159 static void operational_state_to_color(const char *state, const char **on, const char **off) {
160 assert(on);
161 assert(off);
162
163 if (streq_ptr(state, "routable")) {
164 *on = ansi_highlight_green();
165 *off = ansi_highlight_off();
166 } else if (streq_ptr(state, "degraded")) {
167 *on = ansi_highlight_yellow();
168 *off = ansi_highlight_off();
169 } else
170 *on = *off = "";
171 }
172
173 static void setup_state_to_color(const char *state, const char **on, const char **off) {
174 assert(on);
175 assert(off);
176
177 if (streq_ptr(state, "configured")) {
178 *on = ansi_highlight_green();
179 *off = ansi_highlight_off();
180 } else if (streq_ptr(state, "configuring")) {
181 *on = ansi_highlight_yellow();
182 *off = ansi_highlight_off();
183 } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
184 *on = ansi_highlight_red();
185 *off = ansi_highlight_off();
186 } else
187 *on = *off = "";
188 }
189
190 static int list_links(int argc, char *argv[], void *userdata) {
191 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
192 _cleanup_udev_unref_ struct udev *udev = NULL;
193 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
194 _cleanup_free_ LinkInfo *links = NULL;
195 int r, c, i;
196
197 pager_open_if_enabled();
198
199 r = sd_rtnl_open(&rtnl, 0);
200 if (r < 0)
201 return log_error_errno(r, "Failed to connect to netlink: %m");
202
203 udev = udev_new();
204 if (!udev)
205 return log_error_errno(errno, "Failed to connect to udev: %m");
206
207 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
208 if (r < 0)
209 return rtnl_log_create_error(r);
210
211 r = sd_rtnl_message_request_dump(req, true);
212 if (r < 0)
213 return rtnl_log_create_error(r);
214
215 r = sd_rtnl_call(rtnl, req, 0, &reply);
216 if (r < 0)
217 return log_error_errno(r, "Failed to enumerate links: %m");
218
219 if (arg_legend)
220 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
221
222 c = decode_and_sort_links(reply, &links);
223 if (c < 0)
224 return rtnl_log_parse_error(c);
225
226 for (i = 0; i < c; i++) {
227 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
228 _cleanup_udev_device_unref_ struct udev_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 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 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
238 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
239
240 sprintf(devid, "n%i", links[i].ifindex);
241 d = udev_device_new_from_device_id(udev, devid);
242
243 link_get_type_string(links[i].iftype, d, &t);
244
245 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
246 links[i].ifindex, links[i].name, strna(t),
247 on_color_operational, strna(operational_state), off_color_operational,
248 on_color_setup, strna(setup_state), off_color_setup);
249 }
250
251 if (arg_legend)
252 printf("\n%i links listed.\n", c);
253
254 return 0;
255 }
256
257 /* IEEE Organizationally Unique Identifier vendor string */
258 static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
259 const char *description;
260 char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
261 int r;
262
263 assert(ret);
264
265 if (!hwdb)
266 return -EINVAL;
267
268 if (!mac)
269 return -EINVAL;
270
271 /* skip commonly misused 00:00:00 (Xerox) prefix */
272 if (memcmp(mac, "\0\0\0", 3) == 0)
273 return -EINVAL;
274
275 snprintf(modalias, sizeof(modalias), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
276
277 r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
278 if (r < 0)
279 return r;
280
281 desc = strdup(description);
282 if (!desc)
283 return -ENOMEM;
284
285 *ret = desc;
286
287 return 0;
288 }
289
290 static int get_gateway_description(
291 sd_rtnl *rtnl,
292 sd_hwdb *hwdb,
293 int ifindex,
294 int family,
295 union in_addr_union *gateway,
296 char **gateway_description) {
297 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
298 sd_rtnl_message *m;
299 int r;
300
301 assert(rtnl);
302 assert(ifindex >= 0);
303 assert(family == AF_INET || family == AF_INET6);
304 assert(gateway);
305 assert(gateway_description);
306
307 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
308 if (r < 0)
309 return r;
310
311 r = sd_rtnl_message_request_dump(req, true);
312 if (r < 0)
313 return r;
314
315 r = sd_rtnl_call(rtnl, req, 0, &reply);
316 if (r < 0)
317 return r;
318
319 for (m = reply; m; m = sd_rtnl_message_next(m)) {
320 union in_addr_union gw = {};
321 struct ether_addr mac = {};
322 uint16_t type;
323 int ifi, fam;
324
325 r = sd_rtnl_message_get_errno(m);
326 if (r < 0) {
327 log_error_errno(r, "got error: %m");
328 continue;
329 }
330
331 r = sd_rtnl_message_get_type(m, &type);
332 if (r < 0) {
333 log_error_errno(r, "could not get type: %m");
334 continue;
335 }
336
337 if (type != RTM_NEWNEIGH) {
338 log_error("type is not RTM_NEWNEIGH");
339 continue;
340 }
341
342 r = sd_rtnl_message_neigh_get_family(m, &fam);
343 if (r < 0) {
344 log_error_errno(r, "could not get family: %m");
345 continue;
346 }
347
348 if (fam != family) {
349 log_error("family is not correct");
350 continue;
351 }
352
353 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
354 if (r < 0) {
355 log_error_errno(r, "could not get ifindex: %m");
356 continue;
357 }
358
359 if (ifindex > 0 && ifi != ifindex)
360 continue;
361
362 switch (fam) {
363 case AF_INET:
364 r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
365 if (r < 0)
366 continue;
367
368 break;
369 case AF_INET6:
370 r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
371 if (r < 0)
372 continue;
373
374 break;
375 default:
376 continue;
377 }
378
379 if (!in_addr_equal(fam, &gw, gateway))
380 continue;
381
382 r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
383 if (r < 0)
384 continue;
385
386 r = ieee_oui(hwdb, &mac, gateway_description);
387 if (r < 0)
388 continue;
389
390 return 0;
391 }
392
393 return -ENODATA;
394 }
395
396 static int dump_gateways(
397 sd_rtnl *rtnl,
398 sd_hwdb *hwdb,
399 const char *prefix,
400 int ifindex) {
401 _cleanup_free_ struct local_address *local = NULL;
402 int r, n, i;
403
404 n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
405 if (n < 0)
406 return n;
407
408 for (i = 0; i < n; i++) {
409 _cleanup_free_ char *gateway = NULL, *description = NULL;
410
411 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
412 if (r < 0)
413 return r;
414
415 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
416 if (r < 0)
417 log_debug_errno(r, "Could not get description of gateway: %m");
418
419 printf("%*s%s",
420 (int) strlen(prefix),
421 i == 0 ? prefix : "",
422 gateway);
423
424 if (description)
425 printf(" (%s)", description);
426
427 /* Show interface name for the entry if we show
428 * entries for all interfaces */
429 if (ifindex <= 0) {
430 char name[IF_NAMESIZE+1];
431
432 if (if_indextoname(local[i].ifindex, name)) {
433 fputs(" on ", stdout);
434 fputs(name, stdout);
435 } else
436 printf(" on %%%i", local[i].ifindex);
437 }
438
439 fputc('\n', stdout);
440 }
441
442 return 0;
443 }
444
445 static int dump_addresses(
446 sd_rtnl *rtnl,
447 const char *prefix,
448 int ifindex) {
449
450 _cleanup_free_ struct local_address *local = NULL;
451 int r, n, i;
452
453 n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
454 if (n < 0)
455 return n;
456
457 for (i = 0; i < n; i++) {
458 _cleanup_free_ char *pretty = NULL;
459
460 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
461 if (r < 0)
462 return r;
463
464 printf("%*s%s",
465 (int) strlen(prefix),
466 i == 0 ? prefix : "",
467 pretty);
468
469 if (ifindex <= 0) {
470 char name[IF_NAMESIZE+1];
471
472 if (if_indextoname(local[i].ifindex, name)) {
473 fputs(" on ", stdout);
474 fputs(name, stdout);
475 } else
476 printf(" on %%%i", local[i].ifindex);
477 }
478
479 fputc('\n', stdout);
480 }
481
482 return 0;
483 }
484
485 static void dump_list(const char *prefix, char **l) {
486 char **i;
487
488 STRV_FOREACH(i, l) {
489 printf("%*s%s\n",
490 (int) strlen(prefix),
491 i == l ? prefix : "",
492 *i);
493 }
494 }
495
496 static int link_status_one(
497 sd_rtnl *rtnl,
498 struct udev *udev,
499 sd_hwdb *hwdb,
500 const char *name) {
501
502 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
503 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
504 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
505 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
506 char devid[2 + DECIMAL_STR_MAX(int)];
507 _cleanup_free_ char *t = NULL, *network = NULL;
508 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
509 const char *on_color_operational, *off_color_operational,
510 *on_color_setup, *off_color_setup;
511 _cleanup_strv_free_ char **carrier_bound_to = NULL;
512 _cleanup_strv_free_ char **carrier_bound_by = NULL;
513 struct ether_addr e;
514 unsigned iftype;
515 int r, ifindex;
516 bool have_mac;
517 uint32_t mtu;
518
519 assert(rtnl);
520 assert(udev);
521 assert(name);
522
523 if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
524 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
525 else {
526 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
527 if (r < 0)
528 return rtnl_log_create_error(r);
529
530 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
531 }
532
533 if (r < 0)
534 return rtnl_log_create_error(r);
535
536 r = sd_rtnl_call(rtnl, req, 0, &reply);
537 if (r < 0)
538 return log_error_errno(r, "Failed to query link: %m");
539
540 r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
541 if (r < 0)
542 return rtnl_log_parse_error(r);
543
544 r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
545 if (r < 0)
546 return rtnl_log_parse_error(r);
547
548 r = sd_rtnl_message_link_get_type(reply, &iftype);
549 if (r < 0)
550 return rtnl_log_parse_error(r);
551
552 have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
553
554 if (have_mac) {
555 const uint8_t *p;
556 bool all_zeroes = true;
557
558 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
559 if (*p != 0) {
560 all_zeroes = false;
561 break;
562 }
563
564 if (all_zeroes)
565 have_mac = false;
566 }
567
568 sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
569
570 sd_network_link_get_operational_state(ifindex, &operational_state);
571 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
572
573 sd_network_link_get_setup_state(ifindex, &setup_state);
574 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
575
576 sd_network_link_get_dns(ifindex, &dns);
577 sd_network_link_get_ntp(ifindex, &ntp);
578 sd_network_link_get_domains(ifindex, &domains);
579 r = sd_network_link_get_wildcard_domain(ifindex);
580 if (r > 0) {
581 char *wildcard;
582
583 wildcard = strdup("*");
584 if (!wildcard)
585 return log_oom();
586
587 if (strv_consume(&domains, wildcard) < 0)
588 return log_oom();
589 }
590
591 sprintf(devid, "n%i", ifindex);
592 d = udev_device_new_from_device_id(udev, devid);
593 if (d) {
594 link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
595 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
596 path = udev_device_get_property_value(d, "ID_PATH");
597
598 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
599 if (!vendor)
600 vendor = udev_device_get_property_value(d, "ID_VENDOR");
601
602 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
603 if (!model)
604 model = udev_device_get_property_value(d, "ID_MODEL");
605 }
606
607 link_get_type_string(iftype, d, &t);
608
609 sd_network_link_get_network_file(ifindex, &network);
610
611 sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to);
612 sd_network_link_get_carrier_bound_by(ifindex, &carrier_bound_by);
613
614 printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
615
616 printf(" Link File: %s\n"
617 " Network File: %s\n"
618 " Type: %s\n"
619 " State: %s%s%s (%s%s%s)\n",
620 strna(link),
621 strna(network),
622 strna(t),
623 on_color_operational, strna(operational_state), off_color_operational,
624 on_color_setup, strna(setup_state), off_color_setup);
625
626 if (path)
627 printf(" Path: %s\n", path);
628 if (driver)
629 printf(" Driver: %s\n", driver);
630 if (vendor)
631 printf(" Vendor: %s\n", vendor);
632 if (model)
633 printf(" Model: %s\n", model);
634
635 if (have_mac) {
636 _cleanup_free_ char *description = NULL;
637 char ea[ETHER_ADDR_TO_STRING_MAX];
638
639 ieee_oui(hwdb, &e, &description);
640
641 if (description)
642 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
643 else
644 printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
645 }
646
647 if (mtu > 0)
648 printf(" MTU: %u\n", mtu);
649
650 dump_addresses(rtnl, " Address: ", ifindex);
651 dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
652
653 if (!strv_isempty(dns))
654 dump_list(" DNS: ", dns);
655 if (!strv_isempty(domains))
656 dump_list(" Domain: ", domains);
657 if (!strv_isempty(ntp))
658 dump_list(" NTP: ", ntp);
659
660 if (!strv_isempty(carrier_bound_to))
661 dump_list("Carrier Bound To: ", carrier_bound_to);
662
663 if (!strv_isempty(carrier_bound_by))
664 dump_list("Carrier Bound By: ", carrier_bound_by);
665
666 return 0;
667 }
668
669 static int link_status(int argc, char *argv[], void *userdata) {
670 _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
671 _cleanup_udev_unref_ struct udev *udev = NULL;
672 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
673 char **name;
674 int r;
675
676 r = sd_rtnl_open(&rtnl, 0);
677 if (r < 0)
678 return log_error_errno(r, "Failed to connect to netlink: %m");
679
680 udev = udev_new();
681 if (!udev)
682 return log_error_errno(errno, "Failed to connect to udev: %m");
683
684 r = sd_hwdb_new(&hwdb);
685 if (r < 0)
686 log_debug_errno(r, "Failed to open hardware database: %m");
687
688 if (argc <= 1 && !arg_all) {
689 _cleanup_free_ char *operational_state = NULL;
690 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
691 const char *on_color_operational, *off_color_operational;
692
693 sd_network_get_operational_state(&operational_state);
694 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
695
696 printf("%s%s%s State: %s%s%s\n",
697 on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
698 on_color_operational, strna(operational_state), off_color_operational);
699
700 dump_addresses(rtnl, " Address: ", 0);
701 dump_gateways(rtnl, hwdb, " Gateway: ", 0);
702
703 sd_network_get_dns(&dns);
704 if (!strv_isempty(dns))
705 dump_list(" DNS: ", dns);
706
707 sd_network_get_domains(&domains);
708 if (!strv_isempty(domains))
709 dump_list(" Domain: ", domains);
710
711 sd_network_get_ntp(&ntp);
712 if (!strv_isempty(ntp))
713 dump_list(" NTP: ", ntp);
714
715 return 0;
716 }
717
718 pager_open_if_enabled();
719
720 if (arg_all) {
721 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
722 _cleanup_free_ LinkInfo *links = NULL;
723 int c, i;
724
725 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
726 if (r < 0)
727 return rtnl_log_create_error(r);
728
729 r = sd_rtnl_message_request_dump(req, true);
730 if (r < 0)
731 return rtnl_log_create_error(r);
732
733 r = sd_rtnl_call(rtnl, req, 0, &reply);
734 if (r < 0)
735 return log_error_errno(r, "Failed to enumerate links: %m");
736
737 c = decode_and_sort_links(reply, &links);
738 if (c < 0)
739 return rtnl_log_parse_error(c);
740
741 for (i = 0; i < c; i++) {
742 if (i > 0)
743 fputc('\n', stdout);
744
745 link_status_one(rtnl, udev, hwdb, links[i].name);
746 }
747 } else {
748 STRV_FOREACH(name, argv + 1) {
749 if (name != argv + 1)
750 fputc('\n', stdout);
751
752 link_status_one(rtnl, udev, hwdb, *name);
753 }
754 }
755
756 return 0;
757 }
758
759 const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_;
760 LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_;
761
762 static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = {
763 [LLDP_SYSTEM_CAPABILITIES_OTHER] = "O",
764 [LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P",
765 [LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B",
766 [LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W",
767 [LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R",
768 [LLDP_SYSTEM_CAPABILITIES_PHONE] = "T",
769 [LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D",
770 [LLDP_SYSTEM_CAPABILITIES_STATION] = "A",
771 [LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C",
772 [LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S",
773 [LLDP_SYSTEM_CAPABILITIES_TPMR] = "M",
774 [_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A",
775 };
776
777 DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities);
778
779 static char *lldp_system_caps(uint16_t cap) {
780 _cleanup_free_ char *s = NULL, *t = NULL;
781 char *capability;
782
783 t = strdup("[ ");
784 if (!t)
785 return NULL;
786
787 if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) {
788 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL);
789 if (!s)
790 return NULL;
791
792 free(t);
793 t = s;
794 }
795
796 if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) {
797 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL);
798 if (!s)
799 return NULL;
800
801 free(t);
802 t = s;
803 }
804
805 if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) {
806 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL);
807 if (!s)
808 return NULL;
809
810 free(t);
811 t = s;
812 }
813
814 if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) {
815 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL);
816 if (!s)
817 return NULL;
818
819 free(t);
820 t = s;
821 }
822
823 if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) {
824 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL);
825 if (!s)
826 return NULL;
827
828 free(t);
829 t = s;
830 }
831
832 if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) {
833 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL);
834 if (!s)
835 return NULL;
836
837 free(t);
838 t = s;
839 }
840
841 if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) {
842 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL);
843 if (!s)
844 return NULL;
845
846 free(t);
847 t = s;
848 }
849
850 if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) {
851 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL);
852 if (!s)
853 return NULL;
854
855 free(t);
856 t = s;
857 }
858
859 if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) {
860 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL);
861 if (!s)
862 return NULL;
863
864 free(t);
865 t = s;
866 }
867
868 if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) {
869 s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL);
870 if (!s)
871 return NULL;
872
873 free(t);
874 t = s;
875 }
876
877 if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) {
878 s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR));
879 if (!s)
880 return NULL;
881
882 free(t);
883 }
884
885 if (!s) {
886 s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX));
887 if (!s)
888 return NULL;
889
890 free(t);
891 }
892
893 t = strappend(s, "]");
894 if (!t)
895 return NULL;
896
897 free(s);
898 capability = t;
899
900 s = NULL;
901 t = NULL;
902
903 return capability;
904 }
905
906 static int link_lldp_status(int argc, char *argv[], void *userdata) {
907 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
908 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
909 _cleanup_free_ LinkInfo *links = NULL;
910 const char *state, *word;
911
912 double ttl = -1;
913 uint32_t capability;
914 int i, r, c, j;
915 size_t ll;
916 char **s;
917
918 pager_open_if_enabled();
919
920 r = sd_rtnl_open(&rtnl, 0);
921 if (r < 0)
922 return log_error_errno(r, "Failed to connect to netlink: %m");
923
924 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
925 if (r < 0)
926 return rtnl_log_create_error(r);
927
928 r = sd_rtnl_message_request_dump(req, true);
929 if (r < 0)
930 return rtnl_log_create_error(r);
931
932 r = sd_rtnl_call(rtnl, req, 0, &reply);
933 if (r < 0)
934 return log_error_errno(r, "Failed to enumerate links: %m");
935
936 c = decode_and_sort_links(reply, &links);
937 if (c < 0)
938 return rtnl_log_parse_error(c);
939
940 if (arg_legend)
941 printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
942
943 for (i = j = 0; i < c; i++) {
944 _cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL;
945 _cleanup_strv_free_ char **l = NULL;
946
947 r = sd_network_link_get_lldp(links[i].ifindex, &lldp);
948 if (r < 0)
949 continue;
950
951 l = strv_split_newlines(lldp);
952 if (!l)
953 return -ENOMEM;
954
955 STRV_FOREACH(s, l) {
956 FOREACH_WORD_QUOTED(word, ll, *s, state) {
957 _cleanup_free_ char *t = NULL, *a = NULL, *b = NULL;
958
959 t = strndup(word, ll);
960 if (!t)
961 return -ENOMEM;
962
963 r = split_pair(t, "=", &a, &b);
964 if (r < 0)
965 continue;
966
967 if (streq(a, "_Chassis")) {
968 chassis = strdup(b);
969 if (!chassis)
970 return -ENOMEM;
971
972 } else if (streq(a, "_Port")) {
973 port = strdup(b);
974 if (!port)
975 return -ENOMEM;
976
977 } else if (streq(a, "_TTL")) {
978 long long unsigned x;
979 usec_t time;
980
981 r = safe_atollu(b, &x);
982 if (r < 0 || (usec_t) x != x)
983 return log_warning_errno(r < 0 ? r : ERANGE,
984 "Failed to parse TTL \"%s\": %m", b);
985
986 time = now(CLOCK_BOOTTIME);
987 if (x < time)
988 continue;
989
990 ttl = (double) (x - time) / USEC_PER_SEC;
991
992 } else if (streq(a, "_CAP")) {
993 sscanf(b, "%x", &capability);
994
995 cap = lldp_system_caps(capability);
996 }
997
998 }
999
1000 if (ttl >= 0) {
1001 printf("%10s %24s %16s %16f %16s\n",
1002 links[i].name,
1003 strna(chassis), strna(port),
1004 ttl, cap);
1005 j++;
1006 }
1007 }
1008 }
1009
1010 if (arg_legend) {
1011 printf("\nCapability Codes:\n"
1012 "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
1013 "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
1014 "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
1015
1016 printf("Total entries displayed: %d\n", j);
1017 }
1018
1019 return 0;
1020 }
1021
1022 static void help(void) {
1023 printf("%s [OPTIONS...]\n\n"
1024 "Query and control the networking subsystem.\n\n"
1025 " -h --help Show this help\n"
1026 " --version Show package version\n"
1027 " --no-pager Do not pipe output into a pager\n"
1028 " --no-legend Do not show the headers and footers\n"
1029 " -a --all Show status for all links\n\n"
1030 "Commands:\n"
1031 " list List links\n"
1032 " status [LINK...] Show link status\n"
1033 " lldp Show lldp information\n"
1034 , program_invocation_short_name);
1035 }
1036
1037 static int parse_argv(int argc, char *argv[]) {
1038
1039 enum {
1040 ARG_VERSION = 0x100,
1041 ARG_NO_PAGER,
1042 ARG_NO_LEGEND,
1043 };
1044
1045 static const struct option options[] = {
1046 { "help", no_argument, NULL, 'h' },
1047 { "version", no_argument, NULL, ARG_VERSION },
1048 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1049 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1050 { "all", no_argument, NULL, 'a' },
1051 {}
1052 };
1053
1054 int c;
1055
1056 assert(argc >= 0);
1057 assert(argv);
1058
1059 while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
1060
1061 switch (c) {
1062
1063 case 'h':
1064 help();
1065 return 0;
1066
1067 case ARG_VERSION:
1068 puts(PACKAGE_STRING);
1069 puts(SYSTEMD_FEATURES);
1070 return 0;
1071
1072 case ARG_NO_PAGER:
1073 arg_no_pager = true;
1074 break;
1075
1076 case ARG_NO_LEGEND:
1077 arg_legend = false;
1078 break;
1079
1080 case 'a':
1081 arg_all = true;
1082 break;
1083
1084 case '?':
1085 return -EINVAL;
1086
1087 default:
1088 assert_not_reached("Unhandled option");
1089 }
1090 }
1091
1092 return 1;
1093 }
1094
1095 static int networkctl_main(int argc, char *argv[]) {
1096 const Verb verbs[] = {
1097 { "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
1098 { "status", 1, VERB_ANY, 0, link_status },
1099 { "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status },
1100 {}
1101 };
1102
1103 return dispatch_verb(argc, argv, verbs, NULL);
1104 }
1105
1106 int main(int argc, char* argv[]) {
1107 int r;
1108
1109 log_parse_environment();
1110 log_open();
1111
1112 r = parse_argv(argc, argv);
1113 if (r <= 0)
1114 goto finish;
1115
1116 r = networkctl_main(argc, argv);
1117
1118 finish:
1119 pager_close();
1120
1121 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1122 }