1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
26 #include "sd-network.h"
33 #include "rtnl-util.h"
34 #include "udev-util.h"
35 #include "arphrd-list.h"
36 #include "local-addresses.h"
37 #include "socket-util.h"
38 #include "ether-addr-util.h"
40 static bool arg_no_pager = false;
41 static bool arg_legend = true;
42 static bool arg_all = false;
44 static void pager_open_if_enabled(void) {
52 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
56 if (iftype == ARPHRD_ETHER && d) {
57 const char *devtype, *id = NULL;
58 /* WLANs have iftype ARPHRD_ETHER, but we want
59 * to show a more useful type string for
62 devtype = udev_device_get_devtype(d);
63 if (streq_ptr(devtype, "wlan"))
65 else if (streq_ptr(devtype, "wwan"))
78 t = arphrd_to_name(iftype);
94 typedef struct LinkInfo {
100 static int link_info_compare(const void *a, const void *b) {
101 const LinkInfo *x = a, *y = b;
103 return x->ifindex - y->ifindex;
106 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
107 _cleanup_free_ LinkInfo *links = NULL;
108 size_t size = 0, c = 0;
112 for (i = m; i; i = sd_rtnl_message_next(i)) {
118 r = sd_rtnl_message_get_type(i, &type);
122 if (type != RTM_NEWLINK)
125 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
129 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
133 r = sd_rtnl_message_link_get_type(i, &iftype);
137 if (!GREEDY_REALLOC(links, size, c+1))
140 links[c].name = name;
141 links[c].ifindex = ifindex;
142 links[c].iftype = iftype;
146 qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
154 static void operational_state_to_color(const char *state, const char **on, const char **off) {
158 if (streq_ptr(state, "routable")) {
159 *on = ansi_highlight_green();
160 *off = ansi_highlight_off();
161 } else if (streq_ptr(state, "degraded")) {
162 *on = ansi_highlight_yellow();
163 *off = ansi_highlight_off();
168 static void setup_state_to_color(const char *state, const char **on, const char **off) {
172 if (streq_ptr(state, "configured")) {
173 *on = ansi_highlight_green();
174 *off = ansi_highlight_off();
175 } else if (streq_ptr(state, "configuring")) {
176 *on = ansi_highlight_yellow();
177 *off = ansi_highlight_off();
178 } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
179 *on = ansi_highlight_red();
180 *off = ansi_highlight_off();
185 static int list_links(char **args, unsigned n) {
186 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
187 _cleanup_udev_unref_ struct udev *udev = NULL;
188 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
189 _cleanup_free_ LinkInfo *links = NULL;
192 pager_open_if_enabled();
194 r = sd_rtnl_open(&rtnl, 0);
196 return log_error_errno(r, "Failed to connect to netlink: %m");
200 return log_error_errno(errno, "Failed to connect to udev: %m");
202 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
204 return rtnl_log_create_error(r);
206 r = sd_rtnl_message_request_dump(req, true);
208 return rtnl_log_create_error(r);
210 r = sd_rtnl_call(rtnl, req, 0, &reply);
212 return log_error_errno(r, "Failed to enumerate links: %m");
215 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
217 c = decode_and_sort_links(reply, &links);
219 return rtnl_log_parse_error(c);
221 for (i = 0; i < c; i++) {
222 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
223 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
224 const char *on_color_operational, *off_color_operational,
225 *on_color_setup, *off_color_setup;
226 char devid[2 + DECIMAL_STR_MAX(int)];
227 _cleanup_free_ char *t = NULL;
229 sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
230 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
232 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
233 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
235 sprintf(devid, "n%i", links[i].ifindex);
236 d = udev_device_new_from_device_id(udev, devid);
238 link_get_type_string(links[i].iftype, d, &t);
240 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
241 links[i].ifindex, links[i].name, strna(t),
242 on_color_operational, strna(operational_state), off_color_operational,
243 on_color_setup, strna(setup_state), off_color_setup);
247 printf("\n%i links listed.\n", c);
252 /* IEEE Organizationally Unique Identifier vendor string */
253 static int ieee_oui(struct udev_hwdb *hwdb, struct ether_addr *mac, char **ret) {
254 struct udev_list_entry *entry;
256 char str[strlen("OUI:XXYYXXYYXXYY") + 1];
261 /* skip commonly misused 00:00:00 (Xerox) prefix */
262 if (memcmp(mac, "\0\0\0", 3) == 0)
265 snprintf(str, sizeof(str), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
267 udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, str, 0))
268 if (strcmp(udev_list_entry_get_name(entry), "ID_OUI_FROM_DATABASE") == 0) {
269 description = strdup(udev_list_entry_get_value(entry));
280 static int get_gateway_description(
282 struct udev_hwdb *hwdb,
285 union in_addr_union *gateway,
286 char **gateway_description) {
288 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
293 assert(ifindex >= 0);
294 assert(family == AF_INET || family == AF_INET6);
296 assert(gateway_description);
298 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
302 r = sd_rtnl_message_request_dump(req, true);
306 r = sd_rtnl_call(rtnl, req, 0, &reply);
310 for (m = reply; m; m = sd_rtnl_message_next(m)) {
311 union in_addr_union gw = {};
312 struct ether_addr mac = {};
316 r = sd_rtnl_message_get_errno(m);
318 log_error_errno(r, "got error: %m");
322 r = sd_rtnl_message_get_type(m, &type);
324 log_error_errno(r, "could not get type: %m");
328 if (type != RTM_NEWNEIGH) {
329 log_error("type is not RTM_NEWNEIGH");
333 r = sd_rtnl_message_neigh_get_family(m, &fam);
335 log_error_errno(r, "could not get family: %m");
340 log_error("family is not correct");
344 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
346 log_error_errno(r, "could not get ifindex: %m");
350 if (ifindex > 0 && ifi != ifindex)
355 r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
361 r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
370 if (!in_addr_equal(fam, &gw, gateway))
373 r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
377 r = ieee_oui(hwdb, &mac, gateway_description);
387 static int dump_gateways(
389 struct udev_hwdb *hwdb,
393 _cleanup_free_ struct local_address *local = NULL;
396 n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
400 for (i = 0; i < n; i++) {
401 _cleanup_free_ char *gateway = NULL, *description = NULL;
403 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
407 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
409 log_debug_errno(r, "Could not get description of gateway: %m");
412 (int) strlen(prefix),
413 i == 0 ? prefix : "",
417 printf(" (%s)", description);
419 /* Show interface name for the entry if we show
420 * entries for all interfaces */
422 char name[IF_NAMESIZE+1];
424 if (if_indextoname(local[i].ifindex, name)) {
425 fputs(" on ", stdout);
428 printf(" on %%%i", local[i].ifindex);
437 static int dump_addresses(
442 _cleanup_free_ struct local_address *local = NULL;
445 n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
449 for (i = 0; i < n; i++) {
450 _cleanup_free_ char *pretty = NULL;
452 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
457 (int) strlen(prefix),
458 i == 0 ? prefix : "",
462 char name[IF_NAMESIZE+1];
464 if (if_indextoname(local[i].ifindex, name)) {
465 fputs(" on ", stdout);
468 printf(" on %%%i", local[i].ifindex);
477 static void dump_list(const char *prefix, char **l) {
482 (int) strlen(prefix),
483 i == l ? prefix : "",
488 static int link_status_one(
491 struct udev_hwdb *hwdb,
494 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
495 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
496 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
497 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
498 char devid[2 + DECIMAL_STR_MAX(int)];
499 _cleanup_free_ char *t = NULL, *network = NULL;
500 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
501 const char *on_color_operational, *off_color_operational,
502 *on_color_setup, *off_color_setup;
513 if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
514 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
516 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
518 return rtnl_log_create_error(r);
520 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
524 return rtnl_log_create_error(r);
526 r = sd_rtnl_call(rtnl, req, 0, &reply);
528 return log_error_errno(r, "Failed to query link: %m");
530 r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
532 return rtnl_log_parse_error(r);
534 r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
536 return rtnl_log_parse_error(r);
538 r = sd_rtnl_message_link_get_type(reply, &iftype);
540 return rtnl_log_parse_error(r);
542 have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
546 bool all_zeroes = true;
548 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
558 sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
560 sd_network_link_get_operational_state(ifindex, &operational_state);
561 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
563 sd_network_link_get_setup_state(ifindex, &setup_state);
564 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
566 sd_network_link_get_dns(ifindex, &dns);
567 sd_network_link_get_ntp(ifindex, &ntp);
568 sd_network_link_get_domains(ifindex, &domains);
569 r = sd_network_link_get_wildcard_domain(ifindex);
573 wildcard = strdup("*");
577 if (strv_consume(&domains, wildcard) < 0)
581 sprintf(devid, "n%i", ifindex);
582 d = udev_device_new_from_device_id(udev, devid);
584 link_get_type_string(iftype, d, &t);
587 link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
588 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
589 path = udev_device_get_property_value(d, "ID_PATH");
591 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
593 vendor = udev_device_get_property_value(d, "ID_VENDOR");
595 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
597 model = udev_device_get_property_value(d, "ID_MODEL");
600 sd_network_link_get_network_file(ifindex, &network);
602 printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
604 printf(" Link File: %s\n"
607 " State: %s%s%s (%s%s%s)\n",
611 on_color_operational, strna(operational_state), off_color_operational,
612 on_color_setup, strna(setup_state), off_color_setup);
615 printf(" Path: %s\n", path);
617 printf(" Driver: %s\n", driver);
619 printf(" Vendor: %s\n", vendor);
621 printf(" Model: %s\n", model);
624 _cleanup_free_ char *description = NULL;
625 char ea[ETHER_ADDR_TO_STRING_MAX];
627 ieee_oui(hwdb, &e, &description);
630 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
632 printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
636 printf(" MTU: %u\n", mtu);
638 dump_addresses(rtnl, " Address: ", ifindex);
639 dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
641 if (!strv_isempty(dns))
642 dump_list(" DNS: ", dns);
643 if (!strv_isempty(domains))
644 dump_list(" Domain: ", domains);
645 if (!strv_isempty(ntp))
646 dump_list(" NTP: ", ntp);
651 static int link_status(char **args, unsigned n) {
652 _cleanup_udev_hwdb_unref_ struct udev_hwdb *hwdb = NULL;
653 _cleanup_udev_unref_ struct udev *udev = NULL;
654 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
658 r = sd_rtnl_open(&rtnl, 0);
660 return log_error_errno(r, "Failed to connect to netlink: %m");
664 return log_error_errno(errno, "Failed to connect to udev: %m");
666 hwdb = udev_hwdb_new(udev);
668 log_debug_errno(errno, "Failed to open hardware database: %m");
670 if (n <= 1 && !arg_all) {
671 _cleanup_free_ char *operational_state = NULL;
672 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
673 _cleanup_free_ struct local_address *addresses = NULL;
674 const char *on_color_operational, *off_color_operational;
676 sd_network_get_operational_state(&operational_state);
677 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
679 printf(" State: %s%s%s\n", on_color_operational, strna(operational_state), off_color_operational);
681 dump_addresses(rtnl, " Address: ", 0);
682 dump_gateways(rtnl, hwdb, " Gateway: ", 0);
684 sd_network_get_dns(&dns);
685 if (!strv_isempty(dns))
686 dump_list(" DNS: ", dns);
688 sd_network_get_domains(&domains);
689 if (!strv_isempty(domains))
690 dump_list(" Domain: ", domains);
692 sd_network_get_ntp(&ntp);
693 if (!strv_isempty(ntp))
694 dump_list(" NTP: ", ntp);
699 pager_open_if_enabled();
702 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
703 _cleanup_free_ LinkInfo *links = NULL;
706 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
708 return rtnl_log_create_error(r);
710 r = sd_rtnl_message_request_dump(req, true);
712 return rtnl_log_create_error(r);
714 r = sd_rtnl_call(rtnl, req, 0, &reply);
716 return log_error_errno(r, "Failed to enumerate links: %m");
718 c = decode_and_sort_links(reply, &links);
720 return rtnl_log_parse_error(c);
722 for (i = 0; i < c; i++) {
726 link_status_one(rtnl, udev, hwdb, links[i].name);
729 STRV_FOREACH(name, args + 1) {
733 link_status_one(rtnl, udev, hwdb, *name);
740 static void help(void) {
741 printf("%s [OPTIONS...]\n\n"
742 "Query and control the networking subsystem.\n\n"
743 " -h --help Show this help\n"
744 " --version Show package version\n"
745 " --no-pager Do not pipe output into a pager\n"
746 " --no-legend Do not show the headers and footers\n"
747 " -a --all Show status for all links\n\n"
750 " status LINK Show link status\n"
751 , program_invocation_short_name);
754 static int parse_argv(int argc, char *argv[]) {
762 static const struct option options[] = {
763 { "help", no_argument, NULL, 'h' },
764 { "version", no_argument, NULL, ARG_VERSION },
765 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
766 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
767 { "all", no_argument, NULL, 'a' },
776 while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
785 puts(PACKAGE_STRING);
786 puts(SYSTEMD_FEATURES);
805 assert_not_reached("Unhandled option");
812 static int networkctl_main(int argc, char *argv[]) {
814 static const struct {
822 int (* const dispatch)(char **args, unsigned n);
824 { "list", LESS, 1, list_links },
825 { "status", MORE, 1, link_status },
834 left = argc - optind;
837 /* Special rule: no arguments means "list" */
840 if (streq(argv[optind], "help")) {
845 for (i = 0; i < ELEMENTSOF(verbs); i++)
846 if (streq(argv[optind], verbs[i].verb))
849 if (i >= ELEMENTSOF(verbs)) {
850 log_error("Unknown operation %s", argv[optind]);
855 switch (verbs[i].argc_cmp) {
858 if (left != verbs[i].argc) {
859 log_error("Invalid number of arguments.");
866 if (left < verbs[i].argc) {
867 log_error("Too few arguments.");
874 if (left > verbs[i].argc) {
875 log_error("Too many arguments.");
882 assert_not_reached("Unknown comparison operator.");
885 return verbs[i].dispatch(argv + optind, left);
888 int main(int argc, char* argv[]) {
891 log_parse_environment();
894 r = parse_argv(argc, argv);
898 r = networkctl_main(argc, argv);
903 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;