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 = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
585 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
586 path = udev_device_get_property_value(d, "ID_PATH");
588 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
590 vendor = udev_device_get_property_value(d, "ID_VENDOR");
592 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
594 model = udev_device_get_property_value(d, "ID_MODEL");
597 link_get_type_string(iftype, d, &t);
599 sd_network_link_get_network_file(ifindex, &network);
601 printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
603 printf(" Link File: %s\n"
606 " State: %s%s%s (%s%s%s)\n",
610 on_color_operational, strna(operational_state), off_color_operational,
611 on_color_setup, strna(setup_state), off_color_setup);
614 printf(" Path: %s\n", path);
616 printf(" Driver: %s\n", driver);
618 printf(" Vendor: %s\n", vendor);
620 printf(" Model: %s\n", model);
623 _cleanup_free_ char *description = NULL;
624 char ea[ETHER_ADDR_TO_STRING_MAX];
626 ieee_oui(hwdb, &e, &description);
629 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
631 printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
635 printf(" MTU: %u\n", mtu);
637 dump_addresses(rtnl, " Address: ", ifindex);
638 dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
640 if (!strv_isempty(dns))
641 dump_list(" DNS: ", dns);
642 if (!strv_isempty(domains))
643 dump_list(" Domain: ", domains);
644 if (!strv_isempty(ntp))
645 dump_list(" NTP: ", ntp);
650 static int link_status(char **args, unsigned n) {
651 _cleanup_udev_hwdb_unref_ struct udev_hwdb *hwdb = NULL;
652 _cleanup_udev_unref_ struct udev *udev = NULL;
653 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
657 r = sd_rtnl_open(&rtnl, 0);
659 return log_error_errno(r, "Failed to connect to netlink: %m");
663 return log_error_errno(errno, "Failed to connect to udev: %m");
665 hwdb = udev_hwdb_new(udev);
667 log_debug_errno(errno, "Failed to open hardware database: %m");
669 if (n <= 1 && !arg_all) {
670 _cleanup_free_ char *operational_state = NULL;
671 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
672 _cleanup_free_ struct local_address *addresses = NULL;
673 const char *on_color_operational, *off_color_operational;
675 sd_network_get_operational_state(&operational_state);
676 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
678 printf("%s%s%s State: %s%s%s\n",
679 on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
680 on_color_operational, strna(operational_state), off_color_operational);
682 dump_addresses(rtnl, " Address: ", 0);
683 dump_gateways(rtnl, hwdb, " Gateway: ", 0);
685 sd_network_get_dns(&dns);
686 if (!strv_isempty(dns))
687 dump_list(" DNS: ", dns);
689 sd_network_get_domains(&domains);
690 if (!strv_isempty(domains))
691 dump_list(" Domain: ", domains);
693 sd_network_get_ntp(&ntp);
694 if (!strv_isempty(ntp))
695 dump_list(" NTP: ", ntp);
700 pager_open_if_enabled();
703 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
704 _cleanup_free_ LinkInfo *links = NULL;
707 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
709 return rtnl_log_create_error(r);
711 r = sd_rtnl_message_request_dump(req, true);
713 return rtnl_log_create_error(r);
715 r = sd_rtnl_call(rtnl, req, 0, &reply);
717 return log_error_errno(r, "Failed to enumerate links: %m");
719 c = decode_and_sort_links(reply, &links);
721 return rtnl_log_parse_error(c);
723 for (i = 0; i < c; i++) {
727 link_status_one(rtnl, udev, hwdb, links[i].name);
730 STRV_FOREACH(name, args + 1) {
734 link_status_one(rtnl, udev, hwdb, *name);
741 static void help(void) {
742 printf("%s [OPTIONS...]\n\n"
743 "Query and control the networking subsystem.\n\n"
744 " -h --help Show this help\n"
745 " --version Show package version\n"
746 " --no-pager Do not pipe output into a pager\n"
747 " --no-legend Do not show the headers and footers\n"
748 " -a --all Show status for all links\n\n"
751 " status LINK Show link status\n"
752 , program_invocation_short_name);
755 static int parse_argv(int argc, char *argv[]) {
763 static const struct option options[] = {
764 { "help", no_argument, NULL, 'h' },
765 { "version", no_argument, NULL, ARG_VERSION },
766 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
767 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
768 { "all", no_argument, NULL, 'a' },
777 while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
786 puts(PACKAGE_STRING);
787 puts(SYSTEMD_FEATURES);
806 assert_not_reached("Unhandled option");
813 static int networkctl_main(int argc, char *argv[]) {
815 static const struct {
823 int (* const dispatch)(char **args, unsigned n);
825 { "list", LESS, 1, list_links },
826 { "status", MORE, 1, link_status },
835 left = argc - optind;
838 /* Special rule: no arguments means "list" */
841 if (streq(argv[optind], "help")) {
846 for (i = 0; i < ELEMENTSOF(verbs); i++)
847 if (streq(argv[optind], verbs[i].verb))
850 if (i >= ELEMENTSOF(verbs)) {
851 log_error("Unknown operation %s", argv[optind]);
856 switch (verbs[i].argc_cmp) {
859 if (left != verbs[i].argc) {
860 log_error("Invalid number of arguments.");
867 if (left < verbs[i].argc) {
868 log_error("Too few arguments.");
875 if (left > verbs[i].argc) {
876 log_error("Too many arguments.");
883 assert_not_reached("Unknown comparison operator.");
886 return verbs[i].dispatch(argv + optind, left);
889 int main(int argc, char* argv[]) {
892 log_parse_environment();
895 r = parse_argv(argc, argv);
899 r = networkctl_main(argc, argv);
904 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;