networkctl.c revision d9000fd3b3ad0728832007f56e9cafacfbbe54e7
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering/***
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering This file is part of systemd.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Copyright 2014 Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering systemd is free software; you can redistribute it and/or modify it
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering under the terms of the GNU Lesser General Public License as published by
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering (at your option) any later version.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering systemd is distributed in the hope that it will be useful, but
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering Lesser General Public License for more details.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering You should have received a copy of the GNU Lesser General Public License
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering***/
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <stdbool.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <getopt.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include <net/if.h>
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "sd-network.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "sd-rtnl.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "sd-hwdb.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "libudev.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "strv.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "build.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "pager.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "lldp.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "rtnl-util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "udev-util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "hwdb-util.h"
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering#include "arphrd-list.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "local-addresses.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "socket-util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "ether-addr-util.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering#include "verbs.h"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic bool arg_no_pager = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic bool arg_legend = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic bool arg_all = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic void pager_open_if_enabled(void) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (arg_no_pager)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering pager_open(false);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic int link_get_type_string(int iftype, struct udev_device *d, char **ret) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *t;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char *p;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (iftype == ARPHRD_ETHER && d) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *devtype, *id = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering /* WLANs have iftype ARPHRD_ETHER, but we want
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * to show a more useful type string for
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * them */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering devtype = udev_device_get_devtype(d);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (streq_ptr(devtype, "wlan"))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering id = "wlan";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else if (streq_ptr(devtype, "wwan"))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering id = "wwan";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (id) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering p = strdup(id);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!p)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return -ENOMEM;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *ret = p;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 1;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering t = arphrd_to_name(iftype);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!t) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *ret = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering p = strdup(t);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!p)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return -ENOMEM;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering ascii_strlower(p);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering *ret = p;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return 0;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering}
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poetteringtypedef struct LinkInfo {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering const char *name;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering int ifindex;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering unsigned iftype;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering} LinkInfo;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poetteringstatic int link_info_compare(const void *a, const void *b) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering const LinkInfo *x = a, *y = b;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return x->ifindex - y->ifindex;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering}
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poetteringstatic int decode_and_sort_links(sd_rtnl_message *m, LinkInfo **ret) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering _cleanup_free_ LinkInfo *links = NULL;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering size_t size = 0, c = 0;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering sd_rtnl_message *i;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering int r;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering for (i = m; i; i = sd_rtnl_message_next(i)) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering const char *name;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering unsigned iftype;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering uint16_t type;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering int ifindex;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = sd_rtnl_message_get_type(i, &type);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (r < 0)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return r;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (type != RTM_NEWLINK)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering continue;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (r < 0)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return r;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = sd_rtnl_message_read_string(i, IFLA_IFNAME, &name);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (r < 0)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return r;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering r = sd_rtnl_message_link_get_type(i, &iftype);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (r < 0)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return r;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (!GREEDY_REALLOC(links, size, c+1))
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return -ENOMEM;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering links[c].name = name;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering links[c].ifindex = ifindex;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering links[c].iftype = iftype;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering c++;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering }
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *ret = links;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering links = NULL;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return (int) c;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic void operational_state_to_color(const char *state, const char **on, const char **off) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(on);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(off);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (streq_ptr(state, "routable")) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *on = ansi_highlight_green();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *off = ansi_highlight_off();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering } else if (streq_ptr(state, "degraded")) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *on = ansi_highlight_yellow();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *off = ansi_highlight_off();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering } else
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *on = *off = "";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic void setup_state_to_color(const char *state, const char **on, const char **off) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(on);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(off);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (streq_ptr(state, "configured")) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *on = ansi_highlight_green();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *off = ansi_highlight_off();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering } else if (streq_ptr(state, "configuring")) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *on = ansi_highlight_yellow();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *off = ansi_highlight_off();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *on = ansi_highlight_red();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *off = ansi_highlight_off();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering } else
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering *on = *off = "";
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poetteringstatic int list_links(int argc, char *argv[], void *userdata) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering _cleanup_udev_unref_ struct udev *udev = NULL;
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_free_ LinkInfo *links = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int r, c, i;
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering pager_open_if_enabled();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_rtnl_open(&rtnl, 0);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (r < 0)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return log_error_errno(r, "Failed to connect to netlink: %m");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering udev = udev_new();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!udev)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return log_error_errno(errno, "Failed to connect to udev: %m");
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering if (r < 0)
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering return rtnl_log_create_error(r);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering r = sd_rtnl_message_request_dump(req, true);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering if (r < 0)
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering return rtnl_log_create_error(r);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering r = sd_rtnl_call(rtnl, req, 0, &reply);
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (r < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return log_error_errno(r, "Failed to enumerate links: %m");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (arg_legend)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering c = decode_and_sort_links(reply, &links);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (c < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return rtnl_log_parse_error(c);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering for (i = 0; i < c; i++) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *d = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *on_color_operational, *off_color_operational,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *on_color_setup, *off_color_setup;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char devid[2 + DECIMAL_STR_MAX(int)];
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_free_ char *t = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sprintf(devid, "n%i", links[i].ifindex);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering d = udev_device_new_from_device_id(udev, devid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering link_get_type_string(links[i].iftype, d, &t);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering links[i].ifindex, links[i].name, strna(t),
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering on_color_operational, strna(operational_state), off_color_operational,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering on_color_setup, strna(setup_state), off_color_setup);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (arg_legend)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf("\n%i links listed.\n", c);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering/* IEEE Organizationally Unique Identifier vendor string */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *description;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering int r;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering assert(ret);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (!hwdb)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return -EINVAL;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering if (!mac)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return -EINVAL;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering /* skip commonly misused 00:00:00 (Xerox) prefix */
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (memcmp(mac, "\0\0\0", 3) == 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return -EINVAL;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering snprintf(modalias, sizeof(modalias), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac));
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return r;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering desc = strdup(description);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (!desc)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return -ENOMEM;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering *ret = desc;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return 0;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering}
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poetteringstatic int get_gateway_description(
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering sd_rtnl *rtnl,
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering sd_hwdb *hwdb,
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering int ifindex,
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering int family,
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering union in_addr_union *gateway,
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering char **gateway_description) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering sd_rtnl_message *m;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering int r;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering assert(rtnl);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering assert(ifindex >= 0);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering assert(family == AF_INET || family == AF_INET6);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering assert(gateway);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering assert(gateway_description);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return r;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_message_request_dump(req, true);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return r;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_call(rtnl, req, 0, &reply);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return r;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering for (m = reply; m; m = sd_rtnl_message_next(m)) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering union in_addr_union gw = {};
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering struct ether_addr mac = {};
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering uint16_t type;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering int ifi, fam;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_message_get_errno(m);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_error_errno(r, "got error: %m");
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_message_get_type(m, &type);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_error_errno(r, "could not get type: %m");
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (type != RTM_NEWNEIGH) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_error("type is not RTM_NEWNEIGH");
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_message_neigh_get_family(m, &fam);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_error_errno(r, "could not get family: %m");
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (fam != family) {
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering log_error("family is not correct");
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering if (r < 0) {
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering log_error_errno(r, "could not get ifindex: %m");
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering continue;
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering }
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering if (ifindex > 0 && ifi != ifindex)
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering switch (fam) {
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering case AF_INET:
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_message_read_in_addr(m, NDA_DST, &gw.in);
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering break;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering case AF_INET6:
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_message_read_in6_addr(m, NDA_DST, &gw.in6);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering break;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering default:
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (!in_addr_equal(fam, &gw, gateway))
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_message_read_ether_addr(m, NDA_LLADDR, &mac);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = ieee_oui(hwdb, &mac, gateway_description);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering continue;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return 0;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return -ENODATA;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic int dump_gateways(
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_rtnl *rtnl,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_hwdb *hwdb,
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering const char *prefix,
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering int ifindex) {
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering _cleanup_free_ struct local_address *local = NULL;
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering int r, n, i;
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering if (n < 0)
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering return n;
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering for (i = 0; i < n; i++) {
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering _cleanup_free_ char *gateway = NULL, *description = NULL;
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0)
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering return r;
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0)
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering log_debug_errno(r, "Could not get description of gateway: %m");
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering printf("%*s%s",
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering (int) strlen(prefix),
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering i == 0 ? prefix : "",
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering gateway);
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering if (description)
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering printf(" (%s)", description);
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering /* Show interface name for the entry if we show
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering * entries for all interfaces */
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering if (ifindex <= 0) {
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering char name[IF_NAMESIZE+1];
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering
f7d68aa8c9430dfddee5f913f93b405a5d75723aLennart Poettering if (if_indextoname(local[i].ifindex, name)) {
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering fputs(" on ", stdout);
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering fputs(name, stdout);
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering } else
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering printf(" on %%%i", local[i].ifindex);
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering }
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering
03cc0fd1431b82e59c11ae12a274c1f2df23169dLennart Poettering fputc('\n', stdout);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic int dump_addresses(
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering sd_rtnl *rtnl,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *prefix,
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering int ifindex) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_free_ struct local_address *local = NULL;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering int r, n, i;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (n < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return n;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering for (i = 0; i < n; i++) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_free_ char *pretty = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return r;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf("%*s%s",
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering (int) strlen(prefix),
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering i == 0 ? prefix : "",
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering pretty);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering if (ifindex <= 0) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering char name[IF_NAMESIZE+1];
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (if_indextoname(local[i].ifindex, name)) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering fputs(" on ", stdout);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering fputs(name, stdout);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering } else
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf(" on %%%i", local[i].ifindex);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering fputc('\n', stdout);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic void dump_list(const char *prefix, char **l) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char **i;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering STRV_FOREACH(i, l) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf("%*s%s\n",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering (int) strlen(prefix),
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering i == l ? prefix : "",
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering *i);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering }
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering}
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poetteringstatic int link_status_one(
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_rtnl *rtnl,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct udev *udev,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_hwdb *hwdb,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *name) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_udev_device_unref_ struct udev_device *d = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char devid[2 + DECIMAL_STR_MAX(int)];
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_free_ char *t = NULL, *network = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const char *on_color_operational, *off_color_operational,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering *on_color_setup, *off_color_setup;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering struct ether_addr e;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering unsigned iftype;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering int r, ifindex;
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering bool have_mac;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering uint32_t mtu;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(rtnl);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(udev);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering assert(name);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering else {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return rtnl_log_create_error(r);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_rtnl_message_append_string(req, IFLA_IFNAME, name);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return rtnl_log_create_error(r);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_rtnl_call(rtnl, req, 0, &reply);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return log_error_errno(r, "Failed to query link: %m");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return rtnl_log_parse_error(r);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_rtnl_message_read_string(reply, IFLA_IFNAME, &name);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r < 0)
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering return rtnl_log_parse_error(r);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering r = sd_rtnl_message_link_get_type(reply, &iftype);
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if (r < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return rtnl_log_parse_error(r);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering have_mac = sd_rtnl_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (have_mac) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering const uint8_t *p;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering bool all_zeroes = true;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (*p != 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering all_zeroes = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering break;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (all_zeroes)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering have_mac = false;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_rtnl_message_read_u32(reply, IFLA_MTU, &mtu);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_network_link_get_operational_state(ifindex, &operational_state);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_network_link_get_setup_state(ifindex, &setup_state);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_network_link_get_dns(ifindex, &dns);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_network_link_get_ntp(ifindex, &ntp);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_network_link_get_domains(ifindex, &domains);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering r = sd_network_link_get_wildcard_domain(ifindex);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (r > 0) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char *wildcard;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering wildcard = strdup("*");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!wildcard)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return log_oom();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (strv_consume(&domains, wildcard) < 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering return log_oom();
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sprintf(devid, "n%i", ifindex);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering d = udev_device_new_from_device_id(udev, devid);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (d) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering link = udev_device_get_property_value(d, "ID_NET_LINK_FILE");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering driver = udev_device_get_property_value(d, "ID_NET_DRIVER");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering path = udev_device_get_property_value(d, "ID_PATH");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering vendor = udev_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!vendor)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering vendor = udev_device_get_property_value(d, "ID_VENDOR");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering model = udev_device_get_property_value(d, "ID_MODEL_FROM_DATABASE");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!model)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering model = udev_device_get_property_value(d, "ID_MODEL");
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering link_get_type_string(iftype, d, &t);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering sd_network_link_get_network_file(ifindex, &network);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf(" Link File: %s\n"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering "Network File: %s\n"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering " Type: %s\n"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering " State: %s%s%s (%s%s%s)\n",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering strna(link),
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering strna(network),
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering strna(t),
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering on_color_operational, strna(operational_state), off_color_operational,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering on_color_setup, strna(setup_state), off_color_setup);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (path)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf(" Path: %s\n", path);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (driver)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf(" Driver: %s\n", driver);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (vendor)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf(" Vendor: %s\n", vendor);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (model)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf(" Model: %s\n", model);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (have_mac) {
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering _cleanup_free_ char *description = NULL;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering char ea[ETHER_ADDR_TO_STRING_MAX];
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ieee_oui(hwdb, &e, &description);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (description)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering }
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (mtu > 0)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering printf(" MTU: %u\n", mtu);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering dump_addresses(rtnl, " Address: ", ifindex);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!strv_isempty(dns))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering dump_list(" DNS: ", dns);
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if (!strv_isempty(domains))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering dump_list(" Domain: ", domains);
if (!strv_isempty(ntp))
dump_list(" NTP: ", ntp);
return 0;
}
static int link_status(int argc, char *argv[], void *userdata) {
_cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL;
_cleanup_udev_unref_ struct udev *udev = NULL;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
char **name;
int r;
r = sd_rtnl_open(&rtnl, 0);
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
udev = udev_new();
if (!udev)
return log_error_errno(errno, "Failed to connect to udev: %m");
r = sd_hwdb_new(&hwdb);
if (r < 0)
log_debug_errno(r, "Failed to open hardware database: %m");
if (argc <= 1 && !arg_all) {
_cleanup_free_ char *operational_state = NULL;
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL;
const char *on_color_operational, *off_color_operational;
sd_network_get_operational_state(&operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
printf("%s%s%s State: %s%s%s\n",
on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
on_color_operational, strna(operational_state), off_color_operational);
dump_addresses(rtnl, " Address: ", 0);
dump_gateways(rtnl, hwdb, " Gateway: ", 0);
sd_network_get_dns(&dns);
if (!strv_isempty(dns))
dump_list(" DNS: ", dns);
sd_network_get_domains(&domains);
if (!strv_isempty(domains))
dump_list(" Domain: ", domains);
sd_network_get_ntp(&ntp);
if (!strv_isempty(ntp))
dump_list(" NTP: ", ntp);
return 0;
}
pager_open_if_enabled();
if (arg_all) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
_cleanup_free_ LinkInfo *links = NULL;
int c, i;
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
if (r < 0)
return rtnl_log_create_error(r);
r = sd_rtnl_message_request_dump(req, true);
if (r < 0)
return rtnl_log_create_error(r);
r = sd_rtnl_call(rtnl, req, 0, &reply);
if (r < 0)
return log_error_errno(r, "Failed to enumerate links: %m");
c = decode_and_sort_links(reply, &links);
if (c < 0)
return rtnl_log_parse_error(c);
for (i = 0; i < c; i++) {
if (i > 0)
fputc('\n', stdout);
link_status_one(rtnl, udev, hwdb, links[i].name);
}
} else {
STRV_FOREACH(name, argv + 1) {
if (name != argv + 1)
fputc('\n', stdout);
link_status_one(rtnl, udev, hwdb, *name);
}
}
return 0;
}
const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_;
LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_;
static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = {
[LLDP_SYSTEM_CAPABILITIES_OTHER] = "O",
[LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P",
[LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B",
[LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W",
[LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R",
[LLDP_SYSTEM_CAPABILITIES_PHONE] = "T",
[LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D",
[LLDP_SYSTEM_CAPABILITIES_STATION] = "A",
[LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C",
[LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S",
[LLDP_SYSTEM_CAPABILITIES_TPMR] = "M",
[_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A",
};
DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities);
static char *lldp_system_caps(uint16_t cap) {
_cleanup_free_ char *s = NULL, *t = NULL;
char *capability;
t = strdup("[ ");
if (!t)
return NULL;
if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) {
s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL);
if (!s)
return NULL;
free(t);
t = s;
}
if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) {
s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR));
if (!s)
return NULL;
free(t);
}
if (!s) {
s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX));
if (!s)
return NULL;
free(t);
}
t = strappend(s, "]");
if (!t)
return NULL;
free(s);
capability = t;
s = NULL;
t = NULL;
return capability;
}
static int link_lldp_status(int argc, char *argv[], void *userdata) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
_cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
_cleanup_free_ LinkInfo *links = NULL;
const char *state, *word;
double ttl = -1;
uint32_t capability;
int i, r, c, j;
size_t ll;
char **s;
pager_open_if_enabled();
r = sd_rtnl_open(&rtnl, 0);
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
if (r < 0)
return rtnl_log_create_error(r);
r = sd_rtnl_message_request_dump(req, true);
if (r < 0)
return rtnl_log_create_error(r);
r = sd_rtnl_call(rtnl, req, 0, &reply);
if (r < 0)
return log_error_errno(r, "Failed to enumerate links: %m");
c = decode_and_sort_links(reply, &links);
if (c < 0)
return rtnl_log_parse_error(c);
if (arg_legend)
printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
for (i = j = 0; i < c; i++) {
_cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL;
_cleanup_strv_free_ char **l = NULL;
r = sd_network_link_get_lldp(links[i].ifindex, &lldp);
if (r < 0)
continue;
l = strv_split_newlines(lldp);
if (!l)
return -ENOMEM;
STRV_FOREACH(s, l) {
FOREACH_WORD_QUOTED(word, ll, *s, state) {
_cleanup_free_ char *t = NULL, *a = NULL, *b = NULL;
t = strndup(word, ll);
if (!t)
return -ENOMEM;
r = split_pair(t, "=", &a, &b);
if (r < 0)
continue;
if (streq(a, "_Chassis")) {
chassis = strdup(b);
if (!chassis)
return -ENOMEM;
} else if (streq(a, "_Port")) {
port = strdup(b);
if (!port)
return -ENOMEM;
} else if (streq(a, "_TTL")) {
long long unsigned x;
usec_t time;
r = safe_atollu(b, &x);
if (r < 0 || (usec_t) x != x)
return log_warning_errno(r < 0 ? r : ERANGE,
"Failed to parse TTL \"%s\": %m", b);
time = now(CLOCK_BOOTTIME);
if (x < time)
continue;
ttl = (double) (x - time) / USEC_PER_SEC;
} else if (streq(a, "_CAP")) {
sscanf(b, "%x", &capability);
cap = lldp_system_caps(capability);
}
}
if (ttl >= 0) {
printf("%10s %24s %16s %16f %16s\n",
links[i].name,
strna(chassis), strna(port),
ttl, cap);
j++;
}
}
}
if (arg_legend) {
printf("\nCapability Codes:\n"
"(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
"(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
"(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
printf("Total entries displayed: %d\n", j);
}
return 0;
}
static void help(void) {
printf("%s [OPTIONS...]\n\n"
"Query and control the networking subsystem.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" -a --all Show status for all links\n\n"
"Commands:\n"
" list List links\n"
" status [LINK...] Show link status\n"
" lldp Show lldp information\n"
, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_NO_LEGEND,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "all", no_argument, NULL, 'a' },
{}
};
int c;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "ha", options, NULL)) >= 0) {
switch (c) {
case 'h':
help();
return 0;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case ARG_NO_LEGEND:
arg_legend = false;
break;
case 'a':
arg_all = true;
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
}
return 1;
}
static int networkctl_main(int argc, char *argv[]) {
const Verb verbs[] = {
{ "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
{ "status", 1, VERB_ANY, 0, link_status },
{ "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status },
{}
};
return dispatch_verb(argc, argv, verbs, NULL);
}
int main(int argc, char* argv[]) {
int r;
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = networkctl_main(argc, argv);
finish:
pager_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}