LCOV - code coverage report
Current view: top level - network - networkctl.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 23 956 2.4 %
Date: 2019-08-22 15:41:25 Functions: 4 35 11.4 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <getopt.h>
       4             : #include <linux/if_addrlabel.h>
       5             : #include <net/if.h>
       6             : #include <stdbool.h>
       7             : #include <sys/stat.h>
       8             : #include <sys/types.h>
       9             : #include <unistd.h>
      10             : 
      11             : #include "sd-bus.h"
      12             : #include "sd-device.h"
      13             : #include "sd-hwdb.h"
      14             : #include "sd-lldp.h"
      15             : #include "sd-netlink.h"
      16             : #include "sd-network.h"
      17             : 
      18             : #include "alloc-util.h"
      19             : #include "arphrd-list.h"
      20             : #include "bus-common-errors.h"
      21             : #include "bus-error.h"
      22             : #include "bus-util.h"
      23             : #include "device-util.h"
      24             : #include "ether-addr-util.h"
      25             : #include "ethtool-util.h"
      26             : #include "fd-util.h"
      27             : #include "format-table.h"
      28             : #include "format-util.h"
      29             : #include "hwdb-util.h"
      30             : #include "local-addresses.h"
      31             : #include "locale-util.h"
      32             : #include "macro.h"
      33             : #include "main-func.h"
      34             : #include "netlink-util.h"
      35             : #include "pager.h"
      36             : #include "parse-util.h"
      37             : #include "pretty-print.h"
      38             : #include "set.h"
      39             : #include "socket-util.h"
      40             : #include "sort-util.h"
      41             : #include "sparse-endian.h"
      42             : #include "stdio-util.h"
      43             : #include "string-table.h"
      44             : #include "string-util.h"
      45             : #include "strv.h"
      46             : #include "strxcpyx.h"
      47             : #include "terminal-util.h"
      48             : #include "verbs.h"
      49             : 
      50             : /* Kernel defines MODULE_NAME_LEN as 64 - sizeof(unsigned long). So, 64 is enough. */
      51             : #define NETDEV_KIND_MAX 64
      52             : 
      53             : static PagerFlags arg_pager_flags = 0;
      54             : static bool arg_legend = true;
      55             : static bool arg_all = false;
      56             : static bool arg_stats = false;
      57             : 
      58           0 : static char *link_get_type_string(unsigned short iftype, sd_device *d) {
      59             :         const char *t, *devtype;
      60             :         char *p;
      61             : 
      62           0 :         if (d &&
      63           0 :             sd_device_get_devtype(d, &devtype) >= 0 &&
      64           0 :             !isempty(devtype))
      65           0 :                 return strdup(devtype);
      66             : 
      67           0 :         t = arphrd_to_name(iftype);
      68           0 :         if (!t)
      69           0 :                 return NULL;
      70             : 
      71           0 :         p = strdup(t);
      72           0 :         if (!p)
      73           0 :                 return NULL;
      74             : 
      75           0 :         ascii_strlower(p);
      76           0 :         return p;
      77             : }
      78             : 
      79           0 : static void operational_state_to_color(const char *state, const char **on, const char **off) {
      80           0 :         assert(on);
      81           0 :         assert(off);
      82             : 
      83           0 :         if (STRPTR_IN_SET(state, "routable", "enslaved")) {
      84           0 :                 *on = ansi_highlight_green();
      85           0 :                 *off = ansi_normal();
      86           0 :         } else if (streq_ptr(state, "degraded")) {
      87           0 :                 *on = ansi_highlight_yellow();
      88           0 :                 *off = ansi_normal();
      89             :         } else
      90           0 :                 *on = *off = "";
      91           0 : }
      92             : 
      93           0 : static void setup_state_to_color(const char *state, const char **on, const char **off) {
      94           0 :         assert(on);
      95           0 :         assert(off);
      96             : 
      97           0 :         if (streq_ptr(state, "configured")) {
      98           0 :                 *on = ansi_highlight_green();
      99           0 :                 *off = ansi_normal();
     100           0 :         } else if (streq_ptr(state, "configuring")) {
     101           0 :                 *on = ansi_highlight_yellow();
     102           0 :                 *off = ansi_normal();
     103           0 :         } else if (STRPTR_IN_SET(state, "failed", "linger")) {
     104           0 :                 *on = ansi_highlight_red();
     105           0 :                 *off = ansi_normal();
     106             :         } else
     107           0 :                 *on = *off = "";
     108           0 : }
     109             : 
     110             : typedef struct VxLanInfo {
     111             :         uint32_t vni;
     112             :         uint32_t link;
     113             : 
     114             :         int local_family;
     115             :         int group_family;
     116             : 
     117             :         union in_addr_union local;
     118             :         union in_addr_union group;
     119             : 
     120             :         uint16_t dest_port;
     121             : 
     122             : } VxLanInfo;
     123             : 
     124             : typedef struct LinkInfo {
     125             :         char name[IFNAMSIZ+1];
     126             :         char netdev_kind[NETDEV_KIND_MAX];
     127             :         int ifindex;
     128             :         unsigned short iftype;
     129             :         struct ether_addr mac_address;
     130             :         uint32_t mtu;
     131             :         uint32_t min_mtu;
     132             :         uint32_t max_mtu;
     133             :         uint32_t tx_queues;
     134             :         uint32_t rx_queues;
     135             : 
     136             :         union {
     137             :                 struct rtnl_link_stats64 stats64;
     138             :                 struct rtnl_link_stats stats;
     139             :         };
     140             : 
     141             :         uint64_t tx_bitrate;
     142             :         uint64_t rx_bitrate;
     143             : 
     144             :         /* bridge info */
     145             :         uint32_t forward_delay;
     146             :         uint32_t hello_time;
     147             :         uint32_t max_age;
     148             :         uint32_t ageing_time;
     149             :         uint32_t stp_state;
     150             :         uint16_t priority;
     151             :         uint8_t mcast_igmp_version;
     152             : 
     153             :         /* vxlan info */
     154             :         VxLanInfo vxlan_info;
     155             : 
     156             :         /* ethtool info */
     157             :         int autonegotiation;
     158             :         size_t speed;
     159             :         Duplex duplex;
     160             :         NetDevPort port;
     161             : 
     162             :         bool has_mac_address:1;
     163             :         bool has_tx_queues:1;
     164             :         bool has_rx_queues:1;
     165             :         bool has_stats64:1;
     166             :         bool has_stats:1;
     167             :         bool has_bitrates:1;
     168             :         bool has_ethtool_link_info:1;
     169             : } LinkInfo;
     170             : 
     171           0 : static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
     172           0 :         return CMP(a->ifindex, b->ifindex);
     173             : }
     174             : 
     175           0 : static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
     176             :         const char *received_kind;
     177             :         int r;
     178             : 
     179           0 :         assert(m);
     180           0 :         assert(info);
     181             : 
     182           0 :         r = sd_netlink_message_enter_container(m, IFLA_LINKINFO);
     183           0 :         if (r < 0)
     184           0 :                 return r;
     185             : 
     186           0 :         r = sd_netlink_message_read_string(m, IFLA_INFO_KIND, &received_kind);
     187           0 :         if (r < 0)
     188           0 :                 return r;
     189             : 
     190           0 :         r = sd_netlink_message_enter_container(m, IFLA_INFO_DATA);
     191           0 :         if (r < 0)
     192           0 :                 return r;
     193             : 
     194           0 :         if (streq(received_kind, "bridge")) {
     195           0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_FORWARD_DELAY, &info->forward_delay);
     196           0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_HELLO_TIME, &info->hello_time);
     197           0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_MAX_AGE, &info->max_age);
     198           0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_AGEING_TIME, &info->ageing_time);
     199           0 :                 (void) sd_netlink_message_read_u32(m, IFLA_BR_STP_STATE, &info->stp_state);
     200           0 :                 (void) sd_netlink_message_read_u16(m, IFLA_BR_PRIORITY, &info->priority);
     201           0 :                 (void) sd_netlink_message_read_u8(m, IFLA_BR_MCAST_IGMP_VERSION, &info->mcast_igmp_version);
     202             : 
     203           0 :         } else if (streq(received_kind, "vxlan")) {
     204           0 :                 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_ID, &info->vxlan_info.vni);
     205             : 
     206           0 :                 r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_GROUP, &info->vxlan_info.group.in);
     207           0 :                 if (r >= 0)
     208           0 :                         info->vxlan_info.group_family = AF_INET;
     209             :                 else {
     210           0 :                         r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_GROUP6, &info->vxlan_info.group.in6);
     211           0 :                         if (r >= 0)
     212           0 :                                 info->vxlan_info.group_family = AF_INET6;
     213             :                 }
     214             : 
     215           0 :                 r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_LOCAL, &info->vxlan_info.local.in);
     216           0 :                 if (r >= 0)
     217           0 :                         info->vxlan_info.local_family = AF_INET;
     218             :                 else {
     219           0 :                         r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_LOCAL6, &info->vxlan_info.local.in6);
     220           0 :                         if (r >= 0)
     221           0 :                                 info->vxlan_info.local_family = AF_INET6;
     222             :                 }
     223             : 
     224           0 :                 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_LINK, &info->vxlan_info.link);
     225           0 :                 (void) sd_netlink_message_read_u16(m, IFLA_VXLAN_PORT, &info->vxlan_info.dest_port);
     226             :         }
     227             : 
     228           0 :         strncpy(info->netdev_kind, received_kind, IFNAMSIZ);
     229             : 
     230           0 :         (void) sd_netlink_message_exit_container(m);
     231           0 :         (void) sd_netlink_message_exit_container(m);
     232             : 
     233           0 :         return 0;
     234             : }
     235             : 
     236           0 : static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
     237             :         const char *name;
     238             :         int ifindex, r;
     239             :         uint16_t type;
     240             : 
     241           0 :         assert(m);
     242           0 :         assert(info);
     243             : 
     244           0 :         r = sd_netlink_message_get_type(m, &type);
     245           0 :         if (r < 0)
     246           0 :                 return r;
     247             : 
     248           0 :         if (type != RTM_NEWLINK)
     249           0 :                 return 0;
     250             : 
     251           0 :         r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
     252           0 :         if (r < 0)
     253           0 :                 return r;
     254             : 
     255           0 :         r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name);
     256           0 :         if (r < 0)
     257           0 :                 return r;
     258             : 
     259           0 :         if (patterns) {
     260             :                 char str[DECIMAL_STR_MAX(int)];
     261             : 
     262           0 :                 xsprintf(str, "%i", ifindex);
     263             : 
     264           0 :                 if (!strv_fnmatch(patterns, str, 0) && !strv_fnmatch(patterns, name, 0))
     265           0 :                         return 0;
     266             :         }
     267             : 
     268           0 :         r = sd_rtnl_message_link_get_type(m, &info->iftype);
     269           0 :         if (r < 0)
     270           0 :                 return r;
     271             : 
     272           0 :         strscpy(info->name, sizeof info->name, name);
     273           0 :         info->ifindex = ifindex;
     274             : 
     275           0 :         info->has_mac_address =
     276           0 :                 sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 &&
     277           0 :                 memcmp(&info->mac_address, &ETHER_ADDR_NULL, sizeof(struct ether_addr)) != 0;
     278             : 
     279           0 :         (void) sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu);
     280           0 :         (void) sd_netlink_message_read_u32(m, IFLA_MIN_MTU, &info->min_mtu);
     281           0 :         (void) sd_netlink_message_read_u32(m, IFLA_MAX_MTU, &info->max_mtu);
     282             : 
     283           0 :         info->has_rx_queues =
     284           0 :                 sd_netlink_message_read_u32(m, IFLA_NUM_RX_QUEUES, &info->rx_queues) >= 0 &&
     285           0 :                 info->rx_queues > 0;
     286             : 
     287           0 :         info->has_tx_queues =
     288           0 :                 sd_netlink_message_read_u32(m, IFLA_NUM_TX_QUEUES, &info->tx_queues) >= 0 &&
     289           0 :                 info->tx_queues > 0;
     290             : 
     291           0 :         if (sd_netlink_message_read(m, IFLA_STATS64, sizeof info->stats64, &info->stats64) >= 0)
     292           0 :                 info->has_stats64 = true;
     293           0 :         else if (sd_netlink_message_read(m, IFLA_STATS, sizeof info->stats, &info->stats) >= 0)
     294           0 :                 info->has_stats = true;
     295             : 
     296             :         /* fill kind info */
     297           0 :         (void) decode_netdev(m, info);
     298             : 
     299           0 :         return 1;
     300             : }
     301             : 
     302           0 : static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
     303           0 :         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
     304           0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     305           0 :         _cleanup_free_ char *path = NULL, *ifindex_str = NULL;
     306             :         int r;
     307             : 
     308           0 :         if (asprintf(&ifindex_str, "%i", link->ifindex) < 0)
     309           0 :                 return -ENOMEM;
     310             : 
     311           0 :         r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex_str, &path);
     312           0 :         if (r < 0)
     313           0 :                 return r;
     314             : 
     315           0 :         r = sd_bus_call_method(
     316             :                         bus,
     317             :                         "org.freedesktop.network1",
     318             :                         path,
     319             :                         "org.freedesktop.DBus.Properties",
     320             :                         "Get",
     321             :                         &error,
     322             :                         &reply,
     323             :                         "ss",
     324             :                         "org.freedesktop.network1.Link",
     325             :                         "BitRates");
     326           0 :         if (r < 0) {
     327           0 :                 bool quiet = sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY) ||
     328           0 :                              sd_bus_error_has_name(&error, BUS_ERROR_SPEED_METER_INACTIVE);
     329             : 
     330           0 :                 return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING,
     331             :                                       r, "Failed to query link bit rates: %s", bus_error_message(&error, r));
     332             :         }
     333             : 
     334           0 :         r = sd_bus_message_enter_container(reply, 'v', "(tt)");
     335           0 :         if (r < 0)
     336           0 :                 return bus_log_parse_error(r);
     337             : 
     338           0 :         r = sd_bus_message_read(reply, "(tt)", &link->tx_bitrate, &link->rx_bitrate);
     339           0 :         if (r < 0)
     340           0 :                 return bus_log_parse_error(r);
     341             : 
     342           0 :         r = sd_bus_message_exit_container(reply);
     343           0 :         if (r < 0)
     344           0 :                 return bus_log_parse_error(r);
     345             : 
     346           0 :         link->has_bitrates = true;
     347             : 
     348           0 :         return 0;
     349             : }
     350             : 
     351           0 : static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
     352           0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
     353           0 :         _cleanup_free_ LinkInfo *links = NULL;
     354           0 :         _cleanup_close_ int fd = -1;
     355           0 :         size_t allocated = 0, c = 0, j;
     356             :         sd_netlink_message *i;
     357             :         int r;
     358             : 
     359           0 :         assert(rtnl);
     360           0 :         assert(ret);
     361             : 
     362           0 :         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
     363           0 :         if (r < 0)
     364           0 :                 return rtnl_log_create_error(r);
     365             : 
     366           0 :         r = sd_netlink_message_request_dump(req, true);
     367           0 :         if (r < 0)
     368           0 :                 return rtnl_log_create_error(r);
     369             : 
     370           0 :         r = sd_netlink_call(rtnl, req, 0, &reply);
     371           0 :         if (r < 0)
     372           0 :                 return log_error_errno(r, "Failed to enumerate links: %m");
     373             : 
     374           0 :         for (i = reply; i; i = sd_netlink_message_next(i)) {
     375           0 :                 if (!GREEDY_REALLOC0(links, allocated, c+1))
     376           0 :                         return -ENOMEM;
     377             : 
     378           0 :                 r = decode_link(i, links + c, patterns);
     379           0 :                 if (r < 0)
     380           0 :                         return r;
     381           0 :                 if (r == 0)
     382           0 :                         continue;
     383             : 
     384           0 :                 r = ethtool_get_link_info(&fd, links[c].name,
     385           0 :                                           &links[c].autonegotiation, &links[c].speed,
     386           0 :                                           &links[c].duplex, &links[c].port);
     387           0 :                 if (r >= 0)
     388           0 :                         links[c].has_ethtool_link_info = true;
     389             : 
     390           0 :                 c++;
     391             :         }
     392             : 
     393           0 :         typesafe_qsort(links, c, link_info_compare);
     394             : 
     395           0 :         if (bus)
     396           0 :                 for (j = 0; j < c; j++)
     397           0 :                         (void) acquire_link_bitrates(bus, links + j);
     398             : 
     399           0 :         *ret = TAKE_PTR(links);
     400             : 
     401           0 :         return (int) c;
     402             : }
     403             : 
     404           0 : static int list_links(int argc, char *argv[], void *userdata) {
     405           0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
     406           0 :         _cleanup_free_ LinkInfo *links = NULL;
     407           0 :         _cleanup_(table_unrefp) Table *table = NULL;
     408             :         TableCell *cell;
     409             :         int c, i, r;
     410             : 
     411           0 :         r = sd_netlink_open(&rtnl);
     412           0 :         if (r < 0)
     413           0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
     414             : 
     415           0 :         c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
     416           0 :         if (c < 0)
     417           0 :                 return c;
     418             : 
     419           0 :         (void) pager_open(arg_pager_flags);
     420             : 
     421           0 :         table = table_new("idx", "link", "type", "operational", "setup");
     422           0 :         if (!table)
     423           0 :                 return log_oom();
     424             : 
     425           0 :         table_set_header(table, arg_legend);
     426             : 
     427           0 :         assert_se(cell = table_get_cell(table, 0, 0));
     428           0 :         (void) table_set_minimum_width(table, cell, 3);
     429           0 :         (void) table_set_weight(table, cell, 0);
     430           0 :         (void) table_set_ellipsize_percent(table, cell, 100);
     431           0 :         (void) table_set_align_percent(table, cell, 100);
     432             : 
     433           0 :         assert_se(cell = table_get_cell(table, 0, 1));
     434           0 :         (void) table_set_ellipsize_percent(table, cell, 100);
     435             : 
     436           0 :         for (i = 0; i < c; i++) {
     437           0 :                 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
     438           0 :                 _cleanup_(sd_device_unrefp) sd_device *d = NULL;
     439             :                 const char *on_color_operational, *off_color_operational,
     440             :                            *on_color_setup, *off_color_setup;
     441             :                 char devid[2 + DECIMAL_STR_MAX(int)];
     442           0 :                 _cleanup_free_ char *t = NULL;
     443             : 
     444           0 :                 (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
     445           0 :                 operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
     446             : 
     447           0 :                 r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
     448           0 :                 if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
     449           0 :                         setup_state = strdup("unmanaged");
     450           0 :                 setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
     451             : 
     452           0 :                 xsprintf(devid, "n%i", links[i].ifindex);
     453           0 :                 (void) sd_device_new_from_device_id(&d, devid);
     454             : 
     455           0 :                 t = link_get_type_string(links[i].iftype, d);
     456             : 
     457           0 :                 r = table_add_many(table,
     458             :                                    TABLE_INT, links[i].ifindex,
     459             :                                    TABLE_STRING, links[i].name,
     460             :                                    TABLE_STRING, strna(t),
     461             :                                    TABLE_STRING, strna(operational_state),
     462             :                                    TABLE_SET_COLOR, on_color_operational,
     463             :                                    TABLE_STRING, strna(setup_state),
     464             :                                    TABLE_SET_COLOR, on_color_setup);
     465           0 :                 if (r < 0)
     466           0 :                         return r;
     467             :         }
     468             : 
     469           0 :         r = table_print(table, NULL);
     470           0 :         if (r < 0)
     471           0 :                 return log_error_errno(r, "Failed to print table: %m");
     472             : 
     473           0 :         if (arg_legend)
     474           0 :                 printf("\n%i links listed.\n", c);
     475             : 
     476           0 :         return 0;
     477             : }
     478             : 
     479             : /* IEEE Organizationally Unique Identifier vendor string */
     480           0 : static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) {
     481             :         const char *description;
     482             :         char modalias[STRLEN("OUI:XXYYXXYYXXYY") + 1], *desc;
     483             :         int r;
     484             : 
     485           0 :         assert(ret);
     486             : 
     487           0 :         if (!hwdb)
     488           0 :                 return -EINVAL;
     489             : 
     490           0 :         if (!mac)
     491           0 :                 return -EINVAL;
     492             : 
     493             :         /* skip commonly misused 00:00:00 (Xerox) prefix */
     494           0 :         if (memcmp(mac, "\0\0\0", 3) == 0)
     495           0 :                 return -EINVAL;
     496             : 
     497           0 :         xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR,
     498             :                  ETHER_ADDR_FORMAT_VAL(*mac));
     499             : 
     500           0 :         r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
     501           0 :         if (r < 0)
     502           0 :                 return r;
     503             : 
     504           0 :         desc = strdup(description);
     505           0 :         if (!desc)
     506           0 :                 return -ENOMEM;
     507             : 
     508           0 :         *ret = desc;
     509             : 
     510           0 :         return 0;
     511             : }
     512             : 
     513           0 : static int get_gateway_description(
     514             :                 sd_netlink *rtnl,
     515             :                 sd_hwdb *hwdb,
     516             :                 int ifindex,
     517             :                 int family,
     518             :                 union in_addr_union *gateway,
     519             :                 char **gateway_description) {
     520           0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
     521             :         sd_netlink_message *m;
     522             :         int r;
     523             : 
     524           0 :         assert(rtnl);
     525           0 :         assert(ifindex >= 0);
     526           0 :         assert(IN_SET(family, AF_INET, AF_INET6));
     527           0 :         assert(gateway);
     528           0 :         assert(gateway_description);
     529             : 
     530           0 :         r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
     531           0 :         if (r < 0)
     532           0 :                 return r;
     533             : 
     534           0 :         r = sd_netlink_message_request_dump(req, true);
     535           0 :         if (r < 0)
     536           0 :                 return r;
     537             : 
     538           0 :         r = sd_netlink_call(rtnl, req, 0, &reply);
     539           0 :         if (r < 0)
     540           0 :                 return r;
     541             : 
     542           0 :         for (m = reply; m; m = sd_netlink_message_next(m)) {
     543           0 :                 union in_addr_union gw = IN_ADDR_NULL;
     544           0 :                 struct ether_addr mac = ETHER_ADDR_NULL;
     545             :                 uint16_t type;
     546             :                 int ifi, fam;
     547             : 
     548           0 :                 r = sd_netlink_message_get_errno(m);
     549           0 :                 if (r < 0) {
     550           0 :                         log_error_errno(r, "got error: %m");
     551           0 :                         continue;
     552             :                 }
     553             : 
     554           0 :                 r = sd_netlink_message_get_type(m, &type);
     555           0 :                 if (r < 0) {
     556           0 :                         log_error_errno(r, "could not get type: %m");
     557           0 :                         continue;
     558             :                 }
     559             : 
     560           0 :                 if (type != RTM_NEWNEIGH) {
     561           0 :                         log_error("type is not RTM_NEWNEIGH");
     562           0 :                         continue;
     563             :                 }
     564             : 
     565           0 :                 r = sd_rtnl_message_neigh_get_family(m, &fam);
     566           0 :                 if (r < 0) {
     567           0 :                         log_error_errno(r, "could not get family: %m");
     568           0 :                         continue;
     569             :                 }
     570             : 
     571           0 :                 if (fam != family) {
     572           0 :                         log_error("family is not correct");
     573           0 :                         continue;
     574             :                 }
     575             : 
     576           0 :                 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
     577           0 :                 if (r < 0) {
     578           0 :                         log_error_errno(r, "could not get ifindex: %m");
     579           0 :                         continue;
     580             :                 }
     581             : 
     582           0 :                 if (ifindex > 0 && ifi != ifindex)
     583           0 :                         continue;
     584             : 
     585           0 :                 switch (fam) {
     586           0 :                 case AF_INET:
     587           0 :                         r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in);
     588           0 :                         if (r < 0)
     589           0 :                                 continue;
     590             : 
     591           0 :                         break;
     592           0 :                 case AF_INET6:
     593           0 :                         r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6);
     594           0 :                         if (r < 0)
     595           0 :                                 continue;
     596             : 
     597           0 :                         break;
     598           0 :                 default:
     599           0 :                         continue;
     600             :                 }
     601             : 
     602           0 :                 if (!in_addr_equal(fam, &gw, gateway))
     603           0 :                         continue;
     604             : 
     605           0 :                 r = sd_netlink_message_read(m, NDA_LLADDR, sizeof(mac), &mac);
     606           0 :                 if (r < 0)
     607           0 :                         continue;
     608             : 
     609           0 :                 r = ieee_oui(hwdb, &mac, gateway_description);
     610           0 :                 if (r < 0)
     611           0 :                         continue;
     612             : 
     613           0 :                 return 0;
     614             :         }
     615             : 
     616           0 :         return -ENODATA;
     617             : }
     618             : 
     619           0 : static int dump_gateways(
     620             :                 sd_netlink *rtnl,
     621             :                 sd_hwdb *hwdb,
     622             :                 Table *table,
     623             :                 int ifindex) {
     624           0 :         _cleanup_free_ struct local_address *local = NULL;
     625             :         int r, n, i;
     626             : 
     627           0 :         assert(rtnl);
     628           0 :         assert(table);
     629             : 
     630           0 :         n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
     631           0 :         if (n < 0)
     632           0 :                 return n;
     633             : 
     634           0 :         for (i = 0; i < n; i++) {
     635           0 :                 _cleanup_free_ char *gateway = NULL, *description = NULL, *with_description = NULL;
     636             : 
     637           0 :                 r = table_add_many(table,
     638             :                                    TABLE_EMPTY,
     639             :                                    TABLE_STRING, i == 0 ? "Gateway:" : "");
     640           0 :                 if (r < 0)
     641           0 :                         return r;
     642             : 
     643           0 :                 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
     644           0 :                 if (r < 0)
     645           0 :                         return r;
     646             : 
     647           0 :                 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
     648           0 :                 if (r < 0)
     649           0 :                         log_debug_errno(r, "Could not get description of gateway: %m");
     650             : 
     651           0 :                 if (description) {
     652           0 :                         with_description = strjoin(gateway, " (", description, ")");
     653           0 :                         if (!with_description)
     654           0 :                                 return -ENOMEM;
     655             :                 }
     656             : 
     657             :                 /* Show interface name for the entry if we show
     658             :                  * entries for all interfaces */
     659           0 :                 if (ifindex <= 0) {
     660             :                         char name[IF_NAMESIZE+1];
     661             : 
     662           0 :                         if (format_ifname(local[i].ifindex, name))
     663           0 :                                 r = table_add_cell_stringf(table, NULL, "%s on %s", with_description ?: gateway, name);
     664             :                         else
     665           0 :                                 r = table_add_cell_stringf(table, NULL, "%s on %%%i", with_description ?: gateway, local[i].ifindex);
     666             :                 } else
     667           0 :                         r = table_add_cell(table, NULL, TABLE_STRING, with_description ?: gateway);
     668           0 :                 if (r < 0)
     669           0 :                         return r;
     670             :         }
     671             : 
     672           0 :         return 0;
     673             : }
     674             : 
     675           0 : static int dump_addresses(
     676             :                 sd_netlink *rtnl,
     677             :                 Table *table,
     678             :                 int ifindex) {
     679             : 
     680           0 :         _cleanup_free_ struct local_address *local = NULL;
     681             :         int r, n, i;
     682             : 
     683           0 :         assert(rtnl);
     684           0 :         assert(table);
     685             : 
     686           0 :         n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
     687           0 :         if (n < 0)
     688           0 :                 return n;
     689             : 
     690           0 :         for (i = 0; i < n; i++) {
     691           0 :                 _cleanup_free_ char *pretty = NULL;
     692             : 
     693           0 :                 r = table_add_many(table,
     694             :                                    TABLE_EMPTY,
     695             :                                    TABLE_STRING, i == 0 ? "Address:" : "");
     696           0 :                 if (r < 0)
     697           0 :                         return r;
     698             : 
     699           0 :                 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
     700           0 :                 if (r < 0)
     701           0 :                         return r;
     702             : 
     703           0 :                 if (ifindex <= 0) {
     704             :                         char name[IF_NAMESIZE+1];
     705             : 
     706           0 :                         if (format_ifname(local[i].ifindex, name))
     707           0 :                                 r = table_add_cell_stringf(table, NULL, "%s on %s", pretty, name);
     708             :                         else
     709           0 :                                 r = table_add_cell_stringf(table, NULL, "%s on %%%i", pretty, local[i].ifindex);
     710             :                 } else
     711           0 :                         r = table_add_cell(table, NULL, TABLE_STRING, pretty);
     712           0 :                 if (r < 0)
     713           0 :                         return r;
     714             :         }
     715             : 
     716           0 :         return 0;
     717             : }
     718             : 
     719           0 : static int dump_address_labels(sd_netlink *rtnl) {
     720           0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
     721           0 :         _cleanup_(table_unrefp) Table *table = NULL;
     722             :         sd_netlink_message *m;
     723             :         TableCell *cell;
     724             :         int r;
     725             : 
     726           0 :         assert(rtnl);
     727             : 
     728           0 :         r = sd_rtnl_message_new_addrlabel(rtnl, &req, RTM_GETADDRLABEL, 0, AF_INET6);
     729           0 :         if (r < 0)
     730           0 :                 return log_error_errno(r, "Could not allocate RTM_GETADDRLABEL message: %m");
     731             : 
     732           0 :         r = sd_netlink_message_request_dump(req, true);
     733           0 :         if (r < 0)
     734           0 :                 return r;
     735             : 
     736           0 :         r = sd_netlink_call(rtnl, req, 0, &reply);
     737           0 :         if (r < 0)
     738           0 :                 return r;
     739             : 
     740           0 :         table = table_new("label", "prefix/prefixlen");
     741           0 :         if (!table)
     742           0 :                 return -ENOMEM;
     743             : 
     744           0 :         r = table_set_sort(table, 0, SIZE_MAX);
     745           0 :         if (r < 0)
     746           0 :                 return r;
     747             : 
     748           0 :         assert_se(cell = table_get_cell(table, 0, 0));
     749           0 :         (void) table_set_align_percent(table, cell, 100);
     750           0 :         (void) table_set_ellipsize_percent(table, cell, 100);
     751             : 
     752           0 :         assert_se(cell = table_get_cell(table, 0, 1));
     753           0 :         (void) table_set_align_percent(table, cell, 100);
     754             : 
     755           0 :         for (m = reply; m; m = sd_netlink_message_next(m)) {
     756           0 :                 _cleanup_free_ char *pretty = NULL;
     757           0 :                 union in_addr_union prefix = IN_ADDR_NULL;
     758             :                 uint8_t prefixlen;
     759             :                 uint32_t label;
     760             : 
     761           0 :                 r = sd_netlink_message_get_errno(m);
     762           0 :                 if (r < 0) {
     763           0 :                         log_error_errno(r, "got error: %m");
     764           0 :                         continue;
     765             :                 }
     766             : 
     767           0 :                 r = sd_netlink_message_read_u32(m, IFAL_LABEL, &label);
     768           0 :                 if (r < 0 && r != -ENODATA) {
     769           0 :                         log_error_errno(r, "Could not read IFAL_LABEL, ignoring: %m");
     770           0 :                         continue;
     771             :                 }
     772             : 
     773           0 :                 r = sd_netlink_message_read_in6_addr(m, IFAL_ADDRESS, &prefix.in6);
     774           0 :                 if (r < 0)
     775           0 :                         continue;
     776             : 
     777           0 :                 r = in_addr_to_string(AF_INET6, &prefix, &pretty);
     778           0 :                 if (r < 0)
     779           0 :                         continue;
     780             : 
     781           0 :                 r = sd_rtnl_message_addrlabel_get_prefixlen(m, &prefixlen);
     782           0 :                 if (r < 0)
     783           0 :                         continue;
     784             : 
     785           0 :                 r = table_add_cell(table, NULL, TABLE_UINT32, &label);
     786           0 :                 if (r < 0)
     787           0 :                         return r;
     788             : 
     789           0 :                 r = table_add_cell_stringf(table, NULL, "%s/%u", pretty, prefixlen);
     790           0 :                 if (r < 0)
     791           0 :                         return r;
     792             :         }
     793             : 
     794           0 :         return table_print(table, NULL);
     795             : }
     796             : 
     797           0 : static int list_address_labels(int argc, char *argv[], void *userdata) {
     798           0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
     799             :         int r;
     800             : 
     801           0 :         r = sd_netlink_open(&rtnl);
     802           0 :         if (r < 0)
     803           0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
     804             : 
     805           0 :         dump_address_labels(rtnl);
     806             : 
     807           0 :         return 0;
     808             : }
     809             : 
     810           0 : static int open_lldp_neighbors(int ifindex, FILE **ret) {
     811           0 :         _cleanup_free_ char *p = NULL;
     812             :         FILE *f;
     813             : 
     814           0 :         if (asprintf(&p, "/run/systemd/netif/lldp/%i", ifindex) < 0)
     815           0 :                 return -ENOMEM;
     816             : 
     817           0 :         f = fopen(p, "re");
     818           0 :         if (!f)
     819           0 :                 return -errno;
     820             : 
     821           0 :         *ret = f;
     822           0 :         return 0;
     823             : }
     824             : 
     825           0 : static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) {
     826           0 :         _cleanup_free_ void *raw = NULL;
     827             :         size_t l;
     828             :         le64_t u;
     829             :         int r;
     830             : 
     831           0 :         assert(f);
     832           0 :         assert(ret);
     833             : 
     834           0 :         l = fread(&u, 1, sizeof(u), f);
     835           0 :         if (l == 0 && feof(f))
     836           0 :                 return 0;
     837           0 :         if (l != sizeof(u))
     838           0 :                 return -EBADMSG;
     839             : 
     840             :         /* each LLDP packet is at most MTU size, but let's allow up to 4KiB just in case */
     841           0 :         if (le64toh(u) >= 4096)
     842           0 :                 return -EBADMSG;
     843             : 
     844           0 :         raw = new(uint8_t, le64toh(u));
     845           0 :         if (!raw)
     846           0 :                 return -ENOMEM;
     847             : 
     848           0 :         if (fread(raw, 1, le64toh(u), f) != le64toh(u))
     849           0 :                 return -EBADMSG;
     850             : 
     851           0 :         r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u));
     852           0 :         if (r < 0)
     853           0 :                 return r;
     854             : 
     855           0 :         return 1;
     856             : }
     857             : 
     858           0 : static int dump_lldp_neighbors(Table *table, const char *prefix, int ifindex) {
     859           0 :         _cleanup_fclose_ FILE *f = NULL;
     860           0 :         int r, c = 0;
     861             : 
     862           0 :         assert(table);
     863           0 :         assert(prefix);
     864           0 :         assert(ifindex > 0);
     865             : 
     866           0 :         r = open_lldp_neighbors(ifindex, &f);
     867           0 :         if (r == -ENOENT)
     868           0 :                 return 0;
     869           0 :         if (r < 0)
     870           0 :                 return r;
     871             : 
     872           0 :         for (;;) {
     873           0 :                 const char *system_name = NULL, *port_id = NULL, *port_description = NULL;
     874           0 :                 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
     875             : 
     876           0 :                 r = next_lldp_neighbor(f, &n);
     877           0 :                 if (r < 0)
     878           0 :                         return r;
     879           0 :                 if (r == 0)
     880           0 :                         break;
     881             : 
     882           0 :                 r = table_add_many(table,
     883             :                                    TABLE_EMPTY,
     884             :                                    TABLE_STRING, c == 0 ? prefix : "");
     885           0 :                 if (r < 0)
     886           0 :                         return r;
     887             : 
     888           0 :                 (void) sd_lldp_neighbor_get_system_name(n, &system_name);
     889           0 :                 (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
     890           0 :                 (void) sd_lldp_neighbor_get_port_description(n, &port_description);
     891             : 
     892           0 :                 r = table_add_cell_stringf(table, NULL,
     893             :                                            "%s on port %s%s%s%s",
     894             :                                            strna(system_name), strna(port_id),
     895           0 :                                            isempty(port_description) ? "" : " (",
     896             :                                            strempty(port_description),
     897           0 :                                            isempty(port_description) ? "" : ")");
     898           0 :                 if (r < 0)
     899           0 :                         return r;
     900             : 
     901           0 :                 c++;
     902             :         }
     903             : 
     904           0 :         return c;
     905             : }
     906             : 
     907           0 : static int dump_ifindexes(Table *table, const char *prefix, const int *ifindexes) {
     908             :         unsigned c;
     909             :         int r;
     910             : 
     911           0 :         assert(prefix);
     912             : 
     913           0 :         if (!ifindexes || ifindexes[0] <= 0)
     914           0 :                 return 0;
     915             : 
     916           0 :         for (c = 0; ifindexes[c] > 0; c++) {
     917           0 :                 r = table_add_many(table,
     918             :                                    TABLE_EMPTY,
     919             :                                    TABLE_STRING, c == 0 ? prefix : "",
     920             :                                    TABLE_IFINDEX, ifindexes[c]);
     921           0 :                 if (r < 0)
     922           0 :                         return r;
     923             :         }
     924             : 
     925           0 :         return 0;
     926             : }
     927             : 
     928           0 : static int dump_list(Table *table, const char *prefix, char **l) {
     929             :         char **i;
     930             :         int r;
     931             : 
     932           0 :         if (strv_isempty(l))
     933           0 :                 return 0;
     934             : 
     935           0 :         STRV_FOREACH(i, l) {
     936           0 :                 r = table_add_many(table,
     937             :                                    TABLE_EMPTY,
     938             :                                    TABLE_STRING, i == l ? prefix : "",
     939             :                                    TABLE_STRING, *i);
     940           0 :                 if (r < 0)
     941           0 :                         return r;
     942             :         }
     943             : 
     944           0 :         return 0;
     945             : }
     946             : 
     947             : #define DUMP_STATS_ONE(name, val_name)                                  \
     948             :         r = table_add_many(table,                                       \
     949             :                            TABLE_EMPTY,                                 \
     950             :                            TABLE_STRING, name ":");                     \
     951             :         if (r < 0)                                                      \
     952             :                 return r;                                               \
     953             :         r = table_add_cell(table, NULL,                                 \
     954             :                            info->has_stats64 ? TABLE_UINT64 : TABLE_UINT32, \
     955             :                            info->has_stats64 ? (void*) &info->stats64.val_name : (void*) &info->stats.val_name); \
     956             :         if (r < 0)                                                      \
     957             :                 return r;
     958             : 
     959           0 : static int dump_statistics(Table *table, const LinkInfo *info) {
     960             :         int r;
     961             : 
     962           0 :         if (!arg_stats)
     963           0 :                 return 0;
     964             : 
     965           0 :         if (!info->has_stats64 && !info->has_stats)
     966           0 :                 return 0;
     967             : 
     968           0 :         DUMP_STATS_ONE("Rx Packets", rx_packets);
     969           0 :         DUMP_STATS_ONE("Tx Packets", tx_packets);
     970           0 :         DUMP_STATS_ONE("Rx Bytes", rx_bytes);
     971           0 :         DUMP_STATS_ONE("Tx Bytes", tx_bytes);
     972           0 :         DUMP_STATS_ONE("Rx Errors", rx_errors);
     973           0 :         DUMP_STATS_ONE("Tx Errors", tx_errors);
     974           0 :         DUMP_STATS_ONE("Rx Dropped", rx_dropped);
     975           0 :         DUMP_STATS_ONE("Tx Dropped", tx_dropped);
     976           0 :         DUMP_STATS_ONE("Multicast Packets", multicast);
     977           0 :         DUMP_STATS_ONE("Collisions", collisions);
     978             : 
     979           0 :         return 0;
     980             : }
     981             : 
     982           0 : static int link_status_one(
     983             :                 sd_netlink *rtnl,
     984             :                 sd_hwdb *hwdb,
     985             :                 const LinkInfo *info) {
     986             : 
     987           0 :         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
     988           0 :         _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
     989           0 :         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
     990             :         char devid[2 + DECIMAL_STR_MAX(int)];
     991           0 :         _cleanup_free_ char *t = NULL, *network = NULL;
     992           0 :         const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
     993             :         const char *on_color_operational, *off_color_operational,
     994             :                 *on_color_setup, *off_color_setup;
     995           0 :         _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
     996           0 :         _cleanup_(table_unrefp) Table *table = NULL;
     997             :         TableCell *cell;
     998             :         int r;
     999             : 
    1000           0 :         assert(rtnl);
    1001           0 :         assert(info);
    1002             : 
    1003           0 :         (void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
    1004           0 :         operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
    1005             : 
    1006           0 :         r = sd_network_link_get_setup_state(info->ifindex, &setup_state);
    1007           0 :         if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
    1008           0 :                 setup_state = strdup("unmanaged");
    1009           0 :         setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
    1010             : 
    1011           0 :         (void) sd_network_link_get_dns(info->ifindex, &dns);
    1012           0 :         (void) sd_network_link_get_search_domains(info->ifindex, &search_domains);
    1013           0 :         (void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
    1014           0 :         (void) sd_network_link_get_ntp(info->ifindex, &ntp);
    1015             : 
    1016           0 :         xsprintf(devid, "n%i", info->ifindex);
    1017             : 
    1018           0 :         (void) sd_device_new_from_device_id(&d, devid);
    1019             : 
    1020           0 :         if (d) {
    1021           0 :                 (void) sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link);
    1022           0 :                 (void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver);
    1023           0 :                 (void) sd_device_get_property_value(d, "ID_PATH", &path);
    1024             : 
    1025           0 :                 if (sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
    1026           0 :                         (void) sd_device_get_property_value(d, "ID_VENDOR", &vendor);
    1027             : 
    1028           0 :                 if (sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model) < 0)
    1029           0 :                         (void) sd_device_get_property_value(d, "ID_MODEL", &model);
    1030             :         }
    1031             : 
    1032           0 :         t = link_get_type_string(info->iftype, d);
    1033             : 
    1034           0 :         (void) sd_network_link_get_network_file(info->ifindex, &network);
    1035             : 
    1036           0 :         (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
    1037           0 :         (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
    1038             : 
    1039           0 :         table = table_new("dot", "key", "value");
    1040           0 :         if (!table)
    1041           0 :                 return -ENOMEM;
    1042             : 
    1043           0 :         assert_se(cell = table_get_cell(table, 0, 0));
    1044           0 :         (void) table_set_ellipsize_percent(table, cell, 100);
    1045             : 
    1046           0 :         assert_se(cell = table_get_cell(table, 0, 1));
    1047           0 :         (void) table_set_ellipsize_percent(table, cell, 100);
    1048             : 
    1049           0 :         table_set_header(table, false);
    1050             : 
    1051           0 :         r = table_add_many(table,
    1052             :                            TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
    1053             :                            TABLE_SET_COLOR, on_color_operational);
    1054           0 :         if (r < 0)
    1055           0 :                 return r;
    1056           0 :         r = table_add_cell_stringf(table, &cell, "%i: %s", info->ifindex, info->name);
    1057           0 :         if (r < 0)
    1058           0 :                 return r;
    1059           0 :         (void) table_set_align_percent(table, cell, 0);
    1060             : 
    1061           0 :         r = table_add_many(table,
    1062             :                            TABLE_EMPTY,
    1063             :                            TABLE_EMPTY,
    1064             :                            TABLE_STRING, "Link File:",
    1065             :                            TABLE_SET_ALIGN_PERCENT, 100,
    1066             :                            TABLE_STRING, strna(link),
    1067             :                            TABLE_EMPTY,
    1068             :                            TABLE_STRING, "Network File:",
    1069             :                            TABLE_STRING, strna(network),
    1070             :                            TABLE_EMPTY,
    1071             :                            TABLE_STRING, "Type:",
    1072             :                            TABLE_STRING, strna(t),
    1073             :                            TABLE_EMPTY,
    1074             :                            TABLE_STRING, "State:");
    1075           0 :         if (r < 0)
    1076           0 :                 return r;
    1077           0 :         r = table_add_cell_stringf(table, NULL, "%s%s%s (%s%s%s)",
    1078             :                                    on_color_operational, strna(operational_state), off_color_operational,
    1079             :                                    on_color_setup, strna(setup_state), off_color_setup);
    1080           0 :         if (r < 0)
    1081           0 :                 return r;
    1082             : 
    1083           0 :         if (path) {
    1084           0 :                 r = table_add_many(table,
    1085             :                                    TABLE_EMPTY,
    1086             :                                    TABLE_STRING, "Path:",
    1087             :                                    TABLE_STRING, path);
    1088           0 :                 if (r < 0)
    1089           0 :                         return r;
    1090             :         }
    1091           0 :         if (driver) {
    1092           0 :                 r = table_add_many(table,
    1093             :                                    TABLE_EMPTY,
    1094             :                                    TABLE_STRING, "Driver:",
    1095             :                                    TABLE_STRING, driver);
    1096           0 :                 if (r < 0)
    1097           0 :                         return r;
    1098             :         }
    1099           0 :         if (vendor) {
    1100           0 :                 r = table_add_many(table,
    1101             :                                    TABLE_EMPTY,
    1102             :                                    TABLE_STRING, "Vendor:",
    1103             :                                    TABLE_STRING, vendor);
    1104           0 :                 if (r < 0)
    1105           0 :                         return r;
    1106             :         }
    1107           0 :         if (model) {
    1108           0 :                 r = table_add_many(table,
    1109             :                                    TABLE_EMPTY,
    1110             :                                    TABLE_STRING, "Model:",
    1111             :                                    TABLE_STRING, model);
    1112           0 :                 if (r < 0)
    1113           0 :                         return r;
    1114             :         }
    1115             : 
    1116           0 :         if (info->has_mac_address) {
    1117           0 :                 _cleanup_free_ char *description = NULL;
    1118             :                 char ea[ETHER_ADDR_TO_STRING_MAX];
    1119             : 
    1120           0 :                 (void) ieee_oui(hwdb, &info->mac_address, &description);
    1121             : 
    1122           0 :                 r = table_add_many(table,
    1123             :                                    TABLE_EMPTY,
    1124             :                                    TABLE_STRING, "HW Address:");
    1125           0 :                 if (r < 0)
    1126           0 :                         return r;
    1127           0 :                 r = table_add_cell_stringf(table, NULL, "%s%s%s%s",
    1128             :                                            ether_addr_to_string(&info->mac_address, ea),
    1129           0 :                                            description ? " (" : "",
    1130             :                                            strempty(description),
    1131           0 :                                            description ? ")" : "");
    1132           0 :                 if (r < 0)
    1133           0 :                         return r;
    1134             :         }
    1135             : 
    1136           0 :         if (info->mtu > 0) {
    1137             :                 char min_str[DECIMAL_STR_MAX(uint32_t)], max_str[DECIMAL_STR_MAX(uint32_t)];
    1138             : 
    1139           0 :                 xsprintf(min_str, "%" PRIu32, info->min_mtu);
    1140           0 :                 xsprintf(max_str, "%" PRIu32, info->max_mtu);
    1141             : 
    1142           0 :                 r = table_add_many(table,
    1143             :                                    TABLE_EMPTY,
    1144             :                                    TABLE_STRING, "MTU:");
    1145           0 :                 if (r < 0)
    1146           0 :                         return r;
    1147           0 :                 r = table_add_cell_stringf(table, NULL, "%" PRIu32 "%s%s%s%s%s%s%s",
    1148             :                                            info->mtu,
    1149           0 :                                            info->min_mtu > 0 || info->max_mtu > 0 ? " (" : "",
    1150           0 :                                            info->min_mtu > 0 ? "min: " : "",
    1151           0 :                                            info->min_mtu > 0 ? min_str : "",
    1152           0 :                                            info->min_mtu > 0 && info->max_mtu > 0 ? ", " : "",
    1153           0 :                                            info->max_mtu > 0 ? "max: " : "",
    1154           0 :                                            info->max_mtu > 0 ? max_str : "",
    1155           0 :                                            info->min_mtu > 0 || info->max_mtu > 0 ? ")" : "");
    1156           0 :                 if (r < 0)
    1157           0 :                         return r;
    1158             :         }
    1159             : 
    1160           0 :         if (streq_ptr(info->netdev_kind, "bridge")) {
    1161           0 :                 r = table_add_many(table,
    1162             :                                    TABLE_EMPTY,
    1163             :                                    TABLE_STRING, "Forward Delay:",
    1164             :                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->forward_delay),
    1165             :                                    TABLE_EMPTY,
    1166             :                                    TABLE_STRING, "Hello Time:",
    1167             :                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->hello_time),
    1168             :                                    TABLE_EMPTY,
    1169             :                                    TABLE_STRING, "Max Age:",
    1170             :                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->max_age),
    1171             :                                    TABLE_EMPTY,
    1172             :                                    TABLE_STRING, "Ageing Time:",
    1173             :                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->ageing_time),
    1174             :                                    TABLE_EMPTY,
    1175             :                                    TABLE_STRING, "Priority:",
    1176             :                                    TABLE_UINT16, info->priority,
    1177             :                                    TABLE_EMPTY,
    1178             :                                    TABLE_STRING, "STP:",
    1179             :                                    TABLE_BOOLEAN, info->stp_state > 0,
    1180             :                                    TABLE_EMPTY,
    1181             :                                    TABLE_STRING, "Multicast IGMP Version:",
    1182             :                                    TABLE_UINT8, info->mcast_igmp_version);
    1183           0 :                 if (r < 0)
    1184           0 :                         return r;
    1185             : 
    1186           0 :         } else if (streq_ptr(info->netdev_kind, "vxlan")) {
    1187           0 :                 if (info->vxlan_info.vni > 0) {
    1188           0 :                         r = table_add_many(table,
    1189             :                                            TABLE_EMPTY,
    1190             :                                            TABLE_STRING, "VNI:",
    1191             :                                            TABLE_UINT32, info->vxlan_info.vni);
    1192           0 :                         if (r < 0)
    1193           0 :                                 return r;
    1194             :                 }
    1195             : 
    1196           0 :                 if (IN_SET(info->vxlan_info.group_family, AF_INET, AF_INET6)) {
    1197           0 :                         r = table_add_many(table,
    1198             :                                            TABLE_EMPTY,
    1199             :                                            TABLE_STRING, "Group:",
    1200             :                                            info->vxlan_info.group_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
    1201             :                                            &info->vxlan_info.group);
    1202           0 :                         if (r < 0)
    1203           0 :                                 return r;
    1204             :                 }
    1205             : 
    1206           0 :                 if (IN_SET(info->vxlan_info.local_family, AF_INET, AF_INET6)) {
    1207           0 :                         r = table_add_many(table,
    1208             :                                            TABLE_EMPTY,
    1209             :                                            TABLE_STRING, "Local:",
    1210             :                                            info->vxlan_info.local_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
    1211             :                                            &info->vxlan_info.local);
    1212           0 :                         if (r < 0)
    1213           0 :                                 return r;
    1214             :                 }
    1215             : 
    1216           0 :                 if (info->vxlan_info.dest_port > 0) {
    1217           0 :                         r = table_add_many(table,
    1218             :                                            TABLE_EMPTY,
    1219             :                                            TABLE_STRING, "Destination Port:",
    1220             :                                            TABLE_UINT16, be16toh(info->vxlan_info.dest_port));
    1221           0 :                         if (r < 0)
    1222           0 :                                 return r;
    1223             :                 }
    1224             : 
    1225           0 :                 if (info->vxlan_info.link > 0) {
    1226           0 :                         r = table_add_many(table,
    1227             :                                            TABLE_EMPTY,
    1228             :                                            TABLE_STRING, "Underlying Device:",
    1229             :                                            TABLE_IFINDEX, info->vxlan_info.link);
    1230           0 :                         if (r < 0)
    1231           0 :                                  return r;
    1232             :                 }
    1233             :         }
    1234             : 
    1235           0 :         if (info->has_bitrates) {
    1236             :                 char tx[FORMAT_BYTES_MAX], rx[FORMAT_BYTES_MAX];
    1237             : 
    1238           0 :                 r = table_add_many(table,
    1239             :                                    TABLE_EMPTY,
    1240             :                                    TABLE_STRING, "Bit Rate (Tx/Rx):");
    1241           0 :                 if (r < 0)
    1242           0 :                         return r;
    1243           0 :                 r = table_add_cell_stringf(table, NULL, "%sbps/%sbps",
    1244             :                                            format_bytes_full(tx, sizeof tx, info->tx_bitrate, 0),
    1245             :                                            format_bytes_full(rx, sizeof rx, info->rx_bitrate, 0));
    1246           0 :                 if (r < 0)
    1247           0 :                         return r;
    1248             :         }
    1249             : 
    1250           0 :         if (info->has_tx_queues || info->has_rx_queues) {
    1251           0 :                 r = table_add_many(table,
    1252             :                                    TABLE_EMPTY,
    1253             :                                    TABLE_STRING, "Queue Length (Tx/Rx):");
    1254           0 :                 if (r < 0)
    1255           0 :                         return r;
    1256           0 :                 r = table_add_cell_stringf(table, NULL, "%" PRIu32 "/%" PRIu32, info->tx_queues, info->rx_queues);
    1257           0 :                 if (r < 0)
    1258           0 :                         return r;
    1259             :         }
    1260             : 
    1261           0 :         if (info->has_ethtool_link_info) {
    1262           0 :                 const char *duplex = duplex_to_string(info->duplex);
    1263           0 :                 const char *port = port_to_string(info->port);
    1264             : 
    1265           0 :                 if (IN_SET(info->autonegotiation, AUTONEG_DISABLE, AUTONEG_ENABLE)) {
    1266           0 :                         r = table_add_many(table,
    1267             :                                            TABLE_EMPTY,
    1268             :                                            TABLE_STRING, "Auto negotiation:",
    1269             :                                            TABLE_BOOLEAN, info->autonegotiation == AUTONEG_ENABLE);
    1270           0 :                         if (r < 0)
    1271           0 :                                 return r;
    1272             :                 }
    1273             : 
    1274           0 :                 if (info->speed > 0) {
    1275           0 :                         r = table_add_many(table,
    1276             :                                            TABLE_EMPTY,
    1277             :                                            TABLE_STRING, "Speed:",
    1278             :                                            TABLE_BPS, (uint64_t) info->speed);
    1279           0 :                         if (r < 0)
    1280           0 :                                 return r;
    1281             :                 }
    1282             : 
    1283           0 :                 if (duplex) {
    1284           0 :                         r = table_add_many(table,
    1285             :                                            TABLE_EMPTY,
    1286             :                                            TABLE_STRING, "Duplex:",
    1287             :                                            TABLE_STRING, duplex);
    1288           0 :                         if (r < 0)
    1289           0 :                                 return r;
    1290             :                 }
    1291             : 
    1292           0 :                 if (port) {
    1293           0 :                         r = table_add_many(table,
    1294             :                                            TABLE_EMPTY,
    1295             :                                            TABLE_STRING, "Port:",
    1296             :                                            TABLE_STRING, port);
    1297           0 :                         if (r < 0)
    1298           0 :                                 return r;
    1299             :                 }
    1300             :         }
    1301             : 
    1302           0 :         r = dump_addresses(rtnl, table, info->ifindex);
    1303           0 :         if (r < 0)
    1304           0 :                 return r;
    1305           0 :         r = dump_gateways(rtnl, hwdb, table, info->ifindex);
    1306           0 :         if (r < 0)
    1307           0 :                 return r;
    1308           0 :         r = dump_list(table, "DNS:", dns);
    1309           0 :         if (r < 0)
    1310           0 :                 return r;
    1311           0 :         r = dump_list(table, "Search Domains:", search_domains);
    1312           0 :         if (r < 0)
    1313           0 :                 return r;
    1314           0 :         r = dump_list(table, "Route Domains:", route_domains);
    1315           0 :         if (r < 0)
    1316           0 :                 return r;
    1317           0 :         r = dump_list(table, "NTP:", ntp);
    1318           0 :         if (r < 0)
    1319           0 :                 return r;
    1320           0 :         r = dump_ifindexes(table, "Carrier Bound To:", carrier_bound_to);
    1321           0 :         if (r < 0)
    1322           0 :                 return r;
    1323           0 :         r = dump_ifindexes(table, "Carrier Bound By:", carrier_bound_by);
    1324           0 :         if (r < 0)
    1325           0 :                 return r;
    1326             : 
    1327           0 :         (void) sd_network_link_get_timezone(info->ifindex, &tz);
    1328           0 :         if (tz) {
    1329           0 :                 r = table_add_many(table,
    1330             :                                    TABLE_EMPTY,
    1331             :                                    TABLE_STRING, "Time Zone:",
    1332             :                                    TABLE_STRING, tz);
    1333           0 :                 if (r < 0)
    1334           0 :                         return r;
    1335             :         }
    1336             : 
    1337           0 :         r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
    1338           0 :         if (r < 0)
    1339           0 :                 return r;
    1340             : 
    1341           0 :         r = dump_statistics(table, info);
    1342           0 :         if (r < 0)
    1343           0 :                 return r;
    1344             : 
    1345           0 :         return table_print(table, NULL);
    1346             : }
    1347             : 
    1348           0 : static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
    1349           0 :         _cleanup_free_ char *operational_state = NULL;
    1350           0 :         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
    1351             :         const char *on_color_operational, *off_color_operational;
    1352           0 :         _cleanup_(table_unrefp) Table *table = NULL;
    1353             :         TableCell *cell;
    1354             :         int r;
    1355             : 
    1356           0 :         assert(rtnl);
    1357             : 
    1358           0 :         (void) sd_network_get_operational_state(&operational_state);
    1359           0 :         operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
    1360             : 
    1361           0 :         table = table_new("dot", "key", "value");
    1362           0 :         if (!table)
    1363           0 :                 return -ENOMEM;
    1364             : 
    1365           0 :         assert_se(cell = table_get_cell(table, 0, 0));
    1366           0 :         (void) table_set_ellipsize_percent(table, cell, 100);
    1367             : 
    1368           0 :         assert_se(cell = table_get_cell(table, 0, 1));
    1369           0 :         (void) table_set_align_percent(table, cell, 100);
    1370           0 :         (void) table_set_ellipsize_percent(table, cell, 100);
    1371             : 
    1372           0 :         table_set_header(table, false);
    1373             : 
    1374           0 :         r = table_add_many(table,
    1375             :                            TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
    1376             :                            TABLE_SET_COLOR, on_color_operational,
    1377             :                            TABLE_STRING, "State:",
    1378             :                            TABLE_STRING, strna(operational_state),
    1379             :                            TABLE_SET_COLOR, on_color_operational);
    1380             : 
    1381           0 :         r = dump_addresses(rtnl, table, 0);
    1382           0 :         if (r < 0)
    1383           0 :                 return r;
    1384           0 :         r = dump_gateways(rtnl, hwdb, table, 0);
    1385           0 :         if (r < 0)
    1386           0 :                 return r;
    1387             : 
    1388           0 :         (void) sd_network_get_dns(&dns);
    1389           0 :         r = dump_list(table, "DNS:", dns);
    1390           0 :         if (r < 0)
    1391           0 :                 return r;
    1392             : 
    1393           0 :         (void) sd_network_get_search_domains(&search_domains);
    1394           0 :         r = dump_list(table, "Search Domains:", search_domains);
    1395           0 :         if (r < 0)
    1396           0 :                 return r;
    1397             : 
    1398           0 :         (void) sd_network_get_route_domains(&route_domains);
    1399           0 :         r = dump_list(table, "Route Domains:", route_domains);
    1400           0 :         if (r < 0)
    1401           0 :                 return r;
    1402             : 
    1403           0 :         (void) sd_network_get_ntp(&ntp);
    1404           0 :         r = dump_list(table, "NTP:", ntp);
    1405           0 :         if (r < 0)
    1406           0 :                 return r;
    1407             : 
    1408           0 :         return table_print(table, NULL);
    1409             : }
    1410             : 
    1411           0 : static int link_status(int argc, char *argv[], void *userdata) {
    1412           0 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    1413           0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
    1414           0 :         _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
    1415           0 :         _cleanup_free_ LinkInfo *links = NULL;
    1416             :         int r, c, i;
    1417             : 
    1418           0 :         (void) pager_open(arg_pager_flags);
    1419             : 
    1420           0 :         r = sd_bus_open_system(&bus);
    1421           0 :         if (r < 0)
    1422           0 :                 return log_error_errno(r, "Failed to connect system bus: %m");
    1423             : 
    1424           0 :         r = sd_netlink_open(&rtnl);
    1425           0 :         if (r < 0)
    1426           0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
    1427             : 
    1428           0 :         r = sd_hwdb_new(&hwdb);
    1429           0 :         if (r < 0)
    1430           0 :                 log_debug_errno(r, "Failed to open hardware database: %m");
    1431             : 
    1432           0 :         if (arg_all)
    1433           0 :                 c = acquire_link_info(bus, rtnl, NULL, &links);
    1434           0 :         else if (argc <= 1)
    1435           0 :                 return system_status(rtnl, hwdb);
    1436             :         else
    1437           0 :                 c = acquire_link_info(bus, rtnl, argv + 1, &links);
    1438           0 :         if (c < 0)
    1439           0 :                 return c;
    1440             : 
    1441           0 :         for (i = 0; i < c; i++) {
    1442           0 :                 if (i > 0)
    1443           0 :                         fputc('\n', stdout);
    1444             : 
    1445           0 :                 link_status_one(rtnl, hwdb, links + i);
    1446             :         }
    1447             : 
    1448           0 :         return 0;
    1449             : }
    1450             : 
    1451           0 : static char *lldp_capabilities_to_string(uint16_t x) {
    1452             :         static const char characters[] = {
    1453             :                 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
    1454             :         };
    1455             :         char *ret;
    1456             :         unsigned i;
    1457             : 
    1458           0 :         ret = new(char, ELEMENTSOF(characters) + 1);
    1459           0 :         if (!ret)
    1460           0 :                 return NULL;
    1461             : 
    1462           0 :         for (i = 0; i < ELEMENTSOF(characters); i++)
    1463           0 :                 ret[i] = (x & (1U << i)) ? characters[i] : '.';
    1464             : 
    1465           0 :         ret[i] = 0;
    1466           0 :         return ret;
    1467             : }
    1468             : 
    1469           0 : static void lldp_capabilities_legend(uint16_t x) {
    1470           0 :         unsigned w, i, cols = columns();
    1471             :         static const char* const table[] = {
    1472             :                 "o - Other",
    1473             :                 "p - Repeater",
    1474             :                 "b - Bridge",
    1475             :                 "w - WLAN Access Point",
    1476             :                 "r - Router",
    1477             :                 "t - Telephone",
    1478             :                 "d - DOCSIS cable device",
    1479             :                 "a - Station",
    1480             :                 "c - Customer VLAN",
    1481             :                 "s - Service VLAN",
    1482             :                 "m - Two-port MAC Relay (TPMR)",
    1483             :         };
    1484             : 
    1485           0 :         if (x == 0)
    1486           0 :                 return;
    1487             : 
    1488           0 :         printf("\nCapability Flags:\n");
    1489           0 :         for (w = 0, i = 0; i < ELEMENTSOF(table); i++)
    1490           0 :                 if (x & (1U << i) || arg_all) {
    1491             :                         bool newline;
    1492             : 
    1493           0 :                         newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols;
    1494           0 :                         if (newline)
    1495           0 :                                 w = 0;
    1496           0 :                         w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]);
    1497             :                 }
    1498           0 :         puts("");
    1499             : }
    1500             : 
    1501           0 : static int link_lldp_status(int argc, char *argv[], void *userdata) {
    1502           0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
    1503           0 :         _cleanup_free_ LinkInfo *links = NULL;
    1504           0 :         _cleanup_(table_unrefp) Table *table = NULL;
    1505           0 :         int i, r, c, m = 0;
    1506           0 :         uint16_t all = 0;
    1507             :         TableCell *cell;
    1508             : 
    1509           0 :         r = sd_netlink_open(&rtnl);
    1510           0 :         if (r < 0)
    1511           0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
    1512             : 
    1513           0 :         c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
    1514           0 :         if (c < 0)
    1515           0 :                 return c;
    1516             : 
    1517           0 :         (void) pager_open(arg_pager_flags);
    1518             : 
    1519           0 :         table = table_new("link",
    1520             :                           "chassis id",
    1521             :                           "system name",
    1522             :                           "caps",
    1523             :                           "port id",
    1524             :                           "port description");
    1525           0 :         if (!table)
    1526           0 :                 return -ENOMEM;
    1527             : 
    1528           0 :         table_set_header(table, arg_legend);
    1529             : 
    1530           0 :         assert_se(cell = table_get_cell(table, 0, 0));
    1531           0 :         table_set_minimum_width(table, cell, 16);
    1532             : 
    1533           0 :         assert_se(cell = table_get_cell(table, 0, 1));
    1534           0 :         table_set_minimum_width(table, cell, 17);
    1535             : 
    1536           0 :         assert_se(cell = table_get_cell(table, 0, 2));
    1537           0 :         table_set_minimum_width(table, cell, 16);
    1538             : 
    1539           0 :         assert_se(cell = table_get_cell(table, 0, 3));
    1540           0 :         table_set_minimum_width(table, cell, 11);
    1541             : 
    1542           0 :         assert_se(cell = table_get_cell(table, 0, 4));
    1543           0 :         table_set_minimum_width(table, cell, 17);
    1544             : 
    1545           0 :         assert_se(cell = table_get_cell(table, 0, 5));
    1546           0 :         table_set_minimum_width(table, cell, 16);
    1547             : 
    1548           0 :         for (i = 0; i < c; i++) {
    1549           0 :                 _cleanup_fclose_ FILE *f = NULL;
    1550             : 
    1551           0 :                 r = open_lldp_neighbors(links[i].ifindex, &f);
    1552           0 :                 if (r == -ENOENT)
    1553           0 :                         continue;
    1554           0 :                 if (r < 0) {
    1555           0 :                         log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex);
    1556           0 :                         continue;
    1557             :                 }
    1558             : 
    1559           0 :                 for (;;) {
    1560           0 :                         _cleanup_free_ char *cid = NULL, *pid = NULL, *sname = NULL, *pdesc = NULL, *capabilities = NULL;
    1561           0 :                         const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL;
    1562           0 :                         _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
    1563             :                         uint16_t cc;
    1564             : 
    1565           0 :                         r = next_lldp_neighbor(f, &n);
    1566           0 :                         if (r < 0) {
    1567           0 :                                 log_warning_errno(r, "Failed to read neighbor data: %m");
    1568           0 :                                 break;
    1569             :                         }
    1570           0 :                         if (r == 0)
    1571           0 :                                 break;
    1572             : 
    1573           0 :                         (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id);
    1574           0 :                         (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
    1575           0 :                         (void) sd_lldp_neighbor_get_system_name(n, &system_name);
    1576           0 :                         (void) sd_lldp_neighbor_get_port_description(n, &port_description);
    1577             : 
    1578           0 :                         if (chassis_id) {
    1579           0 :                                 cid = ellipsize(chassis_id, 17, 100);
    1580           0 :                                 if (cid)
    1581           0 :                                         chassis_id = cid;
    1582             :                         }
    1583             : 
    1584           0 :                         if (port_id) {
    1585           0 :                                 pid = ellipsize(port_id, 17, 100);
    1586           0 :                                 if (pid)
    1587           0 :                                         port_id = pid;
    1588             :                         }
    1589             : 
    1590           0 :                         if (system_name) {
    1591           0 :                                 sname = ellipsize(system_name, 16, 100);
    1592           0 :                                 if (sname)
    1593           0 :                                         system_name = sname;
    1594             :                         }
    1595             : 
    1596           0 :                         if (port_description) {
    1597           0 :                                 pdesc = ellipsize(port_description, 16, 100);
    1598           0 :                                 if (pdesc)
    1599           0 :                                         port_description = pdesc;
    1600             :                         }
    1601             : 
    1602           0 :                         if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) {
    1603           0 :                                 capabilities = lldp_capabilities_to_string(cc);
    1604           0 :                                 all |= cc;
    1605             :                         }
    1606             : 
    1607           0 :                         r = table_add_many(table,
    1608             :                                            TABLE_STRING, links[i].name,
    1609             :                                            TABLE_STRING, strna(chassis_id),
    1610             :                                            TABLE_STRING, strna(system_name),
    1611             :                                            TABLE_STRING, strna(capabilities),
    1612             :                                            TABLE_STRING, strna(port_id),
    1613             :                                            TABLE_STRING, strna(port_description));
    1614           0 :                         if (r < 0)
    1615           0 :                                 return r;
    1616             : 
    1617           0 :                         m++;
    1618             :                 }
    1619             :         }
    1620             : 
    1621           0 :         r = table_print(table, NULL);
    1622           0 :         if (r < 0)
    1623           0 :                 return r;
    1624             : 
    1625           0 :         if (arg_legend) {
    1626           0 :                 lldp_capabilities_legend(all);
    1627           0 :                 printf("\n%i neighbors listed.\n", m);
    1628             :         }
    1629             : 
    1630           0 :         return 0;
    1631             : }
    1632             : 
    1633           0 : static int link_delete_send_message(sd_netlink *rtnl, int index) {
    1634           0 :         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
    1635             :         int r;
    1636             : 
    1637           0 :         assert(rtnl);
    1638             : 
    1639           0 :         r = sd_rtnl_message_new_link(rtnl, &req, RTM_DELLINK, index);
    1640           0 :         if (r < 0)
    1641           0 :                 return rtnl_log_create_error(r);
    1642             : 
    1643           0 :         r = sd_netlink_call(rtnl, req, 0, NULL);
    1644           0 :         if (r < 0)
    1645           0 :                 return r;
    1646             : 
    1647           0 :         return 0;
    1648             : }
    1649             : 
    1650           0 : static int link_delete(int argc, char *argv[], void *userdata) {
    1651           0 :         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
    1652           0 :         _cleanup_set_free_ Set *indexes = NULL;
    1653             :         int index, r, i;
    1654             :         Iterator j;
    1655             :         void *p;
    1656             : 
    1657           0 :         r = sd_netlink_open(&rtnl);
    1658           0 :         if (r < 0)
    1659           0 :                 return log_error_errno(r, "Failed to connect to netlink: %m");
    1660             : 
    1661           0 :         indexes = set_new(NULL);
    1662           0 :         if (!indexes)
    1663           0 :                 return log_oom();
    1664             : 
    1665           0 :         for (i = 1; i < argc; i++) {
    1666           0 :                 r = parse_ifindex_or_ifname(argv[i], &index);
    1667           0 :                 if (r < 0)
    1668           0 :                         return log_error_errno(r, "Failed to resolve interface %s", argv[i]);
    1669             : 
    1670           0 :                 r = set_put(indexes, INT_TO_PTR(index));
    1671           0 :                 if (r < 0)
    1672           0 :                         return log_oom();
    1673             :         }
    1674             : 
    1675           0 :         SET_FOREACH(p, indexes, j) {
    1676           0 :                 r = link_delete_send_message(rtnl, PTR_TO_INT(p));
    1677           0 :                 if (r < 0) {
    1678             :                         char ifname[IF_NAMESIZE + 1];
    1679             : 
    1680           0 :                         if (format_ifname(index, ifname))
    1681           0 :                                 return log_error_errno(r, "Failed to delete interface %s: %m", ifname);
    1682             :                         else
    1683           0 :                                 return log_error_errno(r, "Failed to delete interface %d: %m", index);
    1684             :                 }
    1685             :         }
    1686             : 
    1687           0 :         return r;
    1688             : }
    1689             : 
    1690           3 : static int help(void) {
    1691           3 :         _cleanup_free_ char *link = NULL;
    1692             :         int r;
    1693             : 
    1694           3 :         r = terminal_urlify_man("networkctl", "1", &link);
    1695           3 :         if (r < 0)
    1696           0 :                 return log_oom();
    1697             : 
    1698           3 :         printf("%s [OPTIONS...]\n\n"
    1699             :                "Query and control the networking subsystem.\n\n"
    1700             :                "  -h --help             Show this help\n"
    1701             :                "     --version          Show package version\n"
    1702             :                "     --no-pager         Do not pipe output into a pager\n"
    1703             :                "     --no-legend        Do not show the headers and footers\n"
    1704             :                "  -a --all              Show status for all links\n"
    1705             :                "  -s --stats            Show detailed link statics\n"
    1706             :                "\nCommands:\n"
    1707             :                "  list [PATTERN...]     List links\n"
    1708             :                "  status [PATTERN...]   Show link status\n"
    1709             :                "  lldp [PATTERN...]     Show LLDP neighbors\n"
    1710             :                "  label                 Show current address label entries in the kernel\n"
    1711             :                "  delete DEVICES        Delete virtual netdevs\n"
    1712             :                "\nSee the %s for details.\n"
    1713             :                , program_invocation_short_name
    1714             :                , link
    1715             :         );
    1716             : 
    1717           3 :         return 0;
    1718             : }
    1719             : 
    1720           4 : static int parse_argv(int argc, char *argv[]) {
    1721             : 
    1722             :         enum {
    1723             :                 ARG_VERSION = 0x100,
    1724             :                 ARG_NO_PAGER,
    1725             :                 ARG_NO_LEGEND,
    1726             :         };
    1727             : 
    1728             :         static const struct option options[] = {
    1729             :                 { "help",      no_argument,       NULL, 'h'           },
    1730             :                 { "version",   no_argument,       NULL, ARG_VERSION   },
    1731             :                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
    1732             :                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
    1733             :                 { "all",       no_argument,       NULL, 'a'           },
    1734             :                 { "stats",     no_argument,       NULL, 's'           },
    1735             :                 {}
    1736             :         };
    1737             : 
    1738             :         int c;
    1739             : 
    1740           4 :         assert(argc >= 0);
    1741           4 :         assert(argv);
    1742             : 
    1743           4 :         while ((c = getopt_long(argc, argv, "has", options, NULL)) >= 0) {
    1744             : 
    1745           4 :                 switch (c) {
    1746             : 
    1747           3 :                 case 'h':
    1748           3 :                         return help();
    1749             : 
    1750           0 :                 case ARG_VERSION:
    1751           0 :                         return version();
    1752             : 
    1753           0 :                 case ARG_NO_PAGER:
    1754           0 :                         arg_pager_flags |= PAGER_DISABLE;
    1755           0 :                         break;
    1756             : 
    1757           0 :                 case ARG_NO_LEGEND:
    1758           0 :                         arg_legend = false;
    1759           0 :                         break;
    1760             : 
    1761           0 :                 case 'a':
    1762           0 :                         arg_all = true;
    1763           0 :                         break;
    1764             : 
    1765           0 :                 case 's':
    1766           0 :                         arg_stats = true;
    1767           0 :                         break;
    1768             : 
    1769           1 :                 case '?':
    1770           1 :                         return -EINVAL;
    1771             : 
    1772           0 :                 default:
    1773           0 :                         assert_not_reached("Unhandled option");
    1774             :                 }
    1775             :         }
    1776             : 
    1777           0 :         return 1;
    1778             : }
    1779             : 
    1780           0 : static int networkctl_main(int argc, char *argv[]) {
    1781             :         static const Verb verbs[] = {
    1782             :                 { "list",   VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links          },
    1783             :                 { "status", VERB_ANY, VERB_ANY, 0,            link_status         },
    1784             :                 { "lldp",   VERB_ANY, VERB_ANY, 0,            link_lldp_status    },
    1785             :                 { "label",  VERB_ANY, VERB_ANY, 0,            list_address_labels },
    1786             :                 { "delete", 2,        VERB_ANY, 0,            link_delete         },
    1787             :                 {}
    1788             :         };
    1789             : 
    1790           0 :         return dispatch_verb(argc, argv, verbs, NULL);
    1791             : }
    1792             : 
    1793           0 : static void warn_networkd_missing(void) {
    1794             : 
    1795           0 :         if (access("/run/systemd/netif/state", F_OK) >= 0)
    1796           0 :                 return;
    1797             : 
    1798           0 :         fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
    1799             : }
    1800             : 
    1801           4 : static int run(int argc, char* argv[]) {
    1802             :         int r;
    1803             : 
    1804           4 :         log_show_color(true);
    1805           4 :         log_parse_environment();
    1806           4 :         log_open();
    1807             : 
    1808           4 :         r = parse_argv(argc, argv);
    1809           4 :         if (r <= 0)
    1810           4 :                 return r;
    1811             : 
    1812           0 :         warn_networkd_missing();
    1813             : 
    1814           0 :         return networkctl_main(argc, argv);
    1815             : }
    1816             : 
    1817           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14