1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <arpa/inet.h>
4 #include <getopt.h>
5 #include <linux/if_addrlabel.h>
6 #include <net/if.h>
7 #include <stdbool.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include <linux/if_bridge.h>
12 #include <linux/if_tunnel.h>
13 
14 #include "sd-bus.h"
15 #include "sd-device.h"
16 #include "sd-dhcp-client.h"
17 #include "sd-hwdb.h"
18 #include "sd-lldp-rx.h"
19 #include "sd-netlink.h"
20 #include "sd-network.h"
21 
22 #include "alloc-util.h"
23 #include "bond-util.h"
24 #include "bridge-util.h"
25 #include "bus-common-errors.h"
26 #include "bus-error.h"
27 #include "bus-locator.h"
28 #include "device-util.h"
29 #include "escape.h"
30 #include "ether-addr-util.h"
31 #include "ethtool-util.h"
32 #include "fd-util.h"
33 #include "format-table.h"
34 #include "format-util.h"
35 #include "geneve-util.h"
36 #include "glob-util.h"
37 #include "hwdb-util.h"
38 #include "ipvlan-util.h"
39 #include "local-addresses.h"
40 #include "locale-util.h"
41 #include "logs-show.h"
42 #include "macro.h"
43 #include "macvlan-util.h"
44 #include "main-func.h"
45 #include "netif-util.h"
46 #include "netlink-util.h"
47 #include "network-internal.h"
48 #include "network-util.h"
49 #include "pager.h"
50 #include "parse-argument.h"
51 #include "parse-util.h"
52 #include "pretty-print.h"
53 #include "set.h"
54 #include "socket-netlink.h"
55 #include "socket-util.h"
56 #include "sort-util.h"
57 #include "sparse-endian.h"
58 #include "stdio-util.h"
59 #include "string-table.h"
60 #include "string-util.h"
61 #include "strv.h"
62 #include "strxcpyx.h"
63 #include "terminal-util.h"
64 #include "unit-def.h"
65 #include "verbs.h"
66 #include "wifi-util.h"
67 
68 /* Kernel defines MODULE_NAME_LEN as 64 - sizeof(unsigned long). So, 64 is enough. */
69 #define NETDEV_KIND_MAX 64
70 
71 /* use 128 kB for receive socket kernel queue, we shouldn't need more here */
72 #define RCVBUF_SIZE    (128*1024)
73 
74 static PagerFlags arg_pager_flags = 0;
75 static bool arg_legend = true;
76 static bool arg_all = false;
77 static bool arg_stats = false;
78 static bool arg_full = false;
79 static unsigned arg_lines = 10;
80 static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
81 
get_description(sd_bus * bus,JsonVariant ** ret)82 static int get_description(sd_bus *bus, JsonVariant **ret) {
83         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
84         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
85         const char *text = NULL;
86         int r;
87 
88         r = bus_call_method(bus, bus_network_mgr, "Describe", &error, &reply, NULL);
89         if (r < 0)
90                 return log_error_errno(r, "Failed to get description: %s", bus_error_message(&error, r));
91 
92         r = sd_bus_message_read(reply, "s", &text);
93         if (r < 0)
94                 return bus_log_parse_error(r);
95 
96         r = json_parse(text, 0, ret, NULL, NULL);
97         if (r < 0)
98                 return log_error_errno(r, "Failed to parse JSON: %m");
99 
100         return 0;
101 }
102 
dump_manager_description(sd_bus * bus)103 static int dump_manager_description(sd_bus *bus) {
104         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
105         int r;
106 
107         r = get_description(bus, &v);
108         if (r < 0)
109                 return r;
110 
111         json_variant_dump(v, arg_json_format_flags, NULL, NULL);
112         return 0;
113 }
114 
dump_link_description(sd_bus * bus,char ** patterns)115 static int dump_link_description(sd_bus *bus, char **patterns) {
116         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
117         _cleanup_free_ bool *matched_patterns = NULL;
118         JsonVariant *i;
119         size_t c = 0;
120         int r;
121 
122         r = get_description(bus, &v);
123         if (r < 0)
124                 return r;
125 
126         matched_patterns = new0(bool, strv_length(patterns));
127         if (!matched_patterns)
128                 return log_oom();
129 
130         JSON_VARIANT_ARRAY_FOREACH(i, json_variant_by_key(v, "Interfaces")) {
131                 char ifindex_str[DECIMAL_STR_MAX(int64_t)];
132                 const char *name;
133                 int64_t index;
134                 size_t pos;
135 
136                 name = json_variant_string(json_variant_by_key(i, "Name"));
137                 index = json_variant_integer(json_variant_by_key(i, "Index"));
138                 xsprintf(ifindex_str, "%ji", index);
139 
140                 if (!strv_fnmatch_full(patterns, ifindex_str, 0, &pos) &&
141                     !strv_fnmatch_full(patterns, name, 0, &pos)) {
142                         bool match = false;
143                         JsonVariant *a;
144 
145                         JSON_VARIANT_ARRAY_FOREACH(a, json_variant_by_key(i, "AlternativeNames"))
146                                 if (strv_fnmatch_full(patterns, json_variant_string(a), 0, &pos)) {
147                                         match = true;
148                                         break;
149                                 }
150 
151                         if (!match)
152                                 continue;
153                 }
154 
155                 matched_patterns[pos] = true;
156                 json_variant_dump(i, arg_json_format_flags, NULL, NULL);
157                 c++;
158         }
159 
160         /* Look if we matched all our arguments that are not globs. It is OK for a glob to match
161          * nothing, but not for an exact argument. */
162         for (size_t pos = 0; pos < strv_length(patterns); pos++) {
163                 if (matched_patterns[pos])
164                         continue;
165 
166                 if (string_is_glob(patterns[pos]))
167                         log_debug("Pattern \"%s\" doesn't match any interface, ignoring.",
168                                   patterns[pos]);
169                 else
170                         return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
171                                                "Interface \"%s\" not found.", patterns[pos]);
172         }
173 
174         if (c == 0)
175                 log_warning("No interfaces matched.");
176 
177         return 0;
178 }
179 
operational_state_to_color(const char * name,const char * state,const char ** on,const char ** off)180 static void operational_state_to_color(const char *name, const char *state, const char **on, const char **off) {
181         if (STRPTR_IN_SET(state, "routable", "enslaved") ||
182             (streq_ptr(name, "lo") && streq_ptr(state, "carrier"))) {
183                 if (on)
184                         *on = ansi_highlight_green();
185                 if (off)
186                         *off = ansi_normal();
187         } else if (streq_ptr(state, "degraded")) {
188                 if (on)
189                         *on = ansi_highlight_yellow();
190                 if (off)
191                         *off = ansi_normal();
192         } else {
193                 if (on)
194                         *on = "";
195                 if (off)
196                         *off = "";
197         }
198 }
199 
setup_state_to_color(const char * state,const char ** on,const char ** off)200 static void setup_state_to_color(const char *state, const char **on, const char **off) {
201         if (streq_ptr(state, "configured")) {
202                 if (on)
203                         *on = ansi_highlight_green();
204                 if (off)
205                         *off = ansi_normal();
206         } else if (streq_ptr(state, "configuring")) {
207                 if (on)
208                         *on = ansi_highlight_yellow();
209                 if (off)
210                         *off = ansi_normal();
211         } else if (STRPTR_IN_SET(state, "failed", "linger")) {
212                 if (on)
213                         *on = ansi_highlight_red();
214                 if (off)
215                         *off = ansi_normal();
216         } else {
217                 if (on)
218                         *on = "";
219                 if (off)
220                         *off = "";
221         }
222 }
223 
online_state_to_color(const char * state,const char ** on,const char ** off)224 static void online_state_to_color(const char *state, const char **on, const char **off) {
225         if (streq_ptr(state, "online")) {
226                 if (on)
227                         *on = ansi_highlight_green();
228                 if (off)
229                         *off = ansi_normal();
230         } else if (streq_ptr(state, "partial")) {
231                 if (on)
232                         *on = ansi_highlight_yellow();
233                 if (off)
234                         *off = ansi_normal();
235         } else {
236                 if (on)
237                         *on = "";
238                 if (off)
239                         *off = "";
240         }
241 }
242 
243 typedef struct VxLanInfo {
244         uint32_t vni;
245         uint32_t link;
246 
247         int local_family;
248         int group_family;
249 
250         union in_addr_union local;
251         union in_addr_union group;
252 
253         uint16_t dest_port;
254 
255         uint8_t proxy;
256         uint8_t learning;
257         uint8_t rsc;
258         uint8_t l2miss;
259         uint8_t l3miss;
260         uint8_t tos;
261         uint8_t ttl;
262 } VxLanInfo;
263 
264 typedef struct LinkInfo {
265         char name[IFNAMSIZ+1];
266         char *netdev_kind;
267         sd_device *sd_device;
268         int ifindex;
269         unsigned short iftype;
270         struct hw_addr_data hw_address;
271         struct hw_addr_data permanent_hw_address;
272         uint32_t master;
273         uint32_t mtu;
274         uint32_t min_mtu;
275         uint32_t max_mtu;
276         uint32_t tx_queues;
277         uint32_t rx_queues;
278         uint8_t addr_gen_mode;
279         char *qdisc;
280         char **alternative_names;
281 
282         union {
283                 struct rtnl_link_stats64 stats64;
284                 struct rtnl_link_stats stats;
285         };
286 
287         uint64_t tx_bitrate;
288         uint64_t rx_bitrate;
289 
290         /* bridge info */
291         uint32_t forward_delay;
292         uint32_t hello_time;
293         uint32_t max_age;
294         uint32_t ageing_time;
295         uint32_t stp_state;
296         uint32_t cost;
297         uint16_t priority;
298         uint8_t mcast_igmp_version;
299         uint8_t port_state;
300 
301         /* vxlan info */
302         VxLanInfo vxlan_info;
303 
304         /* vlan info */
305         uint16_t vlan_id;
306 
307         /* tunnel info */
308         uint8_t ttl;
309         uint8_t tos;
310         uint8_t inherit;
311         uint8_t df;
312         uint8_t csum;
313         uint8_t csum6_tx;
314         uint8_t csum6_rx;
315         uint16_t tunnel_port;
316         uint32_t vni;
317         uint32_t label;
318         union in_addr_union local;
319         union in_addr_union remote;
320 
321         /* bonding info */
322         uint8_t mode;
323         uint32_t miimon;
324         uint32_t updelay;
325         uint32_t downdelay;
326 
327         /* macvlan and macvtap info */
328         uint32_t macvlan_mode;
329 
330         /* ipvlan info */
331         uint16_t ipvlan_mode;
332         uint16_t ipvlan_flags;
333 
334         /* ethtool info */
335         int autonegotiation;
336         uint64_t speed;
337         Duplex duplex;
338         NetDevPort port;
339 
340         /* wlan info */
341         enum nl80211_iftype wlan_iftype;
342         char *ssid;
343         struct ether_addr bssid;
344 
345         bool has_hw_address:1;
346         bool has_permanent_hw_address:1;
347         bool has_tx_queues:1;
348         bool has_rx_queues:1;
349         bool has_stats64:1;
350         bool has_stats:1;
351         bool has_bitrates:1;
352         bool has_ethtool_link_info:1;
353         bool has_wlan_link_info:1;
354         bool has_tunnel_ipv4:1;
355         bool has_ipv6_address_generation_mode:1;
356 
357         bool needs_freeing:1;
358 } LinkInfo;
359 
link_info_compare(const LinkInfo * a,const LinkInfo * b)360 static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
361         return CMP(a->ifindex, b->ifindex);
362 }
363 
link_info_array_free(LinkInfo * array)364 static LinkInfo* link_info_array_free(LinkInfo *array) {
365         for (unsigned i = 0; array && array[i].needs_freeing; i++) {
366                 sd_device_unref(array[i].sd_device);
367                 free(array[i].netdev_kind);
368                 free(array[i].ssid);
369                 free(array[i].qdisc);
370                 strv_free(array[i].alternative_names);
371         }
372 
373         return mfree(array);
374 }
375 DEFINE_TRIVIAL_CLEANUP_FUNC(LinkInfo*, link_info_array_free);
376 
decode_netdev(sd_netlink_message * m,LinkInfo * info)377 static int decode_netdev(sd_netlink_message *m, LinkInfo *info) {
378         int r;
379 
380         assert(m);
381         assert(info);
382 
383         r = sd_netlink_message_enter_container(m, IFLA_LINKINFO);
384         if (r < 0)
385                 return r;
386 
387         r = sd_netlink_message_read_string_strdup(m, IFLA_INFO_KIND, &info->netdev_kind);
388         if (r < 0) {
389                 (void) sd_netlink_message_exit_container(m);
390                 return r;
391         }
392 
393         r = sd_netlink_message_enter_container(m, IFLA_INFO_DATA);
394         if (r < 0)
395                 return r;
396 
397         if (streq(info->netdev_kind, "bridge")) {
398                 (void) sd_netlink_message_read_u32(m, IFLA_BR_FORWARD_DELAY, &info->forward_delay);
399                 (void) sd_netlink_message_read_u32(m, IFLA_BR_HELLO_TIME, &info->hello_time);
400                 (void) sd_netlink_message_read_u32(m, IFLA_BR_MAX_AGE, &info->max_age);
401                 (void) sd_netlink_message_read_u32(m, IFLA_BR_AGEING_TIME, &info->ageing_time);
402                 (void) sd_netlink_message_read_u32(m, IFLA_BR_STP_STATE, &info->stp_state);
403                 (void) sd_netlink_message_read_u32(m, IFLA_BRPORT_COST, &info->cost);
404                 (void) sd_netlink_message_read_u16(m, IFLA_BR_PRIORITY, &info->priority);
405                 (void) sd_netlink_message_read_u8(m, IFLA_BR_MCAST_IGMP_VERSION, &info->mcast_igmp_version);
406                 (void) sd_netlink_message_read_u8(m, IFLA_BRPORT_STATE, &info->port_state);
407         } if (streq(info->netdev_kind, "bond")) {
408                 (void) sd_netlink_message_read_u8(m, IFLA_BOND_MODE, &info->mode);
409                 (void) sd_netlink_message_read_u32(m, IFLA_BOND_MIIMON, &info->miimon);
410                 (void) sd_netlink_message_read_u32(m, IFLA_BOND_DOWNDELAY, &info->downdelay);
411                 (void) sd_netlink_message_read_u32(m, IFLA_BOND_UPDELAY, &info->updelay);
412         } else if (streq(info->netdev_kind, "vxlan")) {
413                 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_ID, &info->vxlan_info.vni);
414 
415                 r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_GROUP, &info->vxlan_info.group.in);
416                 if (r >= 0)
417                         info->vxlan_info.group_family = AF_INET;
418                 else {
419                         r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_GROUP6, &info->vxlan_info.group.in6);
420                         if (r >= 0)
421                                 info->vxlan_info.group_family = AF_INET6;
422                 }
423 
424                 r = sd_netlink_message_read_in_addr(m, IFLA_VXLAN_LOCAL, &info->vxlan_info.local.in);
425                 if (r >= 0)
426                         info->vxlan_info.local_family = AF_INET;
427                 else {
428                         r = sd_netlink_message_read_in6_addr(m, IFLA_VXLAN_LOCAL6, &info->vxlan_info.local.in6);
429                         if (r >= 0)
430                                 info->vxlan_info.local_family = AF_INET6;
431                 }
432 
433                 (void) sd_netlink_message_read_u32(m, IFLA_VXLAN_LINK, &info->vxlan_info.link);
434                 (void) sd_netlink_message_read_u16(m, IFLA_VXLAN_PORT, &info->vxlan_info.dest_port);
435                 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_PROXY, &info->vxlan_info.proxy);
436                 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_LEARNING, &info->vxlan_info.learning);
437                 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_RSC, &info->vxlan_info.rsc);
438                 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L3MISS, &info->vxlan_info.l3miss);
439                 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_L2MISS, &info->vxlan_info.l2miss);
440                 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TOS, &info->vxlan_info.tos);
441                 (void) sd_netlink_message_read_u8(m, IFLA_VXLAN_TTL, &info->vxlan_info.ttl);
442         } else if (streq(info->netdev_kind, "vlan"))
443                 (void) sd_netlink_message_read_u16(m, IFLA_VLAN_ID, &info->vlan_id);
444         else if (STR_IN_SET(info->netdev_kind, "ipip", "sit")) {
445                 (void) sd_netlink_message_read_in_addr(m, IFLA_IPTUN_LOCAL, &info->local.in);
446                 (void) sd_netlink_message_read_in_addr(m, IFLA_IPTUN_REMOTE, &info->remote.in);
447         } else if (streq(info->netdev_kind, "geneve")) {
448                 (void) sd_netlink_message_read_u32(m, IFLA_GENEVE_ID, &info->vni);
449 
450                 r = sd_netlink_message_read_in_addr(m, IFLA_GENEVE_REMOTE, &info->remote.in);
451                 if (r >= 0)
452                         info->has_tunnel_ipv4 = true;
453                 else
454                         (void) sd_netlink_message_read_in6_addr(m, IFLA_GENEVE_REMOTE6, &info->remote.in6);
455 
456                 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_TTL, &info->ttl);
457                 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_TTL_INHERIT, &info->inherit);
458                 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_TOS, &info->tos);
459                 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_DF, &info->df);
460                 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_UDP_CSUM, &info->csum);
461                 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_TX, &info->csum6_tx);
462                 (void) sd_netlink_message_read_u8(m, IFLA_GENEVE_UDP_ZERO_CSUM6_RX, &info->csum6_rx);
463                 (void) sd_netlink_message_read_u16(m, IFLA_GENEVE_PORT, &info->tunnel_port);
464                 (void) sd_netlink_message_read_u32(m, IFLA_GENEVE_LABEL, &info->label);
465         } else if (STR_IN_SET(info->netdev_kind, "gre", "gretap", "erspan")) {
466                 (void) sd_netlink_message_read_in_addr(m, IFLA_GRE_LOCAL, &info->local.in);
467                 (void) sd_netlink_message_read_in_addr(m, IFLA_GRE_REMOTE, &info->remote.in);
468         } else if (STR_IN_SET(info->netdev_kind, "ip6gre", "ip6gretap", "ip6erspan")) {
469                 (void) sd_netlink_message_read_in6_addr(m, IFLA_GRE_LOCAL, &info->local.in6);
470                 (void) sd_netlink_message_read_in6_addr(m, IFLA_GRE_REMOTE, &info->remote.in6);
471         } else if (streq(info->netdev_kind, "vti")) {
472                 (void) sd_netlink_message_read_in_addr(m, IFLA_VTI_LOCAL, &info->local.in);
473                 (void) sd_netlink_message_read_in_addr(m, IFLA_VTI_REMOTE, &info->remote.in);
474         } else if (streq(info->netdev_kind, "vti6")) {
475                 (void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_LOCAL, &info->local.in6);
476                 (void) sd_netlink_message_read_in6_addr(m, IFLA_VTI_REMOTE, &info->remote.in6);
477         } else if (STR_IN_SET(info->netdev_kind, "macvlan", "macvtap"))
478                 (void) sd_netlink_message_read_u32(m, IFLA_MACVLAN_MODE, &info->macvlan_mode);
479         else if (streq(info->netdev_kind, "ipvlan")) {
480                 (void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_MODE, &info->ipvlan_mode);
481                 (void) sd_netlink_message_read_u16(m, IFLA_IPVLAN_FLAGS, &info->ipvlan_flags);
482         }
483 
484         (void) sd_netlink_message_exit_container(m);
485         (void) sd_netlink_message_exit_container(m);
486 
487         return 0;
488 }
489 
decode_link(sd_netlink_message * m,LinkInfo * info,char ** patterns,bool matched_patterns[])490 static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns, bool matched_patterns[]) {
491         _cleanup_strv_free_ char **altnames = NULL;
492         const char *name, *qdisc;
493         int ifindex, r;
494         uint16_t type;
495 
496         assert(m);
497         assert(info);
498 
499         r = sd_netlink_message_get_type(m, &type);
500         if (r < 0)
501                 return r;
502 
503         if (type != RTM_NEWLINK)
504                 return 0;
505 
506         r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
507         if (r < 0)
508                 return r;
509 
510         r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name);
511         if (r < 0)
512                 return r;
513 
514         r = sd_netlink_message_read_strv(m, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &altnames);
515         if (r < 0 && r != -ENODATA)
516                 return r;
517 
518         if (patterns) {
519                 char str[DECIMAL_STR_MAX(int)];
520                 size_t pos;
521 
522                 assert(matched_patterns);
523 
524                 xsprintf(str, "%i", ifindex);
525                 if (!strv_fnmatch_full(patterns, str, 0, &pos) &&
526                     !strv_fnmatch_full(patterns, name, 0, &pos)) {
527                         bool match = false;
528 
529                         STRV_FOREACH(p, altnames)
530                                 if (strv_fnmatch_full(patterns, *p, 0, &pos)) {
531                                         match = true;
532                                         break;
533                                 }
534                         if (!match)
535                                 return 0;
536                 }
537 
538                 matched_patterns[pos] = true;
539         }
540 
541         r = sd_rtnl_message_link_get_type(m, &info->iftype);
542         if (r < 0)
543                 return r;
544 
545         strscpy(info->name, sizeof info->name, name);
546         info->ifindex = ifindex;
547         info->alternative_names = TAKE_PTR(altnames);
548 
549         info->has_hw_address =
550                 netlink_message_read_hw_addr(m, IFLA_ADDRESS, &info->hw_address) >= 0 &&
551                 info->hw_address.length > 0;
552 
553         info->has_permanent_hw_address =
554                 (netlink_message_read_hw_addr(m, IFLA_PERM_ADDRESS, &info->permanent_hw_address) >= 0 ||
555                  ethtool_get_permanent_hw_addr(NULL, info->name, &info->permanent_hw_address) >= 0) &&
556                 !hw_addr_is_null(&info->permanent_hw_address) &&
557                 !hw_addr_equal(&info->permanent_hw_address, &info->hw_address);
558 
559         (void) sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu);
560         (void) sd_netlink_message_read_u32(m, IFLA_MIN_MTU, &info->min_mtu);
561         (void) sd_netlink_message_read_u32(m, IFLA_MAX_MTU, &info->max_mtu);
562 
563         info->has_rx_queues =
564                 sd_netlink_message_read_u32(m, IFLA_NUM_RX_QUEUES, &info->rx_queues) >= 0 &&
565                 info->rx_queues > 0;
566 
567         info->has_tx_queues =
568                 sd_netlink_message_read_u32(m, IFLA_NUM_TX_QUEUES, &info->tx_queues) >= 0 &&
569                 info->tx_queues > 0;
570 
571         if (sd_netlink_message_read(m, IFLA_STATS64, sizeof info->stats64, &info->stats64) >= 0)
572                 info->has_stats64 = true;
573         else if (sd_netlink_message_read(m, IFLA_STATS, sizeof info->stats, &info->stats) >= 0)
574                 info->has_stats = true;
575 
576         r = sd_netlink_message_read_string(m, IFLA_QDISC, &qdisc);
577         if (r >= 0) {
578                 info->qdisc = strdup(qdisc);
579                 if (!info->qdisc)
580                         return log_oom();
581         }
582 
583         (void) sd_netlink_message_read_u32(m, IFLA_MASTER, &info->master);
584 
585         r = sd_netlink_message_enter_container(m, IFLA_AF_SPEC);
586         if (r >= 0) {
587                 r = sd_netlink_message_enter_container(m, AF_INET6);
588                 if (r >= 0) {
589                         r = sd_netlink_message_read_u8(m, IFLA_INET6_ADDR_GEN_MODE, &info->addr_gen_mode);
590                         if (r >= 0 && IN_SET(info->addr_gen_mode,
591                                              IN6_ADDR_GEN_MODE_EUI64,
592                                              IN6_ADDR_GEN_MODE_NONE,
593                                              IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
594                                              IN6_ADDR_GEN_MODE_RANDOM))
595                                 info->has_ipv6_address_generation_mode = true;
596 
597                         (void) sd_netlink_message_exit_container(m);
598                 }
599                 (void) sd_netlink_message_exit_container(m);
600         }
601 
602         /* fill kind info */
603         (void) decode_netdev(m, info);
604 
605         return 1;
606 }
607 
link_get_property(sd_bus * bus,const LinkInfo * link,sd_bus_error * error,sd_bus_message ** reply,const char * iface,const char * propname)608 static int link_get_property(
609                 sd_bus *bus,
610                 const LinkInfo *link,
611                 sd_bus_error *error,
612                 sd_bus_message **reply,
613                 const char *iface,
614                 const char *propname) {
615 
616         char ifindex_str[DECIMAL_STR_MAX(int)];
617         _cleanup_free_ char *path = NULL;
618         int r;
619 
620         xsprintf(ifindex_str, "%i", link->ifindex);
621 
622         r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex_str, &path);
623         if (r < 0)
624                 return r;
625 
626         return sd_bus_call_method(
627                         bus,
628                         "org.freedesktop.network1",
629                         path,
630                         "org.freedesktop.DBus.Properties",
631                         "Get",
632                         error,
633                         reply,
634                         "ss",
635                         iface,
636                         propname);
637 }
638 
acquire_link_bitrates(sd_bus * bus,LinkInfo * link)639 static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
640         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
641         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
642         int r;
643 
644         r = link_get_property(bus, link, &error, &reply, "org.freedesktop.network1.Link", "BitRates");
645         if (r < 0) {
646                 bool quiet = sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY,
647                                                             BUS_ERROR_SPEED_METER_INACTIVE);
648 
649                 return log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING,
650                                       r, "Failed to query link bit rates: %s", bus_error_message(&error, r));
651         }
652 
653         r = sd_bus_message_enter_container(reply, 'v', "(tt)");
654         if (r < 0)
655                 return bus_log_parse_error(r);
656 
657         r = sd_bus_message_read(reply, "(tt)", &link->tx_bitrate, &link->rx_bitrate);
658         if (r < 0)
659                 return bus_log_parse_error(r);
660 
661         r = sd_bus_message_exit_container(reply);
662         if (r < 0)
663                 return bus_log_parse_error(r);
664 
665         link->has_bitrates = link->tx_bitrate != UINT64_MAX && link->rx_bitrate != UINT64_MAX;
666 
667         return 0;
668 }
669 
acquire_ether_link_info(int * fd,LinkInfo * link)670 static void acquire_ether_link_info(int *fd, LinkInfo *link) {
671         if (ethtool_get_link_info(fd, link->name,
672                                   &link->autonegotiation,
673                                   &link->speed,
674                                   &link->duplex,
675                                   &link->port) >= 0)
676                 link->has_ethtool_link_info = true;
677 }
678 
acquire_wlan_link_info(LinkInfo * link)679 static void acquire_wlan_link_info(LinkInfo *link) {
680         _cleanup_(sd_netlink_unrefp) sd_netlink *genl = NULL;
681         const char *type = NULL;
682         int r, k = 0;
683 
684         if (link->sd_device)
685                 (void) sd_device_get_devtype(link->sd_device, &type);
686         if (!streq_ptr(type, "wlan"))
687                 return;
688 
689         r = sd_genl_socket_open(&genl);
690         if (r < 0) {
691                 log_debug_errno(r, "Failed to open generic netlink socket: %m");
692                 return;
693         }
694 
695         (void) sd_netlink_inc_rcvbuf(genl, RCVBUF_SIZE);
696 
697         r = wifi_get_interface(genl, link->ifindex, &link->wlan_iftype, &link->ssid);
698         if (r < 0)
699                 log_debug_errno(r, "%s: failed to query ssid: %m", link->name);
700 
701         if (link->wlan_iftype == NL80211_IFTYPE_STATION) {
702                 k = wifi_get_station(genl, link->ifindex, &link->bssid);
703                 if (k < 0)
704                         log_debug_errno(k, "%s: failed to query bssid: %m", link->name);
705         }
706 
707         link->has_wlan_link_info = r > 0 || k > 0;
708 }
709 
acquire_link_info(sd_bus * bus,sd_netlink * rtnl,char ** patterns,LinkInfo ** ret)710 static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
711         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
712         _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
713         _cleanup_close_ int fd = -1;
714         size_t c = 0;
715         int r;
716 
717         assert(rtnl);
718         assert(ret);
719 
720         r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
721         if (r < 0)
722                 return rtnl_log_create_error(r);
723 
724         r = sd_netlink_message_request_dump(req, true);
725         if (r < 0)
726                 return rtnl_log_create_error(r);
727 
728         r = sd_netlink_call(rtnl, req, 0, &reply);
729         if (r < 0)
730                 return log_error_errno(r, "Failed to enumerate links: %m");
731 
732         _cleanup_free_ bool *matched_patterns = NULL;
733         if (patterns) {
734                 matched_patterns = new0(bool, strv_length(patterns));
735                 if (!matched_patterns)
736                         return log_oom();
737         }
738 
739         for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) {
740                 if (!GREEDY_REALLOC0(links, c + 2)) /* We keep one trailing one as marker */
741                         return -ENOMEM;
742 
743                 r = decode_link(i, links + c, patterns, matched_patterns);
744                 if (r < 0)
745                         return r;
746                 if (r == 0)
747                         continue;
748 
749                 links[c].needs_freeing = true;
750 
751                 (void) sd_device_new_from_ifindex(&links[c].sd_device, links[c].ifindex);
752 
753                 acquire_ether_link_info(&fd, &links[c]);
754                 acquire_wlan_link_info(&links[c]);
755 
756                 c++;
757         }
758 
759         /* Look if we matched all our arguments that are not globs. It
760          * is OK for a glob to match nothing, but not for an exact argument. */
761         for (size_t pos = 0; pos < strv_length(patterns); pos++) {
762                 if (matched_patterns[pos])
763                         continue;
764 
765                 if (string_is_glob(patterns[pos]))
766                         log_debug("Pattern \"%s\" doesn't match any interface, ignoring.",
767                                   patterns[pos]);
768                 else
769                         return log_error_errno(SYNTHETIC_ERRNO(ENODEV),
770                                                "Interface \"%s\" not found.", patterns[pos]);
771         }
772 
773         typesafe_qsort(links, c, link_info_compare);
774 
775         if (bus)
776                 for (size_t j = 0; j < c; j++)
777                         (void) acquire_link_bitrates(bus, links + j);
778 
779         *ret = TAKE_PTR(links);
780 
781         if (patterns && c == 0)
782                 log_warning("No interfaces matched.");
783 
784         return (int) c;
785 }
786 
list_links(int argc,char * argv[],void * userdata)787 static int list_links(int argc, char *argv[], void *userdata) {
788         sd_bus *bus = ASSERT_PTR(userdata);
789         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
790         _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
791         _cleanup_(table_unrefp) Table *table = NULL;
792         TableCell *cell;
793         int c, r;
794 
795         if (arg_json_format_flags != JSON_FORMAT_OFF) {
796                 if (arg_all || argc <= 1)
797                         return dump_manager_description(bus);
798                 else
799                         return dump_link_description(bus, strv_skip(argv, 1));
800         }
801 
802         r = sd_netlink_open(&rtnl);
803         if (r < 0)
804                 return log_error_errno(r, "Failed to connect to netlink: %m");
805 
806         c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
807         if (c < 0)
808                 return c;
809 
810         pager_open(arg_pager_flags);
811 
812         table = table_new("idx", "link", "type", "operational", "setup");
813         if (!table)
814                 return log_oom();
815 
816         if (arg_full)
817                 table_set_width(table, 0);
818 
819         table_set_header(table, arg_legend);
820         if (table_set_empty_string(table, "n/a") < 0)
821                 return log_oom();
822 
823         assert_se(cell = table_get_cell(table, 0, 0));
824         (void) table_set_minimum_width(table, cell, 3);
825         (void) table_set_weight(table, cell, 0);
826         (void) table_set_ellipsize_percent(table, cell, 100);
827         (void) table_set_align_percent(table, cell, 100);
828 
829         assert_se(cell = table_get_cell(table, 0, 1));
830         (void) table_set_ellipsize_percent(table, cell, 100);
831 
832         for (int i = 0; i < c; i++) {
833                 _cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
834                 const char *on_color_operational, *on_color_setup;
835                 _cleanup_free_ char *t = NULL;
836 
837                 (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
838                 operational_state_to_color(links[i].name, operational_state, &on_color_operational, NULL);
839 
840                 r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
841                 if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
842                         setup_state = strdup("unmanaged");
843                 setup_state_to_color(setup_state, &on_color_setup, NULL);
844 
845                 r = net_get_type_string(links[i].sd_device, links[i].iftype, &t);
846                 if (r == -ENOMEM)
847                         return log_oom();
848 
849                 r = table_add_many(table,
850                                    TABLE_INT, links[i].ifindex,
851                                    TABLE_STRING, links[i].name,
852                                    TABLE_STRING, t,
853                                    TABLE_STRING, operational_state,
854                                    TABLE_SET_COLOR, on_color_operational,
855                                    TABLE_STRING, setup_state,
856                                    TABLE_SET_COLOR, on_color_setup);
857                 if (r < 0)
858                         return table_log_add_error(r);
859         }
860 
861         r = table_print(table, NULL);
862         if (r < 0)
863                 return table_log_print_error(r);
864 
865         if (arg_legend)
866                 printf("\n%i links listed.\n", c);
867 
868         return 0;
869 }
870 
871 /* IEEE Organizationally Unique Identifier vendor string */
ieee_oui(sd_hwdb * hwdb,const struct ether_addr * mac,char ** ret)872 static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) {
873         const char *description;
874         char modalias[STRLEN("OUI:XXYYXXYYXXYY") + 1], *desc;
875         int r;
876 
877         assert(ret);
878 
879         if (!hwdb)
880                 return -EINVAL;
881 
882         if (!mac)
883                 return -EINVAL;
884 
885         /* skip commonly misused 00:00:00 (Xerox) prefix */
886         if (memcmp(mac, "\0\0\0", 3) == 0)
887                 return -EINVAL;
888 
889         xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR,
890                  ETHER_ADDR_FORMAT_VAL(*mac));
891 
892         r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description);
893         if (r < 0)
894                 return r;
895 
896         desc = strdup(description);
897         if (!desc)
898                 return -ENOMEM;
899 
900         *ret = desc;
901 
902         return 0;
903 }
904 
get_gateway_description(sd_netlink * rtnl,sd_hwdb * hwdb,int ifindex,int family,union in_addr_union * gateway,char ** gateway_description)905 static int get_gateway_description(
906                 sd_netlink *rtnl,
907                 sd_hwdb *hwdb,
908                 int ifindex,
909                 int family,
910                 union in_addr_union *gateway,
911                 char **gateway_description) {
912         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
913         int r;
914 
915         assert(rtnl);
916         assert(ifindex >= 0);
917         assert(IN_SET(family, AF_INET, AF_INET6));
918         assert(gateway);
919         assert(gateway_description);
920 
921         r = sd_rtnl_message_new_neigh(rtnl, &req, RTM_GETNEIGH, ifindex, family);
922         if (r < 0)
923                 return r;
924 
925         r = sd_netlink_message_request_dump(req, true);
926         if (r < 0)
927                 return r;
928 
929         r = sd_netlink_call(rtnl, req, 0, &reply);
930         if (r < 0)
931                 return r;
932 
933         for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
934                 union in_addr_union gw = IN_ADDR_NULL;
935                 struct ether_addr mac = ETHER_ADDR_NULL;
936                 uint16_t type;
937                 int ifi, fam;
938 
939                 r = sd_netlink_message_get_errno(m);
940                 if (r < 0) {
941                         log_error_errno(r, "got error: %m");
942                         continue;
943                 }
944 
945                 r = sd_netlink_message_get_type(m, &type);
946                 if (r < 0) {
947                         log_error_errno(r, "could not get type: %m");
948                         continue;
949                 }
950 
951                 if (type != RTM_NEWNEIGH) {
952                         log_error("type is not RTM_NEWNEIGH");
953                         continue;
954                 }
955 
956                 r = sd_rtnl_message_neigh_get_family(m, &fam);
957                 if (r < 0) {
958                         log_error_errno(r, "could not get family: %m");
959                         continue;
960                 }
961 
962                 if (fam != family) {
963                         log_error("family is not correct");
964                         continue;
965                 }
966 
967                 r = sd_rtnl_message_neigh_get_ifindex(m, &ifi);
968                 if (r < 0) {
969                         log_error_errno(r, "could not get ifindex: %m");
970                         continue;
971                 }
972 
973                 if (ifindex > 0 && ifi != ifindex)
974                         continue;
975 
976                 switch (fam) {
977                 case AF_INET:
978                         r = sd_netlink_message_read_in_addr(m, NDA_DST, &gw.in);
979                         if (r < 0)
980                                 continue;
981 
982                         break;
983                 case AF_INET6:
984                         r = sd_netlink_message_read_in6_addr(m, NDA_DST, &gw.in6);
985                         if (r < 0)
986                                 continue;
987 
988                         break;
989                 default:
990                         continue;
991                 }
992 
993                 if (!in_addr_equal(fam, &gw, gateway))
994                         continue;
995 
996                 r = sd_netlink_message_read(m, NDA_LLADDR, sizeof(mac), &mac);
997                 if (r < 0)
998                         continue;
999 
1000                 r = ieee_oui(hwdb, &mac, gateway_description);
1001                 if (r < 0)
1002                         continue;
1003 
1004                 return 0;
1005         }
1006 
1007         return -ENODATA;
1008 }
1009 
dump_list(Table * table,const char * prefix,char * const * l)1010 static int dump_list(Table *table, const char *prefix, char * const *l) {
1011         int r;
1012 
1013         if (strv_isempty(l))
1014                 return 0;
1015 
1016         r = table_add_many(table,
1017                            TABLE_EMPTY,
1018                            TABLE_STRING, prefix,
1019                            TABLE_STRV, l);
1020         if (r < 0)
1021                 return table_log_add_error(r);
1022 
1023         return 0;
1024 }
1025 
dump_gateways(sd_netlink * rtnl,sd_hwdb * hwdb,Table * table,int ifindex)1026 static int dump_gateways(
1027                 sd_netlink *rtnl,
1028                 sd_hwdb *hwdb,
1029                 Table *table,
1030                 int ifindex) {
1031         _cleanup_free_ struct local_address *local = NULL;
1032         _cleanup_strv_free_ char **buf = NULL;
1033         int r, n;
1034 
1035         assert(rtnl);
1036         assert(table);
1037 
1038         n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
1039         if (n <= 0)
1040                 return n;
1041 
1042         for (int i = 0; i < n; i++) {
1043                 _cleanup_free_ char *gateway = NULL, *description = NULL;
1044 
1045                 r = in_addr_to_string(local[i].family, &local[i].address, &gateway);
1046                 if (r < 0)
1047                         return log_oom();
1048 
1049                 r = get_gateway_description(rtnl, hwdb, local[i].ifindex, local[i].family, &local[i].address, &description);
1050                 if (r < 0)
1051                         log_debug_errno(r, "Could not get description of gateway, ignoring: %m");
1052 
1053                 if (description) {
1054                         if (!strextend(&gateway, " (", description, ")"))
1055                                 return log_oom();
1056                 }
1057 
1058                 /* Show interface name for the entry if we show entries for all interfaces */
1059                 r = strv_extendf(&buf, "%s%s%s",
1060                                  gateway,
1061                                  ifindex <= 0 ? " on " : "",
1062                                  ifindex <= 0 ? FORMAT_IFNAME_FULL(local[i].ifindex, FORMAT_IFNAME_IFINDEX_WITH_PERCENT) : "");
1063                 if (r < 0)
1064                         return log_oom();
1065         }
1066 
1067         return dump_list(table, "Gateway:", buf);
1068 }
1069 
dump_addresses(sd_netlink * rtnl,sd_dhcp_lease * lease,Table * table,int ifindex)1070 static int dump_addresses(
1071                 sd_netlink *rtnl,
1072                 sd_dhcp_lease *lease,
1073                 Table *table,
1074                 int ifindex) {
1075 
1076         _cleanup_free_ struct local_address *local = NULL;
1077         _cleanup_strv_free_ char **buf = NULL;
1078         struct in_addr dhcp4_address = {};
1079         int r, n;
1080 
1081         assert(rtnl);
1082         assert(table);
1083 
1084         n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
1085         if (n <= 0)
1086                 return n;
1087 
1088         if (lease)
1089                 (void) sd_dhcp_lease_get_address(lease, &dhcp4_address);
1090 
1091         for (int i = 0; i < n; i++) {
1092                 _cleanup_free_ char *pretty = NULL;
1093 
1094                 r = in_addr_to_string(local[i].family, &local[i].address, &pretty);
1095                 if (r < 0)
1096                         return r;
1097 
1098                 if (local[i].family == AF_INET && in4_addr_equal(&local[i].address.in, &dhcp4_address)) {
1099                         struct in_addr server_address;
1100                         char *p, s[INET_ADDRSTRLEN];
1101 
1102                         r = sd_dhcp_lease_get_server_identifier(lease, &server_address);
1103                         if (r >= 0 && inet_ntop(AF_INET, &server_address, s, sizeof(s)))
1104                                 p = strjoin(pretty, " (DHCP4 via ", s, ")");
1105                         else
1106                                 p = strjoin(pretty, " (DHCP4)");
1107                         if (!p)
1108                                 return log_oom();
1109 
1110                         free_and_replace(pretty, p);
1111                 }
1112 
1113                 r = strv_extendf(&buf, "%s%s%s",
1114                                  pretty,
1115                                  ifindex <= 0 ? " on " : "",
1116                                  ifindex <= 0 ? FORMAT_IFNAME_FULL(local[i].ifindex, FORMAT_IFNAME_IFINDEX_WITH_PERCENT) : "");
1117                 if (r < 0)
1118                         return log_oom();
1119         }
1120 
1121         return dump_list(table, "Address:", buf);
1122 }
1123 
dump_address_labels(sd_netlink * rtnl)1124 static int dump_address_labels(sd_netlink *rtnl) {
1125         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
1126         _cleanup_(table_unrefp) Table *table = NULL;
1127         TableCell *cell;
1128         int r;
1129 
1130         assert(rtnl);
1131 
1132         r = sd_rtnl_message_new_addrlabel(rtnl, &req, RTM_GETADDRLABEL, 0, AF_INET6);
1133         if (r < 0)
1134                 return log_error_errno(r, "Could not allocate RTM_GETADDRLABEL message: %m");
1135 
1136         r = sd_netlink_message_request_dump(req, true);
1137         if (r < 0)
1138                 return r;
1139 
1140         r = sd_netlink_call(rtnl, req, 0, &reply);
1141         if (r < 0)
1142                 return r;
1143 
1144         table = table_new("label", "prefix/prefixlen");
1145         if (!table)
1146                 return log_oom();
1147 
1148         if (arg_full)
1149                 table_set_width(table, 0);
1150 
1151         r = table_set_sort(table, (size_t) 0);
1152         if (r < 0)
1153                 return r;
1154 
1155         assert_se(cell = table_get_cell(table, 0, 0));
1156         (void) table_set_align_percent(table, cell, 100);
1157         (void) table_set_ellipsize_percent(table, cell, 100);
1158 
1159         assert_se(cell = table_get_cell(table, 0, 1));
1160         (void) table_set_align_percent(table, cell, 100);
1161 
1162         for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) {
1163                 _cleanup_free_ char *pretty = NULL;
1164                 union in_addr_union prefix = IN_ADDR_NULL;
1165                 uint8_t prefixlen;
1166                 uint32_t label;
1167 
1168                 r = sd_netlink_message_get_errno(m);
1169                 if (r < 0) {
1170                         log_error_errno(r, "got error: %m");
1171                         continue;
1172                 }
1173 
1174                 r = sd_netlink_message_read_u32(m, IFAL_LABEL, &label);
1175                 if (r < 0 && r != -ENODATA) {
1176                         log_error_errno(r, "Could not read IFAL_LABEL, ignoring: %m");
1177                         continue;
1178                 }
1179 
1180                 r = sd_netlink_message_read_in6_addr(m, IFAL_ADDRESS, &prefix.in6);
1181                 if (r < 0)
1182                         continue;
1183 
1184                 r = in_addr_to_string(AF_INET6, &prefix, &pretty);
1185                 if (r < 0)
1186                         continue;
1187 
1188                 r = sd_rtnl_message_addrlabel_get_prefixlen(m, &prefixlen);
1189                 if (r < 0)
1190                         continue;
1191 
1192                 r = table_add_cell(table, NULL, TABLE_UINT32, &label);
1193                 if (r < 0)
1194                         return table_log_add_error(r);
1195 
1196                 r = table_add_cell_stringf(table, NULL, "%s/%u", pretty, prefixlen);
1197                 if (r < 0)
1198                         return table_log_add_error(r);
1199         }
1200 
1201         r = table_print(table, NULL);
1202         if (r < 0)
1203                 return table_log_print_error(r);
1204 
1205         return 0;
1206 }
1207 
list_address_labels(int argc,char * argv[],void * userdata)1208 static int list_address_labels(int argc, char *argv[], void *userdata) {
1209         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
1210         int r;
1211 
1212         r = sd_netlink_open(&rtnl);
1213         if (r < 0)
1214                 return log_error_errno(r, "Failed to connect to netlink: %m");
1215 
1216         dump_address_labels(rtnl);
1217 
1218         return 0;
1219 }
1220 
open_lldp_neighbors(int ifindex,FILE ** ret)1221 static int open_lldp_neighbors(int ifindex, FILE **ret) {
1222         char p[STRLEN("/run/systemd/netif/lldp/") + DECIMAL_STR_MAX(int)];
1223         FILE *f;
1224 
1225         xsprintf(p, "/run/systemd/netif/lldp/%i", ifindex);
1226         f = fopen(p, "re");
1227         if (!f)
1228                 return -errno;
1229 
1230         *ret = f;
1231         return 0;
1232 }
1233 
next_lldp_neighbor(FILE * f,sd_lldp_neighbor ** ret)1234 static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) {
1235         _cleanup_free_ void *raw = NULL;
1236         size_t l;
1237         le64_t u;
1238         int r;
1239 
1240         assert(f);
1241         assert(ret);
1242 
1243         l = fread(&u, 1, sizeof(u), f);
1244         if (l == 0 && feof(f))
1245                 return 0;
1246         if (l != sizeof(u))
1247                 return -EBADMSG;
1248 
1249         /* each LLDP packet is at most MTU size, but let's allow up to 4KiB just in case */
1250         if (le64toh(u) >= 4096)
1251                 return -EBADMSG;
1252 
1253         raw = new(uint8_t, le64toh(u));
1254         if (!raw)
1255                 return -ENOMEM;
1256 
1257         if (fread(raw, 1, le64toh(u), f) != le64toh(u))
1258                 return -EBADMSG;
1259 
1260         r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u));
1261         if (r < 0)
1262                 return r;
1263 
1264         return 1;
1265 }
1266 
dump_lldp_neighbors(Table * table,const char * prefix,int ifindex)1267 static int dump_lldp_neighbors(Table *table, const char *prefix, int ifindex) {
1268         _cleanup_strv_free_ char **buf = NULL;
1269         _cleanup_fclose_ FILE *f = NULL;
1270         int r;
1271 
1272         assert(table);
1273         assert(prefix);
1274         assert(ifindex > 0);
1275 
1276         r = open_lldp_neighbors(ifindex, &f);
1277         if (r == -ENOENT)
1278                 return 0;
1279         if (r < 0)
1280                 return r;
1281 
1282         for (;;) {
1283                 const char *system_name = NULL, *port_id = NULL, *port_description = NULL;
1284                 _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
1285 
1286                 r = next_lldp_neighbor(f, &n);
1287                 if (r < 0)
1288                         return r;
1289                 if (r == 0)
1290                         break;
1291 
1292                 (void) sd_lldp_neighbor_get_system_name(n, &system_name);
1293                 (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
1294                 (void) sd_lldp_neighbor_get_port_description(n, &port_description);
1295 
1296                 r = strv_extendf(&buf, "%s on port %s%s%s%s",
1297                                  strna(system_name),
1298                                  strna(port_id),
1299                                  isempty(port_description) ? "" : " (",
1300                                  strempty(port_description),
1301                                  isempty(port_description) ? "" : ")");
1302                 if (r < 0)
1303                         return log_oom();
1304         }
1305 
1306         return dump_list(table, prefix, buf);
1307 }
1308 
dump_dhcp_leases(Table * table,const char * prefix,sd_bus * bus,const LinkInfo * link)1309 static int dump_dhcp_leases(Table *table, const char *prefix, sd_bus *bus, const LinkInfo *link) {
1310         _cleanup_strv_free_ char **buf = NULL;
1311         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1312         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1313         int r;
1314 
1315         r = link_get_property(bus, link, &error, &reply, "org.freedesktop.network1.DHCPServer", "Leases");
1316         if (r < 0) {
1317                 bool quiet = sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY);
1318 
1319                 log_full_errno(quiet ? LOG_DEBUG : LOG_WARNING,
1320                                r, "Failed to query link DHCP leases: %s", bus_error_message(&error, r));
1321                 return 0;
1322         }
1323 
1324         r = sd_bus_message_enter_container(reply, 'v', "a(uayayayayt)");
1325         if (r < 0)
1326                 return bus_log_parse_error(r);
1327 
1328         r = sd_bus_message_enter_container(reply, 'a', "(uayayayayt)");
1329         if (r < 0)
1330                 return bus_log_parse_error(r);
1331 
1332         while ((r = sd_bus_message_enter_container(reply, 'r', "uayayayayt")) > 0) {
1333                 _cleanup_free_ char *id = NULL, *ip = NULL;
1334                 const void *client_id, *addr, *gtw, *hwaddr;
1335                 size_t client_id_sz, sz;
1336                 uint64_t expiration;
1337                 uint32_t family;
1338 
1339                 r = sd_bus_message_read(reply, "u", &family);
1340                 if (r < 0)
1341                         return bus_log_parse_error(r);
1342 
1343                 r = sd_bus_message_read_array(reply, 'y', &client_id, &client_id_sz);
1344                 if (r < 0)
1345                         return bus_log_parse_error(r);
1346 
1347                 r = sd_bus_message_read_array(reply, 'y', &addr, &sz);
1348                 if (r < 0 || sz != 4)
1349                         return bus_log_parse_error(r);
1350 
1351                 r = sd_bus_message_read_array(reply, 'y', &gtw, &sz);
1352                 if (r < 0 || sz != 4)
1353                         return bus_log_parse_error(r);
1354 
1355                 r = sd_bus_message_read_array(reply, 'y', &hwaddr, &sz);
1356                 if (r < 0)
1357                         return bus_log_parse_error(r);
1358 
1359                 r = sd_bus_message_read_basic(reply, 't', &expiration);
1360                 if (r < 0)
1361                         return bus_log_parse_error(r);
1362 
1363                 r = sd_dhcp_client_id_to_string(client_id, client_id_sz, &id);
1364                 if (r < 0)
1365                         return bus_log_parse_error(r);
1366 
1367                 r = in_addr_to_string(family, addr, &ip);
1368                 if (r < 0)
1369                         return bus_log_parse_error(r);
1370 
1371                 r = strv_extendf(&buf, "%s (to %s)", ip, id);
1372                 if (r < 0)
1373                         return log_oom();
1374 
1375                 r = sd_bus_message_exit_container(reply);
1376                 if (r < 0)
1377                         return bus_log_parse_error(r);
1378         }
1379         if (r < 0)
1380                 return bus_log_parse_error(r);
1381 
1382         r = sd_bus_message_exit_container(reply);
1383         if (r < 0)
1384                 return bus_log_parse_error(r);
1385 
1386         r = sd_bus_message_exit_container(reply);
1387         if (r < 0)
1388                 return bus_log_parse_error(r);
1389 
1390         if (strv_isempty(buf)) {
1391                 r = strv_extendf(&buf, "none");
1392                 if (r < 0)
1393                         return log_oom();
1394         }
1395 
1396         return dump_list(table, prefix, buf);
1397 }
1398 
dump_ifindexes(Table * table,const char * prefix,const int * ifindexes)1399 static int dump_ifindexes(Table *table, const char *prefix, const int *ifindexes) {
1400         int r;
1401 
1402         assert(prefix);
1403 
1404         if (!ifindexes || ifindexes[0] <= 0)
1405                 return 0;
1406 
1407         for (unsigned c = 0; ifindexes[c] > 0; c++) {
1408                 r = table_add_many(table,
1409                                    TABLE_EMPTY,
1410                                    TABLE_STRING, c == 0 ? prefix : "",
1411                                    TABLE_IFINDEX, ifindexes[c]);
1412                 if (r < 0)
1413                         return table_log_add_error(r);
1414         }
1415 
1416         return 0;
1417 }
1418 
1419 #define DUMP_STATS_ONE(name, val_name)                                  \
1420         r = table_add_many(table,                                       \
1421                            TABLE_EMPTY,                                 \
1422                            TABLE_STRING, name ":");                     \
1423         if (r < 0)                                                      \
1424                 return table_log_add_error(r);                                               \
1425         r = table_add_cell(table, NULL,                                 \
1426                            info->has_stats64 ? TABLE_UINT64 : TABLE_UINT32, \
1427                            info->has_stats64 ? (void*) &info->stats64.val_name : (void*) &info->stats.val_name); \
1428         if (r < 0)                                                      \
1429                 return table_log_add_error(r);
1430 
dump_statistics(Table * table,const LinkInfo * info)1431 static int dump_statistics(Table *table, const LinkInfo *info) {
1432         int r;
1433 
1434         if (!arg_stats)
1435                 return 0;
1436 
1437         if (!info->has_stats64 && !info->has_stats)
1438                 return 0;
1439 
1440         DUMP_STATS_ONE("Rx Packets", rx_packets);
1441         DUMP_STATS_ONE("Tx Packets", tx_packets);
1442         DUMP_STATS_ONE("Rx Bytes", rx_bytes);
1443         DUMP_STATS_ONE("Tx Bytes", tx_bytes);
1444         DUMP_STATS_ONE("Rx Errors", rx_errors);
1445         DUMP_STATS_ONE("Tx Errors", tx_errors);
1446         DUMP_STATS_ONE("Rx Dropped", rx_dropped);
1447         DUMP_STATS_ONE("Tx Dropped", tx_dropped);
1448         DUMP_STATS_ONE("Multicast Packets", multicast);
1449         DUMP_STATS_ONE("Collisions", collisions);
1450 
1451         return 0;
1452 }
1453 
dump_hw_address(Table * table,sd_hwdb * hwdb,const char * field,const struct hw_addr_data * addr)1454 static int dump_hw_address(Table *table, sd_hwdb *hwdb, const char *field, const struct hw_addr_data *addr) {
1455         _cleanup_free_ char *description = NULL;
1456         int r;
1457 
1458         assert(table);
1459         assert(field);
1460         assert(addr);
1461 
1462         if (addr->length == ETH_ALEN)
1463                 (void) ieee_oui(hwdb, &addr->ether, &description);
1464 
1465         r = table_add_many(table,
1466                            TABLE_EMPTY,
1467                            TABLE_STRING, field);
1468         if (r < 0)
1469                 return table_log_add_error(r);
1470 
1471         r = table_add_cell_stringf(table, NULL, "%s%s%s%s",
1472                                    HW_ADDR_TO_STR(addr),
1473                                    description ? " (" : "",
1474                                    strempty(description),
1475                                    description ? ")" : "");
1476         if (r < 0)
1477                 return table_log_add_error(r);
1478 
1479         return 0;
1480 }
1481 
get_output_flags(void)1482 static OutputFlags get_output_flags(void) {
1483         return
1484                 arg_all * OUTPUT_SHOW_ALL |
1485                 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1486                 colors_enabled() * OUTPUT_COLOR;
1487 }
1488 
show_logs(const LinkInfo * info)1489 static int show_logs(const LinkInfo *info) {
1490         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
1491         int r;
1492 
1493         if (arg_lines == 0)
1494                 return 0;
1495 
1496         r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
1497         if (r < 0)
1498                 return log_error_errno(r, "Failed to open journal: %m");
1499 
1500         r = add_match_this_boot(j, NULL);
1501         if (r < 0)
1502                 return log_error_errno(r, "Failed to add boot matches: %m");
1503 
1504         if (info) {
1505                 char m1[STRLEN("_KERNEL_DEVICE=n") + DECIMAL_STR_MAX(int)];
1506                 const char *m2, *m3;
1507 
1508                 /* kernel */
1509                 xsprintf(m1, "_KERNEL_DEVICE=n%i", info->ifindex);
1510                 /* networkd */
1511                 m2 = strjoina("INTERFACE=", info->name);
1512                 /* udevd */
1513                 m3 = strjoina("DEVICE=", info->name);
1514 
1515                 (void)(
1516                        (r = sd_journal_add_match(j, m1, 0)) ||
1517                        (r = sd_journal_add_disjunction(j)) ||
1518                        (r = sd_journal_add_match(j, m2, 0)) ||
1519                        (r = sd_journal_add_disjunction(j)) ||
1520                        (r = sd_journal_add_match(j, m3, 0))
1521                 );
1522                 if (r < 0)
1523                         return log_error_errno(r, "Failed to add link matches: %m");
1524         } else {
1525                 r = add_matches_for_unit(j, "systemd-networkd.service");
1526                 if (r < 0)
1527                         return log_error_errno(r, "Failed to add unit matches: %m");
1528 
1529                 r = add_matches_for_unit(j, "systemd-networkd-wait-online.service");
1530                 if (r < 0)
1531                         return log_error_errno(r, "Failed to add unit matches: %m");
1532         }
1533 
1534         return show_journal(
1535                         stdout,
1536                         j,
1537                         OUTPUT_SHORT,
1538                         0,
1539                         0,
1540                         arg_lines,
1541                         get_output_flags() | OUTPUT_BEGIN_NEWLINE,
1542                         NULL);
1543 }
1544 
link_status_one(sd_bus * bus,sd_netlink * rtnl,sd_hwdb * hwdb,const LinkInfo * info)1545 static int link_status_one(
1546                 sd_bus *bus,
1547                 sd_netlink *rtnl,
1548                 sd_hwdb *hwdb,
1549                 const LinkInfo *info) {
1550 
1551         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL;
1552         _cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL,
1553                 *setup_state = NULL, *operational_state = NULL, *online_state = NULL, *activation_policy = NULL;
1554         const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL,
1555                 *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup, *on_color_online;
1556         _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
1557         _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
1558         _cleanup_(table_unrefp) Table *table = NULL;
1559         TableCell *cell;
1560         int r;
1561 
1562         assert(rtnl);
1563         assert(info);
1564 
1565         (void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
1566         operational_state_to_color(info->name, operational_state, &on_color_operational, &off_color_operational);
1567 
1568         (void) sd_network_link_get_online_state(info->ifindex, &online_state);
1569         online_state_to_color(online_state, &on_color_online, NULL);
1570 
1571         r = sd_network_link_get_setup_state(info->ifindex, &setup_state);
1572         if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
1573                 setup_state = strdup("unmanaged");
1574         setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
1575 
1576         (void) sd_network_link_get_dns(info->ifindex, &dns);
1577         (void) sd_network_link_get_search_domains(info->ifindex, &search_domains);
1578         (void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
1579         (void) sd_network_link_get_ntp(info->ifindex, &ntp);
1580         (void) sd_network_link_get_sip(info->ifindex, &sip);
1581 
1582         if (info->sd_device) {
1583                 (void) sd_device_get_property_value(info->sd_device, "ID_NET_LINK_FILE", &link);
1584                 (void) sd_device_get_property_value(info->sd_device, "ID_NET_DRIVER", &driver);
1585                 (void) sd_device_get_property_value(info->sd_device, "ID_PATH", &path);
1586 
1587                 if (sd_device_get_property_value(info->sd_device, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
1588                         (void) sd_device_get_property_value(info->sd_device, "ID_VENDOR", &vendor);
1589 
1590                 if (sd_device_get_property_value(info->sd_device, "ID_MODEL_FROM_DATABASE", &model) < 0)
1591                         (void) sd_device_get_property_value(info->sd_device, "ID_MODEL", &model);
1592         }
1593 
1594         r = net_get_type_string(info->sd_device, info->iftype, &t);
1595         if (r == -ENOMEM)
1596                 return log_oom();
1597 
1598         (void) sd_network_link_get_network_file(info->ifindex, &network);
1599 
1600         (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
1601         (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
1602 
1603         char lease_file[STRLEN("/run/systemd/netif/leases/") + DECIMAL_STR_MAX(int)];
1604         xsprintf(lease_file, "/run/systemd/netif/leases/%i", info->ifindex);
1605 
1606         (void) dhcp_lease_load(&lease, lease_file);
1607 
1608         table = table_new("dot", "key", "value");
1609         if (!table)
1610                 return log_oom();
1611 
1612         if (arg_full)
1613                 table_set_width(table, 0);
1614 
1615         assert_se(cell = table_get_cell(table, 0, 0));
1616         (void) table_set_ellipsize_percent(table, cell, 100);
1617 
1618         assert_se(cell = table_get_cell(table, 0, 1));
1619         (void) table_set_ellipsize_percent(table, cell, 100);
1620 
1621         table_set_header(table, false);
1622 
1623         r = table_add_many(table,
1624                            TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
1625                            TABLE_SET_COLOR, on_color_operational);
1626         if (r < 0)
1627                 return table_log_add_error(r);
1628         r = table_add_cell_stringf(table, &cell, "%i: %s", info->ifindex, info->name);
1629         if (r < 0)
1630                 return table_log_add_error(r);
1631         (void) table_set_align_percent(table, cell, 0);
1632 
1633         r = table_add_many(table,
1634                            TABLE_EMPTY,
1635                            TABLE_EMPTY,
1636                            TABLE_STRING, "Link File:",
1637                            TABLE_SET_ALIGN_PERCENT, 100,
1638                            TABLE_STRING, strna(link),
1639                            TABLE_EMPTY,
1640                            TABLE_STRING, "Network File:",
1641                            TABLE_STRING, strna(network),
1642                            TABLE_EMPTY,
1643                            TABLE_STRING, "Type:",
1644                            TABLE_STRING, strna(t),
1645                            TABLE_EMPTY,
1646                            TABLE_STRING, "Kind:",
1647                            TABLE_STRING, strna(info->netdev_kind),
1648                            TABLE_EMPTY,
1649                            TABLE_STRING, "State:");
1650         if (r < 0)
1651                 return table_log_add_error(r);
1652         r = table_add_cell_stringf(table, NULL, "%s%s%s (%s%s%s)",
1653                                    on_color_operational, strna(operational_state), off_color_operational,
1654                                    on_color_setup, strna(setup_state), off_color_setup);
1655         if (r < 0)
1656                 return table_log_add_error(r);
1657 
1658         r = table_add_many(table,
1659                            TABLE_EMPTY,
1660                            TABLE_STRING, "Online state:",
1661                            TABLE_STRING, online_state ?: "unknown",
1662                            TABLE_SET_COLOR, on_color_online);
1663         if (r < 0)
1664                 return table_log_add_error(r);
1665 
1666         strv_sort(info->alternative_names);
1667         r = dump_list(table, "Alternative Names:", info->alternative_names);
1668         if (r < 0)
1669                 return r;
1670 
1671         if (path) {
1672                 r = table_add_many(table,
1673                                    TABLE_EMPTY,
1674                                    TABLE_STRING, "Path:",
1675                                    TABLE_STRING, path);
1676                 if (r < 0)
1677                         return table_log_add_error(r);
1678         }
1679         if (driver) {
1680                 r = table_add_many(table,
1681                                    TABLE_EMPTY,
1682                                    TABLE_STRING, "Driver:",
1683                                    TABLE_STRING, driver);
1684                 if (r < 0)
1685                         return table_log_add_error(r);
1686         }
1687         if (vendor) {
1688                 r = table_add_many(table,
1689                                    TABLE_EMPTY,
1690                                    TABLE_STRING, "Vendor:",
1691                                    TABLE_STRING, vendor);
1692                 if (r < 0)
1693                         return table_log_add_error(r);
1694         }
1695         if (model) {
1696                 r = table_add_many(table,
1697                                    TABLE_EMPTY,
1698                                    TABLE_STRING, "Model:",
1699                                    TABLE_STRING, model);
1700                 if (r < 0)
1701                         return table_log_add_error(r);
1702         }
1703 
1704         if (info->has_hw_address) {
1705                 r = dump_hw_address(table, hwdb, "Hardware Address:", &info->hw_address);
1706                 if (r < 0)
1707                         return r;
1708         }
1709 
1710         if (info->has_permanent_hw_address) {
1711                 r = dump_hw_address(table, hwdb, "Permanent Hardware Address:", &info->permanent_hw_address);
1712                 if (r < 0)
1713                         return r;
1714         }
1715 
1716         if (info->mtu > 0) {
1717                 char min_str[DECIMAL_STR_MAX(uint32_t)], max_str[DECIMAL_STR_MAX(uint32_t)];
1718 
1719                 xsprintf(min_str, "%" PRIu32, info->min_mtu);
1720                 xsprintf(max_str, "%" PRIu32, info->max_mtu);
1721 
1722                 r = table_add_many(table,
1723                                    TABLE_EMPTY,
1724                                    TABLE_STRING, "MTU:");
1725                 if (r < 0)
1726                         return table_log_add_error(r);
1727                 r = table_add_cell_stringf(table, NULL, "%" PRIu32 "%s%s%s%s%s%s%s",
1728                                            info->mtu,
1729                                            info->min_mtu > 0 || info->max_mtu > 0 ? " (" : "",
1730                                            info->min_mtu > 0 ? "min: " : "",
1731                                            info->min_mtu > 0 ? min_str : "",
1732                                            info->min_mtu > 0 && info->max_mtu > 0 ? ", " : "",
1733                                            info->max_mtu > 0 ? "max: " : "",
1734                                            info->max_mtu > 0 ? max_str : "",
1735                                            info->min_mtu > 0 || info->max_mtu > 0 ? ")" : "");
1736                 if (r < 0)
1737                         return table_log_add_error(r);
1738         }
1739 
1740         if (info->qdisc) {
1741                 r = table_add_many(table,
1742                                    TABLE_EMPTY,
1743                                    TABLE_STRING, "QDisc:",
1744                                    TABLE_STRING, info->qdisc);
1745                 if (r < 0)
1746                         return table_log_add_error(r);
1747         }
1748 
1749         if (info->master > 0) {
1750                 r = table_add_many(table,
1751                                    TABLE_EMPTY,
1752                                    TABLE_STRING, "Master:",
1753                                    TABLE_IFINDEX, info->master);
1754                 if (r < 0)
1755                         return table_log_add_error(r);
1756         }
1757 
1758         if (info->has_ipv6_address_generation_mode) {
1759                 static const struct {
1760                         const char *mode;
1761                 } mode_table[] = {
1762                         { "eui64" },
1763                         { "none" },
1764                         { "stable-privacy" },
1765                         { "random" },
1766                 };
1767 
1768                 r = table_add_many(table,
1769                                    TABLE_EMPTY,
1770                                    TABLE_STRING, "IPv6 Address Generation Mode:",
1771                                    TABLE_STRING, mode_table[info->addr_gen_mode]);
1772                 if (r < 0)
1773                         return table_log_add_error(r);
1774         }
1775 
1776         if (streq_ptr(info->netdev_kind, "bridge")) {
1777                 r = table_add_many(table,
1778                                    TABLE_EMPTY,
1779                                    TABLE_STRING, "Forward Delay:",
1780                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->forward_delay),
1781                                    TABLE_EMPTY,
1782                                    TABLE_STRING, "Hello Time:",
1783                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->hello_time),
1784                                    TABLE_EMPTY,
1785                                    TABLE_STRING, "Max Age:",
1786                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->max_age),
1787                                    TABLE_EMPTY,
1788                                    TABLE_STRING, "Ageing Time:",
1789                                    TABLE_TIMESPAN_MSEC, jiffies_to_usec(info->ageing_time),
1790                                    TABLE_EMPTY,
1791                                    TABLE_STRING, "Priority:",
1792                                    TABLE_UINT16, info->priority,
1793                                    TABLE_EMPTY,
1794                                    TABLE_STRING, "STP:",
1795                                    TABLE_BOOLEAN, info->stp_state > 0,
1796                                    TABLE_EMPTY,
1797                                    TABLE_STRING, "Multicast IGMP Version:",
1798                                    TABLE_UINT8, info->mcast_igmp_version,
1799                                    TABLE_EMPTY,
1800                                    TABLE_STRING, "Cost:",
1801                                    TABLE_UINT32, info->cost);
1802                 if (r < 0)
1803                         return table_log_add_error(r);
1804 
1805                 if (info->port_state <= BR_STATE_BLOCKING)
1806                         r = table_add_many(table,
1807                                            TABLE_EMPTY,
1808                                            TABLE_STRING, "Port State:",
1809                                            TABLE_STRING, bridge_state_to_string(info->port_state));
1810         } else if (streq_ptr(info->netdev_kind, "bond")) {
1811                 r = table_add_many(table,
1812                                    TABLE_EMPTY,
1813                                    TABLE_STRING, "Mode:",
1814                                    TABLE_STRING, bond_mode_to_string(info->mode),
1815                                    TABLE_EMPTY,
1816                                    TABLE_STRING, "Miimon:",
1817                                    TABLE_TIMESPAN_MSEC, info->miimon * USEC_PER_MSEC,
1818                                    TABLE_EMPTY,
1819                                    TABLE_STRING, "Updelay:",
1820                                    TABLE_TIMESPAN_MSEC, info->updelay * USEC_PER_MSEC,
1821                                    TABLE_EMPTY,
1822                                    TABLE_STRING, "Downdelay:",
1823                                    TABLE_TIMESPAN_MSEC, info->downdelay * USEC_PER_MSEC);
1824                 if (r < 0)
1825                         return table_log_add_error(r);
1826 
1827         } else if (streq_ptr(info->netdev_kind, "vxlan")) {
1828                 char ttl[CONST_MAX(STRLEN("auto") + 1, DECIMAL_STR_MAX(uint8_t))];
1829 
1830                 if (info->vxlan_info.vni > 0) {
1831                         r = table_add_many(table,
1832                                            TABLE_EMPTY,
1833                                            TABLE_STRING, "VNI:",
1834                                            TABLE_UINT32, info->vxlan_info.vni);
1835                         if (r < 0)
1836                                 return table_log_add_error(r);
1837                 }
1838 
1839                 if (IN_SET(info->vxlan_info.group_family, AF_INET, AF_INET6)) {
1840                         const char *p;
1841 
1842                         r = in_addr_is_multicast(info->vxlan_info.group_family, &info->vxlan_info.group);
1843                         if (r <= 0)
1844                                 p = "Remote:";
1845                         else
1846                                 p = "Group:";
1847 
1848                         r = table_add_many(table,
1849                                            TABLE_EMPTY,
1850                                            TABLE_STRING, p,
1851                                            info->vxlan_info.group_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
1852                                            &info->vxlan_info.group);
1853                         if (r < 0)
1854                                 return table_log_add_error(r);
1855                 }
1856 
1857                 if (IN_SET(info->vxlan_info.local_family, AF_INET, AF_INET6)) {
1858                         r = table_add_many(table,
1859                                            TABLE_EMPTY,
1860                                            TABLE_STRING, "Local:",
1861                                            info->vxlan_info.local_family == AF_INET ? TABLE_IN_ADDR : TABLE_IN6_ADDR,
1862                                            &info->vxlan_info.local);
1863                         if (r < 0)
1864                                 return table_log_add_error(r);
1865                 }
1866 
1867                 if (info->vxlan_info.dest_port > 0) {
1868                         r = table_add_many(table,
1869                                            TABLE_EMPTY,
1870                                            TABLE_STRING, "Destination Port:",
1871                                            TABLE_UINT16, be16toh(info->vxlan_info.dest_port));
1872                         if (r < 0)
1873                                 return table_log_add_error(r);
1874                 }
1875 
1876                 if (info->vxlan_info.link > 0) {
1877                         r = table_add_many(table,
1878                                            TABLE_EMPTY,
1879                                            TABLE_STRING, "Underlying Device:",
1880                                            TABLE_IFINDEX, info->vxlan_info.link);
1881                         if (r < 0)
1882                                  return table_log_add_error(r);
1883                 }
1884 
1885                 r = table_add_many(table,
1886                                    TABLE_EMPTY,
1887                                    TABLE_STRING, "Learning:",
1888                                    TABLE_BOOLEAN, info->vxlan_info.learning);
1889                 if (r < 0)
1890                         return table_log_add_error(r);
1891 
1892                 r = table_add_many(table,
1893                                    TABLE_EMPTY,
1894                                    TABLE_STRING, "RSC:",
1895                                    TABLE_BOOLEAN, info->vxlan_info.rsc);
1896                 if (r < 0)
1897                         return table_log_add_error(r);
1898 
1899                 r = table_add_many(table,
1900                                    TABLE_EMPTY,
1901                                    TABLE_STRING, "L3MISS:",
1902                                    TABLE_BOOLEAN, info->vxlan_info.l3miss);
1903                 if (r < 0)
1904                         return table_log_add_error(r);
1905 
1906                 r = table_add_many(table,
1907                                    TABLE_EMPTY,
1908                                    TABLE_STRING, "L2MISS:",
1909                                    TABLE_BOOLEAN, info->vxlan_info.l2miss);
1910                 if (r < 0)
1911                         return table_log_add_error(r);
1912 
1913                 if (info->vxlan_info.tos > 1) {
1914                         r = table_add_many(table,
1915                                            TABLE_EMPTY,
1916                                            TABLE_STRING, "TOS:",
1917                                            TABLE_UINT8, info->vxlan_info.tos);
1918                         if (r < 0)
1919                                 return table_log_add_error(r);
1920                 }
1921 
1922                 if (info->vxlan_info.ttl > 0)
1923                         xsprintf(ttl, "%" PRIu8, info->vxlan_info.ttl);
1924                 else
1925                         strcpy(ttl, "auto");
1926 
1927                 r = table_add_many(table,
1928                                    TABLE_EMPTY,
1929                                    TABLE_STRING, "TTL:",
1930                                    TABLE_STRING, ttl);
1931                 if (r < 0)
1932                         return table_log_add_error(r);
1933         } else if (streq_ptr(info->netdev_kind, "vlan") && info->vlan_id > 0) {
1934                 r = table_add_many(table,
1935                                    TABLE_EMPTY,
1936                                    TABLE_STRING, "VLan Id:",
1937                                    TABLE_UINT16, info->vlan_id);
1938                 if (r < 0)
1939                         return table_log_add_error(r);
1940         } else if (STRPTR_IN_SET(info->netdev_kind, "ipip", "sit", "gre", "gretap", "erspan", "vti")) {
1941                 if (in_addr_is_set(AF_INET, &info->local)) {
1942                         r = table_add_many(table,
1943                                            TABLE_EMPTY,
1944                                            TABLE_STRING, "Local:",
1945                                            TABLE_IN_ADDR, &info->local);
1946                         if (r < 0)
1947                                 return table_log_add_error(r);
1948                 }
1949 
1950                 if (in_addr_is_set(AF_INET, &info->remote)) {
1951                         r = table_add_many(table,
1952                                            TABLE_EMPTY,
1953                                            TABLE_STRING, "Remote:",
1954                                            TABLE_IN_ADDR, &info->remote);
1955                         if (r < 0)
1956                                 return table_log_add_error(r);
1957                 }
1958         } else if (STRPTR_IN_SET(info->netdev_kind, "ip6gre", "ip6gretap", "ip6erspan", "vti6")) {
1959                 if (in_addr_is_set(AF_INET6, &info->local)) {
1960                         r = table_add_many(table,
1961                                            TABLE_EMPTY,
1962                                            TABLE_STRING, "Local:",
1963                                            TABLE_IN6_ADDR, &info->local);
1964                         if (r < 0)
1965                                 return table_log_add_error(r);
1966                 }
1967 
1968                 if (in_addr_is_set(AF_INET6, &info->remote)) {
1969                         r = table_add_many(table,
1970                                            TABLE_EMPTY,
1971                                            TABLE_STRING, "Remote:",
1972                                            TABLE_IN6_ADDR, &info->remote);
1973                         if (r < 0)
1974                                 return table_log_add_error(r);
1975                 }
1976         } else if (streq_ptr(info->netdev_kind, "geneve")) {
1977                 r = table_add_many(table,
1978                                    TABLE_EMPTY,
1979                                    TABLE_STRING, "VNI:",
1980                                    TABLE_UINT32, info->vni);
1981                 if (r < 0)
1982                         return table_log_add_error(r);
1983 
1984                 if (info->has_tunnel_ipv4 && in_addr_is_set(AF_INET, &info->remote)) {
1985                         r = table_add_many(table,
1986                                            TABLE_EMPTY,
1987                                            TABLE_STRING, "Remote:",
1988                                            TABLE_IN_ADDR, &info->remote);
1989                         if (r < 0)
1990                                 return table_log_add_error(r);
1991                 } else if (in_addr_is_set(AF_INET6, &info->remote)) {
1992                         r = table_add_many(table,
1993                                            TABLE_EMPTY,
1994                                            TABLE_STRING, "Remote:",
1995                                            TABLE_IN6_ADDR, &info->remote);
1996                         if (r < 0)
1997                                 return table_log_add_error(r);
1998                 }
1999 
2000                 if (info->ttl > 0) {
2001                         r = table_add_many(table,
2002                                            TABLE_EMPTY,
2003                                            TABLE_STRING, "TTL:",
2004                                            TABLE_UINT8, info->ttl);
2005                         if (r < 0)
2006                                 return table_log_add_error(r);
2007                 }
2008 
2009                 if (info->tos > 0) {
2010                         r = table_add_many(table,
2011                                            TABLE_EMPTY,
2012                                            TABLE_STRING, "TOS:",
2013                                            TABLE_UINT8, info->tos);
2014                         if (r < 0)
2015                                 return table_log_add_error(r);
2016                 }
2017 
2018                 r = table_add_many(table,
2019                                    TABLE_EMPTY,
2020                                    TABLE_STRING, "Port:",
2021                                    TABLE_UINT16, info->tunnel_port);
2022                 if (r < 0)
2023                         return table_log_add_error(r);
2024 
2025                 r = table_add_many(table,
2026                                    TABLE_EMPTY,
2027                                    TABLE_STRING, "Inherit:",
2028                                    TABLE_STRING, geneve_df_to_string(info->inherit));
2029                 if (r < 0)
2030                         return table_log_add_error(r);
2031 
2032                 if (info->df > 0) {
2033                         r = table_add_many(table,
2034                                            TABLE_EMPTY,
2035                                            TABLE_STRING, "IPDoNotFragment:",
2036                                            TABLE_UINT8, info->df);
2037                         if (r < 0)
2038                                 return table_log_add_error(r);
2039                 }
2040 
2041                 r = table_add_many(table,
2042                                    TABLE_EMPTY,
2043                                    TABLE_STRING, "UDPChecksum:",
2044                                    TABLE_BOOLEAN, info->csum);
2045                 if (r < 0)
2046                         return table_log_add_error(r);
2047 
2048                 r = table_add_many(table,
2049                                    TABLE_EMPTY,
2050                                    TABLE_STRING, "UDP6ZeroChecksumTx:",
2051                                    TABLE_BOOLEAN, info->csum6_tx);
2052                 if (r < 0)
2053                         return table_log_add_error(r);
2054 
2055                 r = table_add_many(table,
2056                                    TABLE_EMPTY,
2057                                    TABLE_STRING, "UDP6ZeroChecksumRx:",
2058                                    TABLE_BOOLEAN, info->csum6_rx);
2059                 if (r < 0)
2060                         return table_log_add_error(r);
2061 
2062                 if (info->label > 0) {
2063                         r = table_add_many(table,
2064                                            TABLE_EMPTY,
2065                                            TABLE_STRING, "FlowLabel:",
2066                                            TABLE_UINT32, info->label);
2067                         if (r < 0)
2068                                 return table_log_add_error(r);
2069                 }
2070         } else if (STRPTR_IN_SET(info->netdev_kind, "macvlan", "macvtap")) {
2071                 r = table_add_many(table,
2072                                    TABLE_EMPTY,
2073                                    TABLE_STRING, "Mode:",
2074                                    TABLE_STRING, macvlan_mode_to_string(info->macvlan_mode));
2075                 if (r < 0)
2076                         return table_log_add_error(r);
2077         } else if (streq_ptr(info->netdev_kind, "ipvlan")) {
2078                 _cleanup_free_ char *p = NULL, *s = NULL;
2079 
2080                 if (info->ipvlan_flags & IPVLAN_F_PRIVATE)
2081                         p = strdup("private");
2082                 else if (info->ipvlan_flags & IPVLAN_F_VEPA)
2083                         p = strdup("vepa");
2084                 else
2085                         p = strdup("bridge");
2086                 if (!p)
2087                         log_oom();
2088 
2089                 s = strjoin(ipvlan_mode_to_string(info->ipvlan_mode), " (", p, ")");
2090                 if (!s)
2091                         return log_oom();
2092 
2093                 r = table_add_many(table,
2094                                    TABLE_EMPTY,
2095                                    TABLE_STRING, "Mode:",
2096                                    TABLE_STRING, s);
2097                 if (r < 0)
2098                         return table_log_add_error(r);
2099         }
2100 
2101         if (info->has_wlan_link_info) {
2102                 _cleanup_free_ char *esc = NULL;
2103 
2104                 r = table_add_many(table,
2105                                    TABLE_EMPTY,
2106                                    TABLE_STRING, "WiFi access point:");
2107                 if (r < 0)
2108                         return table_log_add_error(r);
2109 
2110                 if (info->ssid)
2111                         esc = cescape(info->ssid);
2112 
2113                 r = table_add_cell_stringf(table, NULL, "%s (%s)",
2114                                            strnull(esc),
2115                                            ETHER_ADDR_TO_STR(&info->bssid));
2116                 if (r < 0)
2117                         return table_log_add_error(r);
2118         }
2119 
2120         if (info->has_bitrates) {
2121                 r = table_add_many(table,
2122                                    TABLE_EMPTY,
2123                                    TABLE_STRING, "Bit Rate (Tx/Rx):");
2124                 if (r < 0)
2125                         return table_log_add_error(r);
2126                 r = table_add_cell_stringf(table, NULL, "%sbps/%sbps",
2127                                            FORMAT_BYTES_FULL(info->tx_bitrate, 0),
2128                                            FORMAT_BYTES_FULL(info->rx_bitrate, 0));
2129                 if (r < 0)
2130                         return table_log_add_error(r);
2131         }
2132 
2133         if (info->has_tx_queues || info->has_rx_queues) {
2134                 r = table_add_many(table,
2135                                    TABLE_EMPTY,
2136                                    TABLE_STRING, "Queue Length (Tx/Rx):");
2137                 if (r < 0)
2138                         return table_log_add_error(r);
2139                 r = table_add_cell_stringf(table, NULL, "%" PRIu32 "/%" PRIu32, info->tx_queues, info->rx_queues);
2140                 if (r < 0)
2141                         return table_log_add_error(r);
2142         }
2143 
2144         if (info->has_ethtool_link_info) {
2145                 const char *duplex = duplex_to_string(info->duplex);
2146                 const char *port = port_to_string(info->port);
2147 
2148                 if (IN_SET(info->autonegotiation, AUTONEG_DISABLE, AUTONEG_ENABLE)) {
2149                         r = table_add_many(table,
2150                                            TABLE_EMPTY,
2151                                            TABLE_STRING, "Auto negotiation:",
2152                                            TABLE_BOOLEAN, info->autonegotiation == AUTONEG_ENABLE);
2153                         if (r < 0)
2154                                 return table_log_add_error(r);
2155                 }
2156 
2157                 if (info->speed > 0) {
2158                         r = table_add_many(table,
2159                                            TABLE_EMPTY,
2160                                            TABLE_STRING, "Speed:",
2161                                            TABLE_BPS, info->speed);
2162                         if (r < 0)
2163                                 return table_log_add_error(r);
2164                 }
2165 
2166                 if (duplex) {
2167                         r = table_add_many(table,
2168                                            TABLE_EMPTY,
2169                                            TABLE_STRING, "Duplex:",
2170                                            TABLE_STRING, duplex);
2171                         if (r < 0)
2172                                 return table_log_add_error(r);
2173                 }
2174 
2175                 if (port) {
2176                         r = table_add_many(table,
2177                                            TABLE_EMPTY,
2178                                            TABLE_STRING, "Port:",
2179                                            TABLE_STRING, port);
2180                         if (r < 0)
2181                                 return table_log_add_error(r);
2182                 }
2183         }
2184 
2185         r = dump_addresses(rtnl, lease, table, info->ifindex);
2186         if (r < 0)
2187                 return r;
2188         r = dump_gateways(rtnl, hwdb, table, info->ifindex);
2189         if (r < 0)
2190                 return r;
2191         r = dump_list(table, "DNS:", dns);
2192         if (r < 0)
2193                 return r;
2194         r = dump_list(table, "Search Domains:", search_domains);
2195         if (r < 0)
2196                 return r;
2197         r = dump_list(table, "Route Domains:", route_domains);
2198         if (r < 0)
2199                 return r;
2200         r = dump_list(table, "NTP:", ntp);
2201         if (r < 0)
2202                 return r;
2203         r = dump_list(table, "SIP:", sip);
2204         if (r < 0)
2205                 return r;
2206         r = dump_ifindexes(table, "Carrier Bound To:", carrier_bound_to);
2207         if (r < 0)
2208                 return r;
2209         r = dump_ifindexes(table, "Carrier Bound By:", carrier_bound_by);
2210         if (r < 0)
2211                 return r;
2212 
2213         r = sd_network_link_get_activation_policy(info->ifindex, &activation_policy);
2214         if (r >= 0) {
2215                 r = table_add_many(table,
2216                                    TABLE_EMPTY,
2217                                    TABLE_STRING, "Activation Policy:",
2218                                    TABLE_STRING, activation_policy);
2219                 if (r < 0)
2220                         return table_log_add_error(r);
2221         }
2222 
2223         r = sd_network_link_get_required_for_online(info->ifindex);
2224         if (r >= 0) {
2225                 r = table_add_many(table,
2226                                    TABLE_EMPTY,
2227                                    TABLE_STRING, "Required For Online:",
2228                                    TABLE_BOOLEAN, r);
2229                 if (r < 0)
2230                         return table_log_add_error(r);
2231         }
2232 
2233         if (lease) {
2234                 const void *client_id;
2235                 size_t client_id_len;
2236                 const char *tz;
2237 
2238                 r = sd_dhcp_lease_get_timezone(lease, &tz);
2239                 if (r >= 0) {
2240                         r = table_add_many(table,
2241                                            TABLE_EMPTY,
2242                                            TABLE_STRING, "Time Zone:",
2243                                            TABLE_STRING, tz);
2244                         if (r < 0)
2245                                 return table_log_add_error(r);
2246                 }
2247 
2248                 r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
2249                 if (r >= 0) {
2250                         _cleanup_free_ char *id = NULL;
2251 
2252                         r = sd_dhcp_client_id_to_string(client_id, client_id_len, &id);
2253                         if (r >= 0) {
2254                                 r = table_add_many(table,
2255                                                    TABLE_EMPTY,
2256                                                    TABLE_STRING, "DHCP4 Client ID:",
2257                                                    TABLE_STRING, id);
2258                                 if (r < 0)
2259                                         return table_log_add_error(r);
2260                         }
2261                 }
2262         }
2263 
2264         r = sd_network_link_get_dhcp6_client_iaid_string(info->ifindex, &iaid);
2265         if (r >= 0) {
2266                 r = table_add_many(table,
2267                                    TABLE_EMPTY,
2268                                    TABLE_STRING, "DHCP6 Client IAID:",
2269                                    TABLE_STRING, iaid);
2270                 if (r < 0)
2271                         return table_log_add_error(r);
2272         }
2273 
2274         r = sd_network_link_get_dhcp6_client_duid_string(info->ifindex, &duid);
2275         if (r >= 0) {
2276                 r = table_add_many(table,
2277                                    TABLE_EMPTY,
2278                                    TABLE_STRING, "DHCP6 Client DUID:",
2279                                    TABLE_STRING, duid);
2280                 if (r < 0)
2281                         return table_log_add_error(r);
2282         }
2283 
2284         r = dump_lldp_neighbors(table, "Connected To:", info->ifindex);
2285         if (r < 0)
2286                 return r;
2287 
2288         r = dump_dhcp_leases(table, "Offered DHCP leases:", bus, info);
2289         if (r < 0)
2290                 return r;
2291 
2292         r = dump_statistics(table, info);
2293         if (r < 0)
2294                 return r;
2295 
2296         r = table_print(table, NULL);
2297         if (r < 0)
2298                 return table_log_print_error(r);
2299 
2300         return show_logs(info);
2301 }
2302 
system_status(sd_netlink * rtnl,sd_hwdb * hwdb)2303 static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
2304         _cleanup_free_ char *operational_state = NULL, *online_state = NULL;
2305         _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
2306         const char *on_color_operational, *on_color_online;
2307         _cleanup_(table_unrefp) Table *table = NULL;
2308         TableCell *cell;
2309         int r;
2310 
2311         assert(rtnl);
2312 
2313         (void) sd_network_get_operational_state(&operational_state);
2314         operational_state_to_color(NULL, operational_state, &on_color_operational, NULL);
2315 
2316         (void) sd_network_get_online_state(&online_state);
2317         online_state_to_color(online_state, &on_color_online, NULL);
2318 
2319         table = table_new("dot", "key", "value");
2320         if (!table)
2321                 return log_oom();
2322 
2323         if (arg_full)
2324                 table_set_width(table, 0);
2325 
2326         assert_se(cell = table_get_cell(table, 0, 0));
2327         (void) table_set_ellipsize_percent(table, cell, 100);
2328 
2329         assert_se(cell = table_get_cell(table, 0, 1));
2330         (void) table_set_align_percent(table, cell, 100);
2331         (void) table_set_ellipsize_percent(table, cell, 100);
2332 
2333         table_set_header(table, false);
2334 
2335         r = table_add_many(table,
2336                            TABLE_STRING, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE),
2337                            TABLE_SET_COLOR, on_color_operational,
2338                            TABLE_STRING, "State:",
2339                            TABLE_STRING, strna(operational_state),
2340                            TABLE_SET_COLOR, on_color_operational,
2341                            TABLE_EMPTY,
2342                            TABLE_STRING, "Online state:",
2343                            TABLE_STRING, online_state ?: "unknown",
2344                            TABLE_SET_COLOR, on_color_online);
2345         if (r < 0)
2346                 return table_log_add_error(r);
2347 
2348         r = dump_addresses(rtnl, NULL, table, 0);
2349         if (r < 0)
2350                 return r;
2351         r = dump_gateways(rtnl, hwdb, table, 0);
2352         if (r < 0)
2353                 return r;
2354 
2355         (void) sd_network_get_dns(&dns);
2356         r = dump_list(table, "DNS:", dns);
2357         if (r < 0)
2358                 return r;
2359 
2360         (void) sd_network_get_search_domains(&search_domains);
2361         r = dump_list(table, "Search Domains:", search_domains);
2362         if (r < 0)
2363                 return r;
2364 
2365         (void) sd_network_get_route_domains(&route_domains);
2366         r = dump_list(table, "Route Domains:", route_domains);
2367         if (r < 0)
2368                 return r;
2369 
2370         (void) sd_network_get_ntp(&ntp);
2371         r = dump_list(table, "NTP:", ntp);
2372         if (r < 0)
2373                 return r;
2374 
2375         r = table_print(table, NULL);
2376         if (r < 0)
2377                 return table_log_print_error(r);
2378 
2379         return show_logs(NULL);
2380 }
2381 
link_status(int argc,char * argv[],void * userdata)2382 static int link_status(int argc, char *argv[], void *userdata) {
2383         sd_bus *bus = ASSERT_PTR(userdata);
2384         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2385         _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
2386         _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
2387         int r, c;
2388 
2389         if (arg_json_format_flags != JSON_FORMAT_OFF) {
2390                 if (arg_all || argc <= 1)
2391                         return dump_manager_description(bus);
2392                 else
2393                         return dump_link_description(bus, strv_skip(argv, 1));
2394         }
2395 
2396         pager_open(arg_pager_flags);
2397 
2398         r = sd_netlink_open(&rtnl);
2399         if (r < 0)
2400                 return log_error_errno(r, "Failed to connect to netlink: %m");
2401 
2402         r = sd_hwdb_new(&hwdb);
2403         if (r < 0)
2404                 log_debug_errno(r, "Failed to open hardware database: %m");
2405 
2406         if (arg_all)
2407                 c = acquire_link_info(bus, rtnl, NULL, &links);
2408         else if (argc <= 1)
2409                 return system_status(rtnl, hwdb);
2410         else
2411                 c = acquire_link_info(bus, rtnl, argv + 1, &links);
2412         if (c < 0)
2413                 return c;
2414 
2415         for (int i = 0; i < c; i++) {
2416                 if (i > 0)
2417                         fputc('\n', stdout);
2418 
2419                 link_status_one(bus, rtnl, hwdb, links + i);
2420         }
2421 
2422         return 0;
2423 }
2424 
lldp_capabilities_to_string(uint16_t x)2425 static char *lldp_capabilities_to_string(uint16_t x) {
2426         static const char characters[] = {
2427                 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
2428         };
2429         char *ret;
2430         unsigned i;
2431 
2432         ret = new(char, ELEMENTSOF(characters) + 1);
2433         if (!ret)
2434                 return NULL;
2435 
2436         for (i = 0; i < ELEMENTSOF(characters); i++)
2437                 ret[i] = (x & (1U << i)) ? characters[i] : '.';
2438 
2439         ret[i] = 0;
2440         return ret;
2441 }
2442 
lldp_capabilities_legend(uint16_t x)2443 static void lldp_capabilities_legend(uint16_t x) {
2444         unsigned cols = columns();
2445         static const char* const table[] = {
2446                 "o - Other",
2447                 "p - Repeater",
2448                 "b - Bridge",
2449                 "w - WLAN Access Point",
2450                 "r - Router",
2451                 "t - Telephone",
2452                 "d - DOCSIS cable device",
2453                 "a - Station",
2454                 "c - Customer VLAN",
2455                 "s - Service VLAN",
2456                 "m - Two-port MAC Relay (TPMR)",
2457         };
2458 
2459         if (x == 0)
2460                 return;
2461 
2462         printf("\nCapability Flags:\n");
2463         for (unsigned w = 0, i = 0; i < ELEMENTSOF(table); i++)
2464                 if (x & (1U << i) || arg_all) {
2465                         bool newline;
2466 
2467                         newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols;
2468                         if (newline)
2469                                 w = 0;
2470                         w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]);
2471                 }
2472         puts("");
2473 }
2474 
link_lldp_status(int argc,char * argv[],void * userdata)2475 static int link_lldp_status(int argc, char *argv[], void *userdata) {
2476         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2477         _cleanup_(link_info_array_freep) LinkInfo *links = NULL;
2478         _cleanup_(table_unrefp) Table *table = NULL;
2479         int r, c, m = 0;
2480         uint16_t all = 0;
2481         TableCell *cell;
2482 
2483         r = sd_netlink_open(&rtnl);
2484         if (r < 0)
2485                 return log_error_errno(r, "Failed to connect to netlink: %m");
2486 
2487         c = acquire_link_info(NULL, rtnl, argc > 1 ? argv + 1 : NULL, &links);
2488         if (c < 0)
2489                 return c;
2490 
2491         pager_open(arg_pager_flags);
2492 
2493         table = table_new("link",
2494                           "chassis-id",
2495                           "system-name",
2496                           "caps",
2497                           "port-id",
2498                           "port-description");
2499         if (!table)
2500                 return log_oom();
2501 
2502         if (arg_full)
2503                 table_set_width(table, 0);
2504 
2505         table_set_header(table, arg_legend);
2506 
2507         assert_se(cell = table_get_cell(table, 0, 3));
2508         table_set_minimum_width(table, cell, 11);
2509 
2510         for (int i = 0; i < c; i++) {
2511                 _cleanup_fclose_ FILE *f = NULL;
2512 
2513                 r = open_lldp_neighbors(links[i].ifindex, &f);
2514                 if (r == -ENOENT)
2515                         continue;
2516                 if (r < 0) {
2517                         log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex);
2518                         continue;
2519                 }
2520 
2521                 for (;;) {
2522                         const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL;
2523                         _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
2524                         _cleanup_free_ char *capabilities = NULL;
2525                         uint16_t cc;
2526 
2527                         r = next_lldp_neighbor(f, &n);
2528                         if (r < 0) {
2529                                 log_warning_errno(r, "Failed to read neighbor data: %m");
2530                                 break;
2531                         }
2532                         if (r == 0)
2533                                 break;
2534 
2535                         (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id);
2536                         (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
2537                         (void) sd_lldp_neighbor_get_system_name(n, &system_name);
2538                         (void) sd_lldp_neighbor_get_port_description(n, &port_description);
2539 
2540                         if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) {
2541                                 capabilities = lldp_capabilities_to_string(cc);
2542                                 all |= cc;
2543                         }
2544 
2545                         r = table_add_many(table,
2546                                            TABLE_STRING, links[i].name,
2547                                            TABLE_STRING, strna(chassis_id),
2548                                            TABLE_STRING, strna(system_name),
2549                                            TABLE_STRING, strna(capabilities),
2550                                            TABLE_STRING, strna(port_id),
2551                                            TABLE_STRING, strna(port_description));
2552                         if (r < 0)
2553                                 return table_log_add_error(r);
2554 
2555                         m++;
2556                 }
2557         }
2558 
2559         r = table_print(table, NULL);
2560         if (r < 0)
2561                 return table_log_print_error(r);
2562 
2563         if (arg_legend) {
2564                 lldp_capabilities_legend(all);
2565                 printf("\n%i neighbors listed.\n", m);
2566         }
2567 
2568         return 0;
2569 }
2570 
link_delete_send_message(sd_netlink * rtnl,int index)2571 static int link_delete_send_message(sd_netlink *rtnl, int index) {
2572         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
2573         int r;
2574 
2575         assert(rtnl);
2576 
2577         r = sd_rtnl_message_new_link(rtnl, &req, RTM_DELLINK, index);
2578         if (r < 0)
2579                 return rtnl_log_create_error(r);
2580 
2581         r = sd_netlink_call(rtnl, req, 0, NULL);
2582         if (r < 0)
2583                 return r;
2584 
2585         return 0;
2586 }
2587 
link_up_down_send_message(sd_netlink * rtnl,char * command,int index)2588 static int link_up_down_send_message(sd_netlink *rtnl, char *command, int index) {
2589         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
2590         int r;
2591 
2592         assert(rtnl);
2593 
2594         r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, index);
2595         if (r < 0)
2596                 return rtnl_log_create_error(r);
2597 
2598         if (streq(command, "up"))
2599                 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
2600         else
2601                 r = sd_rtnl_message_link_set_flags(req, 0, IFF_UP);
2602         if (r < 0)
2603                 return log_error_errno(r, "Could not set link flags: %m");
2604 
2605         r = sd_netlink_call(rtnl, req, 0, NULL);
2606         if (r < 0)
2607                 return r;
2608 
2609         return 0;
2610 }
2611 
link_up_down(int argc,char * argv[],void * userdata)2612 static int link_up_down(int argc, char *argv[], void *userdata) {
2613         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2614         _cleanup_set_free_ Set *indexes = NULL;
2615         int index, r;
2616         void *p;
2617 
2618         r = sd_netlink_open(&rtnl);
2619         if (r < 0)
2620                 return log_error_errno(r, "Failed to connect to netlink: %m");
2621 
2622         indexes = set_new(NULL);
2623         if (!indexes)
2624                 return log_oom();
2625 
2626         for (int i = 1; i < argc; i++) {
2627                 index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2628                 if (index < 0)
2629                         return index;
2630 
2631                 r = set_put(indexes, INT_TO_PTR(index));
2632                 if (r < 0)
2633                         return log_oom();
2634         }
2635 
2636         SET_FOREACH(p, indexes) {
2637                 index = PTR_TO_INT(p);
2638                 r = link_up_down_send_message(rtnl, argv[0], index);
2639                 if (r < 0)
2640                         return log_error_errno(r, "Failed to bring %s interface %s: %m",
2641                                                argv[0], FORMAT_IFNAME_FULL(index, FORMAT_IFNAME_IFINDEX));
2642         }
2643 
2644         return r;
2645 }
2646 
link_delete(int argc,char * argv[],void * userdata)2647 static int link_delete(int argc, char *argv[], void *userdata) {
2648         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2649         _cleanup_set_free_ Set *indexes = NULL;
2650         int index, r;
2651         void *p;
2652 
2653         r = sd_netlink_open(&rtnl);
2654         if (r < 0)
2655                 return log_error_errno(r, "Failed to connect to netlink: %m");
2656 
2657         indexes = set_new(NULL);
2658         if (!indexes)
2659                 return log_oom();
2660 
2661         for (int i = 1; i < argc; i++) {
2662                 index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2663                 if (index < 0)
2664                         return index;
2665 
2666                 r = set_put(indexes, INT_TO_PTR(index));
2667                 if (r < 0)
2668                         return log_oom();
2669         }
2670 
2671         SET_FOREACH(p, indexes) {
2672                 index = PTR_TO_INT(p);
2673                 r = link_delete_send_message(rtnl, index);
2674                 if (r < 0)
2675                         return log_error_errno(r, "Failed to delete interface %s: %m",
2676                                                FORMAT_IFNAME_FULL(index, FORMAT_IFNAME_IFINDEX));
2677         }
2678 
2679         return r;
2680 }
2681 
link_renew_one(sd_bus * bus,int index,const char * name)2682 static int link_renew_one(sd_bus *bus, int index, const char *name) {
2683         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2684         int r;
2685 
2686         r = bus_call_method(bus, bus_network_mgr, "RenewLink", &error, NULL, "i", index);
2687         if (r < 0)
2688                 return log_error_errno(r, "Failed to renew dynamic configuration of interface %s: %s",
2689                                        name, bus_error_message(&error, r));
2690 
2691         return 0;
2692 }
2693 
link_renew(int argc,char * argv[],void * userdata)2694 static int link_renew(int argc, char *argv[], void *userdata) {
2695         sd_bus *bus = ASSERT_PTR(userdata);
2696         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2697         int index, k = 0, r;
2698 
2699         for (int i = 1; i < argc; i++) {
2700                 index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2701                 if (index < 0)
2702                         return index;
2703 
2704                 r = link_renew_one(bus, index, argv[i]);
2705                 if (r < 0 && k >= 0)
2706                         k = r;
2707         }
2708 
2709         return k;
2710 }
2711 
link_force_renew_one(sd_bus * bus,int index,const char * name)2712 static int link_force_renew_one(sd_bus *bus, int index, const char *name) {
2713         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2714         int r;
2715 
2716         r = bus_call_method(bus, bus_network_mgr, "ForceRenewLink", &error, NULL, "i", index);
2717         if (r < 0)
2718                 return log_error_errno(r, "Failed to force renew dynamic configuration of interface %s: %s",
2719                                        name, bus_error_message(&error, r));
2720 
2721         return 0;
2722 }
2723 
link_force_renew(int argc,char * argv[],void * userdata)2724 static int link_force_renew(int argc, char *argv[], void *userdata) {
2725         sd_bus *bus = ASSERT_PTR(userdata);
2726         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2727         int k = 0, r;
2728 
2729         for (int i = 1; i < argc; i++) {
2730                 int index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2731                 if (index < 0)
2732                         return index;
2733 
2734                 r = link_force_renew_one(bus, index, argv[i]);
2735                 if (r < 0 && k >= 0)
2736                         k = r;
2737         }
2738 
2739         return k;
2740 }
2741 
verb_reload(int argc,char * argv[],void * userdata)2742 static int verb_reload(int argc, char *argv[], void *userdata) {
2743         sd_bus *bus = ASSERT_PTR(userdata);
2744         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2745         int r;
2746 
2747         r = bus_call_method(bus, bus_network_mgr, "Reload", &error, NULL, NULL);
2748         if (r < 0)
2749                 return log_error_errno(r, "Failed to reload network settings: %m");
2750 
2751         return 0;
2752 }
2753 
verb_reconfigure(int argc,char * argv[],void * userdata)2754 static int verb_reconfigure(int argc, char *argv[], void *userdata) {
2755         sd_bus *bus = ASSERT_PTR(userdata);
2756         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2757         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
2758         _cleanup_set_free_ Set *indexes = NULL;
2759         int index, r;
2760         void *p;
2761 
2762         indexes = set_new(NULL);
2763         if (!indexes)
2764                 return log_oom();
2765 
2766         for (int i = 1; i < argc; i++) {
2767                 index = rtnl_resolve_interface_or_warn(&rtnl, argv[i]);
2768                 if (index < 0)
2769                         return index;
2770 
2771                 r = set_put(indexes, INT_TO_PTR(index));
2772                 if (r < 0)
2773                         return log_oom();
2774         }
2775 
2776         SET_FOREACH(p, indexes) {
2777                 index = PTR_TO_INT(p);
2778                 r = bus_call_method(bus, bus_network_mgr, "ReconfigureLink", &error, NULL, "i", index);
2779                 if (r < 0)
2780                         return log_error_errno(r, "Failed to reconfigure network interface %s: %m",
2781                                                FORMAT_IFNAME_FULL(index, FORMAT_IFNAME_IFINDEX));
2782         }
2783 
2784         return 0;
2785 }
2786 
help(void)2787 static int help(void) {
2788         _cleanup_free_ char *link = NULL;
2789         int r;
2790 
2791         r = terminal_urlify_man("networkctl", "1", &link);
2792         if (r < 0)
2793                 return log_oom();
2794 
2795         printf("%s [OPTIONS...] COMMAND\n\n"
2796                "%sQuery and control the networking subsystem.%s\n"
2797                "\nCommands:\n"
2798                "  list [PATTERN...]      List links\n"
2799                "  status [PATTERN...]    Show link status\n"
2800                "  lldp [PATTERN...]      Show LLDP neighbors\n"
2801                "  label                  Show current address label entries in the kernel\n"
2802                "  delete DEVICES...      Delete virtual netdevs\n"
2803                "  up DEVICES...          Bring devices up\n"
2804                "  down DEVICES...        Bring devices down\n"
2805                "  renew DEVICES...       Renew dynamic configurations\n"
2806                "  forcerenew DEVICES...  Trigger DHCP reconfiguration of all connected clients\n"
2807                "  reconfigure DEVICES... Reconfigure interfaces\n"
2808                "  reload                 Reload .network and .netdev files\n"
2809                "\nOptions:\n"
2810                "  -h --help              Show this help\n"
2811                "     --version           Show package version\n"
2812                "     --no-pager          Do not pipe output into a pager\n"
2813                "     --no-legend         Do not show the headers and footers\n"
2814                "  -a --all               Show status for all links\n"
2815                "  -s --stats             Show detailed link statistics\n"
2816                "  -l --full              Do not ellipsize output\n"
2817                "  -n --lines=INTEGER     Number of journal entries to show\n"
2818                "     --json=pretty|short|off\n"
2819                "                         Generate JSON output\n"
2820                "\nSee the %s for details.\n",
2821                program_invocation_short_name,
2822                ansi_highlight(),
2823                ansi_normal(),
2824                link);
2825 
2826         return 0;
2827 }
2828 
parse_argv(int argc,char * argv[])2829 static int parse_argv(int argc, char *argv[]) {
2830 
2831         enum {
2832                 ARG_VERSION = 0x100,
2833                 ARG_NO_PAGER,
2834                 ARG_NO_LEGEND,
2835                 ARG_JSON,
2836         };
2837 
2838         static const struct option options[] = {
2839                 { "help",      no_argument,       NULL, 'h'           },
2840                 { "version",   no_argument,       NULL, ARG_VERSION   },
2841                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
2842                 { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
2843                 { "all",       no_argument,       NULL, 'a'           },
2844                 { "stats",     no_argument,       NULL, 's'           },
2845                 { "full",      no_argument,       NULL, 'l'           },
2846                 { "lines",     required_argument, NULL, 'n'           },
2847                 { "json",      required_argument, NULL, ARG_JSON      },
2848                 {}
2849         };
2850 
2851         int c, r;
2852 
2853         assert(argc >= 0);
2854         assert(argv);
2855 
2856         while ((c = getopt_long(argc, argv, "hasln:", options, NULL)) >= 0) {
2857 
2858                 switch (c) {
2859 
2860                 case 'h':
2861                         return help();
2862 
2863                 case ARG_VERSION:
2864                         return version();
2865 
2866                 case ARG_NO_PAGER:
2867                         arg_pager_flags |= PAGER_DISABLE;
2868                         break;
2869 
2870                 case ARG_NO_LEGEND:
2871                         arg_legend = false;
2872                         break;
2873 
2874                 case 'a':
2875                         arg_all = true;
2876                         break;
2877 
2878                 case 's':
2879                         arg_stats = true;
2880                         break;
2881 
2882                 case 'l':
2883                         arg_full = true;
2884                         break;
2885 
2886                 case 'n':
2887                         if (safe_atou(optarg, &arg_lines) < 0)
2888                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2889                                                        "Failed to parse lines '%s'", optarg);
2890                         break;
2891 
2892                 case ARG_JSON:
2893                         r = parse_json_argument(optarg, &arg_json_format_flags);
2894                         if (r <= 0)
2895                                 return r;
2896                         break;
2897 
2898                 case '?':
2899                         return -EINVAL;
2900 
2901                 default:
2902                         assert_not_reached();
2903                 }
2904         }
2905 
2906         return 1;
2907 }
2908 
networkctl_main(sd_bus * bus,int argc,char * argv[])2909 static int networkctl_main(sd_bus *bus, int argc, char *argv[]) {
2910         static const Verb verbs[] = {
2911                 { "list",        VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links          },
2912                 { "status",      VERB_ANY, VERB_ANY, 0,            link_status         },
2913                 { "lldp",        VERB_ANY, VERB_ANY, 0,            link_lldp_status    },
2914                 { "label",       1,        1,        0,            list_address_labels },
2915                 { "delete",      2,        VERB_ANY, 0,            link_delete         },
2916                 { "up",          2,        VERB_ANY, 0,            link_up_down        },
2917                 { "down",        2,        VERB_ANY, 0,            link_up_down        },
2918                 { "renew",       2,        VERB_ANY, 0,            link_renew          },
2919                 { "forcerenew",  2,        VERB_ANY, 0,            link_force_renew    },
2920                 { "reconfigure", 2,        VERB_ANY, 0,            verb_reconfigure    },
2921                 { "reload",      1,        1,        0,            verb_reload         },
2922                 {}
2923         };
2924 
2925         return dispatch_verb(argc, argv, verbs, bus);
2926 }
2927 
check_netns_match(sd_bus * bus)2928 static int check_netns_match(sd_bus *bus) {
2929         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2930         struct stat st;
2931         uint64_t id;
2932         int r;
2933 
2934         r = sd_bus_get_property_trivial(
2935                         bus,
2936                         "org.freedesktop.network1",
2937                         "/org/freedesktop/network1",
2938                         "org.freedesktop.network1.Manager",
2939                         "NamespaceId",
2940                         &error,
2941                         't',
2942                         &id);
2943         if (r < 0) {
2944                 log_debug_errno(r, "Failed to query network namespace of networkd, ignoring: %s", bus_error_message(&error, r));
2945                 return 0;
2946         }
2947         if (id == 0) {
2948                 log_debug("systemd-networkd.service not running in a network namespace (?), skipping netns check.");
2949                 return 0;
2950         }
2951 
2952         if (stat("/proc/self/ns/net", &st) < 0)
2953                 return log_error_errno(r, "Failed to determine our own network namespace ID: %m");
2954 
2955         if (id != st.st_ino)
2956                 return log_error_errno(SYNTHETIC_ERRNO(EREMOTE),
2957                                        "networkctl must be invoked in same network namespace as systemd-networkd.service.");
2958 
2959         return 0;
2960 }
2961 
warn_networkd_missing(void)2962 static void warn_networkd_missing(void) {
2963 
2964         if (access("/run/systemd/netif/state", F_OK) >= 0)
2965                 return;
2966 
2967         fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
2968 }
2969 
run(int argc,char * argv[])2970 static int run(int argc, char* argv[]) {
2971         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2972         int r;
2973 
2974         log_setup();
2975 
2976         r = parse_argv(argc, argv);
2977         if (r <= 0)
2978                 return r;
2979 
2980         r = sd_bus_open_system(&bus);
2981         if (r < 0)
2982                 return log_error_errno(r, "Failed to connect system bus: %m");
2983 
2984         r = check_netns_match(bus);
2985         if (r < 0)
2986                 return r;
2987 
2988         warn_networkd_missing();
2989 
2990         return networkctl_main(bus, argc, argv);
2991 }
2992 
2993 DEFINE_MAIN_FUNCTION(run);
2994