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