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"
35 #include "rtnl-util.h"
36 #include "udev-util.h"
37 #include "hwdb-util.h"
38 #include "arphrd-list.h"
39 #include "local-addresses.h"
40 #include "socket-util.h"
41 #include "ether-addr-util.h"
44 static bool arg_no_pager = false;
45 static bool arg_legend = true;
46 static bool arg_all = false;
48 static void pager_open_if_enabled(void) {
56 static int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
60 if (iftype == ARPHRD_ETHER && d) {
61 const char *devtype, *id = NULL;
62 /* WLANs have iftype ARPHRD_ETHER, but we want
63 * to show a more useful type string for
66 devtype = udev_device_get_devtype(d);
67 if (streq_ptr(devtype, "wlan"))
69 else if (streq_ptr(devtype, "wwan"))
82 t = arphrd_to_name(iftype);
98 typedef struct LinkInfo {
104 static int link_info_compare(const void *a, const void *b) {
105 const LinkInfo *x = a, *y = b;
107 return x->ifindex - y->ifindex;
110 static int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
111 _cleanup_free_ LinkInfo *links = NULL;
112 size_t size = 0, c = 0;
116 for (i = m; i; i = sd_rtnl_message_next(i)) {
122 r = sd_rtnl_message_get_type(i, &type);
126 if (type != RTM_NEWLINK)
129 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
133 r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
137 r = sd_rtnl_message_link_get_type(i, &iftype);
141 if (!GREEDY_REALLOC(links, size, c+1))
144 links[c].name = name;
145 links[c].ifindex = ifindex;
146 links[c].iftype = iftype;
150 qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
158 static void operational_state_to_color(const char *state, const char **on, const char **off) {
162 if (streq_ptr(state, "routable")) {
163 *on = ansi_highlight_green();
164 *off = ansi_highlight_off();
165 } else if (streq_ptr(state, "degraded")) {
166 *on = ansi_highlight_yellow();
167 *off = ansi_highlight_off();
172 static void setup_state_to_color(const char *state, const char **on, const char **off) {
176 if (streq_ptr(state, "configured")) {
177 *on = ansi_highlight_green();
178 *off = ansi_highlight_off();
179 } else if (streq_ptr(state, "configuring")) {
180 *on = ansi_highlight_yellow();
181 *off = ansi_highlight_off();
182 } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
183 *on = ansi_highlight_red();
184 *off = ansi_highlight_off();
189 static int list_links(int argc, char *argv[], void *userdata) {
190 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
191 _cleanup_udev_unref_ struct udev *udev = NULL;
192 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
193 _cleanup_free_ LinkInfo *links = NULL;
196 pager_open_if_enabled();
198 r = sd_rtnl_open(&rtnl, 0);
200 return log_error_errno(r, "Failed to connect to netlink: %m");
204 return log_error_errno(errno, "Failed to connect to udev: %m");
206 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
208 return rtnl_log_create_error(r);
210 r = sd_rtnl_message_request_dump(req, true);
212 return rtnl_log_create_error(r);
214 r = sd_rtnl_call(rtnl, req, 0, &reply);
216 return log_error_errno(r, "Failed to enumerate links: %m");
219 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
221 c = decode_and_sort_links(reply, &links);
223 return rtnl_log_parse_error(c);
225 for (i = 0; i < c; i++) {
226 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
227 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
228 const char *on_color_operational, *off_color_operational,
229 *on_color_setup, *off_color_setup;
230 char devid[2 + DECIMAL_STR_MAX(int)];
231 _cleanup_free_ char *t = NULL;
233 sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
234 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
236 sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
237 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
239 sprintf(devid, "n%i", links[i].ifindex);
240 d = udev_device_new_from_device_id(udev, devid);
242 link_get_type_string(links[i].iftype, d, &t);
244 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
245 links[i].ifindex, links[i].name, strna(t),
246 on_color_operational, strna(operational_state), off_color_operational,
247 on_color_setup, strna(setup_state), off_color_setup);
251 printf("\n%i links listed.\n", c);
256 /* IEEE Organizationally Unique Identifier vendor string */
257 static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
258 const char *description;
259 char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
270 /* skip commonly misused 00:00:00 (Xerox) prefix */
271 if (memcmp(mac, "\0\0\0", 3) == 0)
274 snprintf(modalias, sizeof(modalias), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
276 r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
280 desc = strdup(description);
289 static int get_gateway_description(
294 union in_addr_union *gateway,
295 char **gateway_description) {
296 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
301 assert(ifindex >= 0);
302 assert(family == AF_INET || family == AF_INET6);
304 assert(gateway_description);
306 r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
310 r = sd_rtnl_message_request_dump(req, true);
314 r = sd_rtnl_call(rtnl, req, 0, &reply);
318 for (m = reply; m; m = sd_rtnl_message_next(m)) {
319 union in_addr_union gw = {};
320 struct ether_addr mac = {};
324 r = sd_rtnl_message_get_errno(m);
326 log_error_errno(r, "got error: %m");
330 r = sd_rtnl_message_get_type(m, &type);
332 log_error_errno(r, "could not get type: %m");
336 if (type != RTM_NEWNEIGH) {
337 log_error("type is not RTM_NEWNEIGH");
341 r = sd_rtnl_message_neigh_get_family(m, &fam);
343 log_error_errno(r, "could not get family: %m");
348 log_error("family is not correct");
352 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
354 log_error_errno(r, "could not get ifindex: %m");
358 if (ifindex > 0 && ifi != ifindex)
363 r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
369 r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
378 if (!in_addr_equal(fam, &gw, gateway))
381 r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
385 r = ieee_oui(hwdb, &mac, gateway_description);
395 static int dump_gateways(
400 _cleanup_free_ struct local_address *local = NULL;
403 n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
407 for (i = 0; i < n; i++) {
408 _cleanup_free_ char *gateway = NULL, *description = NULL;
410 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
414 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
416 log_debug_errno(r, "Could not get description of gateway: %m");
419 (int) strlen(prefix),
420 i == 0 ? prefix : "",
424 printf(" (%s)", description);
426 /* Show interface name for the entry if we show
427 * entries for all interfaces */
429 char name[IF_NAMESIZE+1];
431 if (if_indextoname(local[i].ifindex, name)) {
432 fputs(" on ", stdout);
435 printf(" on %%%i", local[i].ifindex);
444 static int dump_addresses(
449 _cleanup_free_ struct local_address *local = NULL;
452 n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
456 for (i = 0; i < n; i++) {
457 _cleanup_free_ char *pretty = NULL;
459 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
464 (int) strlen(prefix),
465 i == 0 ? prefix : "",
469 char name[IF_NAMESIZE+1];
471 if (if_indextoname(local[i].ifindex, name)) {
472 fputs(" on ", stdout);
475 printf(" on %%%i", local[i].ifindex);
484 static void dump_list(const char *prefix, char **l) {
489 (int) strlen(prefix),
490 i == l ? prefix : "",
495 static int link_status_one(
501 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
502 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
503 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
504 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
505 char devid[2 + DECIMAL_STR_MAX(int)];
506 _cleanup_free_ char *t = NULL, *network = NULL;
507 const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
508 const char *on_color_operational, *off_color_operational,
509 *on_color_setup, *off_color_setup;
520 if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
521 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
523 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
525 return rtnl_log_create_error(r);
527 r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
531 return rtnl_log_create_error(r);
533 r = sd_rtnl_call(rtnl, req, 0, &reply);
535 return log_error_errno(r, "Failed to query link: %m");
537 r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
539 return rtnl_log_parse_error(r);
541 r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
543 return rtnl_log_parse_error(r);
545 r = sd_rtnl_message_link_get_type(reply, &iftype);
547 return rtnl_log_parse_error(r);
549 have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
553 bool all_zeroes = true;
555 for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
565 sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
567 sd_network_link_get_operational_state(ifindex, &operational_state);
568 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
570 sd_network_link_get_setup_state(ifindex, &setup_state);
571 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
573 sd_network_link_get_dns(ifindex, &dns);
574 sd_network_link_get_ntp(ifindex, &ntp);
575 sd_network_link_get_domains(ifindex, &domains);
576 r = sd_network_link_get_wildcard_domain(ifindex);
580 wildcard = strdup("*");
584 if (strv_consume(&domains, wildcard) < 0)
588 sprintf(devid, "n%i", ifindex);
589 d = udev_device_new_from_device_id(udev, devid);
591 link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
592 driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
593 path = udev_device_get_property_value(d, "ID_PATH");
595 vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
597 vendor = udev_device_get_property_value(d, "ID_VENDOR");
599 model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
601 model = udev_device_get_property_value(d, "ID_MODEL");
604 link_get_type_string(iftype, d, &t);
606 sd_network_link_get_network_file(ifindex, &network);
608 printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
610 printf(" Link File: %s\n"
613 " State: %s%s%s (%s%s%s)\n",
617 on_color_operational, strna(operational_state), off_color_operational,
618 on_color_setup, strna(setup_state), off_color_setup);
621 printf(" Path: %s\n", path);
623 printf(" Driver: %s\n", driver);
625 printf(" Vendor: %s\n", vendor);
627 printf(" Model: %s\n", model);
630 _cleanup_free_ char *description = NULL;
631 char ea[ETHER_ADDR_TO_STRING_MAX];
633 ieee_oui(hwdb, &e, &description);
636 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
638 printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
642 printf(" MTU: %u\n", mtu);
644 dump_addresses(rtnl, " Address: ", ifindex);
645 dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
647 if (!strv_isempty(dns))
648 dump_list(" DNS: ", dns);
649 if (!strv_isempty(domains))
650 dump_list(" Domain: ", domains);
651 if (!strv_isempty(ntp))
652 dump_list(" NTP: ", ntp);
657 static int link_status(int argc, char *argv[], void *userdata) {
658 _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
659 _cleanup_udev_unref_ struct udev *udev = NULL;
660 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
664 r = sd_rtnl_open(&rtnl, 0);
666 return log_error_errno(r, "Failed to connect to netlink: %m");
670 return log_error_errno(errno, "Failed to connect to udev: %m");
672 r = sd_hwdb_new(&hwdb);
674 log_debug_errno(r, "Failed to open hardware database: %m");
676 if (argc <= 1 && !arg_all) {
677 _cleanup_free_ char *operational_state = NULL;
678 _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
679 const char *on_color_operational, *off_color_operational;
681 sd_network_get_operational_state(&operational_state);
682 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
684 printf("%s%s%s State: %s%s%s\n",
685 on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
686 on_color_operational, strna(operational_state), off_color_operational);
688 dump_addresses(rtnl, " Address: ", 0);
689 dump_gateways(rtnl, hwdb, " Gateway: ", 0);
691 sd_network_get_dns(&dns);
692 if (!strv_isempty(dns))
693 dump_list(" DNS: ", dns);
695 sd_network_get_domains(&domains);
696 if (!strv_isempty(domains))
697 dump_list(" Domain: ", domains);
699 sd_network_get_ntp(&ntp);
700 if (!strv_isempty(ntp))
701 dump_list(" NTP: ", ntp);
706 pager_open_if_enabled();
709 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
710 _cleanup_free_ LinkInfo *links = NULL;
713 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
715 return rtnl_log_create_error(r);
717 r = sd_rtnl_message_request_dump(req, true);
719 return rtnl_log_create_error(r);
721 r = sd_rtnl_call(rtnl, req, 0, &reply);
723 return log_error_errno(r, "Failed to enumerate links: %m");
725 c = decode_and_sort_links(reply, &links);
727 return rtnl_log_parse_error(c);
729 for (i = 0; i < c; i++) {
733 link_status_one(rtnl, udev, hwdb, links[i].name);
736 STRV_FOREACH(name, argv + 1) {
737 if (name != argv + 1)
740 link_status_one(rtnl, udev, hwdb, *name);
747 static void help(void) {
748 printf("%s [OPTIONS...]\n\n"
749 "Query and control the networking subsystem.\n\n"
750 " -h --help Show this help\n"
751 " --version Show package version\n"
752 " --no-pager Do not pipe output into a pager\n"
753 " --no-legend Do not show the headers and footers\n"
754 " -a --all Show status for all links\n\n"
757 " status LINK Show link status\n"
758 , program_invocation_short_name);
761 static int parse_argv(int argc, char *argv[]) {
769 static const struct option options[] = {
770 { "help", no_argument, NULL, 'h' },
771 { "version", no_argument, NULL, ARG_VERSION },
772 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
773 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
774 { "all", no_argument, NULL, 'a' },
783 while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
792 puts(PACKAGE_STRING);
793 puts(SYSTEMD_FEATURES);
812 assert_not_reached("Unhandled option");
819 static int networkctl_main(int argc, char *argv[]) {
820 const Verb verbs[] = {
821 { "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
822 { "status", 1, VERB_ANY, 0, link_status },
826 return dispatch_verb(argc, argv, verbs, NULL);
829 int main(int argc, char* argv[]) {
832 log_parse_environment();
835 r = parse_argv(argc, argv);
839 r = networkctl_main(argc, argv);
844 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;