1 /* SPDX-License-Identifier: LGPL-2.1+ */
4 #include <linux/if_addrlabel.h>
11 #include "sd-device.h"
14 #include "sd-netlink.h"
15 #include "sd-network.h"
17 #include "alloc-util.h"
18 #include "arphrd-list.h"
19 #include "device-util.h"
20 #include "ether-addr-util.h"
22 #include "hwdb-util.h"
23 #include "local-addresses.h"
24 #include "locale-util.h"
26 #include "main-func.h"
27 #include "netlink-util.h"
29 #include "parse-util.h"
30 #include "pretty-print.h"
31 #include "socket-util.h"
32 #include "sort-util.h"
33 #include "sparse-endian.h"
34 #include "stdio-util.h"
35 #include "string-table.h"
36 #include "string-util.h"
39 #include "terminal-util.h"
42 static PagerFlags arg_pager_flags
= 0;
43 static bool arg_legend
= true;
44 static bool arg_all
= false;
46 static char *link_get_type_string(unsigned short iftype
, sd_device
*d
) {
47 const char *t
, *devtype
;
51 sd_device_get_devtype(d
, &devtype
) >= 0 &&
53 return strdup(devtype
);
55 t
= arphrd_to_name(iftype
);
67 static void operational_state_to_color(const char *state
, const char **on
, const char **off
) {
71 if (STRPTR_IN_SET(state
, "routable", "enslaved")) {
72 *on
= ansi_highlight_green();
74 } else if (streq_ptr(state
, "degraded")) {
75 *on
= ansi_highlight_yellow();
81 static void setup_state_to_color(const char *state
, const char **on
, const char **off
) {
85 if (streq_ptr(state
, "configured")) {
86 *on
= ansi_highlight_green();
88 } else if (streq_ptr(state
, "configuring")) {
89 *on
= ansi_highlight_yellow();
91 } else if (STRPTR_IN_SET(state
, "failed", "linger")) {
92 *on
= ansi_highlight_red();
98 typedef struct LinkInfo
{
99 char name
[IFNAMSIZ
+1];
101 unsigned short iftype
;
102 struct ether_addr mac_address
;
109 bool has_mac_address
:1;
113 bool has_tx_queues
:1;
114 bool has_rx_queues
:1;
117 static int link_info_compare(const LinkInfo
*a
, const LinkInfo
*b
) {
118 return CMP(a
->ifindex
, b
->ifindex
);
121 static int decode_link(sd_netlink_message
*m
, LinkInfo
*info
, char **patterns
) {
129 r
= sd_netlink_message_get_type(m
, &type
);
133 if (type
!= RTM_NEWLINK
)
136 r
= sd_rtnl_message_link_get_ifindex(m
, &ifindex
);
140 r
= sd_netlink_message_read_string(m
, IFLA_IFNAME
, &name
);
145 char str
[DECIMAL_STR_MAX(int)];
147 xsprintf(str
, "%i", ifindex
);
149 if (!strv_fnmatch(patterns
, str
, 0) && !strv_fnmatch(patterns
, name
, 0))
153 r
= sd_rtnl_message_link_get_type(m
, &info
->iftype
);
157 strscpy(info
->name
, sizeof info
->name
, name
);
158 info
->ifindex
= ifindex
;
160 info
->has_mac_address
=
161 sd_netlink_message_read_ether_addr(m
, IFLA_ADDRESS
, &info
->mac_address
) >= 0 &&
162 memcmp(&info
->mac_address
, ÐER_ADDR_NULL
, sizeof(struct ether_addr
)) != 0;
165 sd_netlink_message_read_u32(m
, IFLA_MTU
, &info
->mtu
) >= 0 &&
169 sd_netlink_message_read_u32(m
, IFLA_MIN_MTU
, &info
->min_mtu
) >= 0 &&
173 sd_netlink_message_read_u32(m
, IFLA_MAX_MTU
, &info
->max_mtu
) >= 0 &&
176 info
->has_rx_queues
=
177 sd_netlink_message_read_u32(m
, IFLA_NUM_RX_QUEUES
, &info
->rx_queues
) >= 0 &&
180 info
->has_tx_queues
=
181 sd_netlink_message_read_u32(m
, IFLA_NUM_TX_QUEUES
, &info
->tx_queues
) >= 0 &&
187 static int acquire_link_info(sd_netlink
*rtnl
, char **patterns
, LinkInfo
**ret
) {
188 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
189 _cleanup_free_ LinkInfo
*links
= NULL
;
190 size_t allocated
= 0, c
= 0;
191 sd_netlink_message
*i
;
197 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
199 return rtnl_log_create_error(r
);
201 r
= sd_netlink_message_request_dump(req
, true);
203 return rtnl_log_create_error(r
);
205 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
207 return log_error_errno(r
, "Failed to enumerate links: %m");
209 for (i
= reply
; i
; i
= sd_netlink_message_next(i
)) {
210 if (!GREEDY_REALLOC(links
, allocated
, c
+1))
213 r
= decode_link(i
, links
+ c
, patterns
);
220 typesafe_qsort(links
, c
, link_info_compare
);
222 *ret
= TAKE_PTR(links
);
227 static int list_links(int argc
, char *argv
[], void *userdata
) {
228 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
229 _cleanup_free_ LinkInfo
*links
= NULL
;
232 r
= sd_netlink_open(&rtnl
);
234 return log_error_errno(r
, "Failed to connect to netlink: %m");
236 c
= acquire_link_info(rtnl
, argc
> 1 ? argv
+ 1 : NULL
, &links
);
240 (void) pager_open(arg_pager_flags
);
243 printf("%3s %-16s %-18s %-16s %-10s\n",
250 for (i
= 0; i
< c
; i
++) {
251 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
;
252 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
253 const char *on_color_operational
, *off_color_operational
,
254 *on_color_setup
, *off_color_setup
;
255 char devid
[2 + DECIMAL_STR_MAX(int)];
256 _cleanup_free_
char *t
= NULL
;
258 (void) sd_network_link_get_operational_state(links
[i
].ifindex
, &operational_state
);
259 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
261 r
= sd_network_link_get_setup_state(links
[i
].ifindex
, &setup_state
);
262 if (r
== -ENODATA
) /* If there's no info available about this iface, it's unmanaged by networkd */
263 setup_state
= strdup("unmanaged");
264 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
266 xsprintf(devid
, "n%i", links
[i
].ifindex
);
267 (void) sd_device_new_from_device_id(&d
, devid
);
269 t
= link_get_type_string(links
[i
].iftype
, d
);
271 printf("%3i %-16s %-18s %s%-16s%s %s%-10s%s\n",
272 links
[i
].ifindex
, links
[i
].name
, strna(t
),
273 on_color_operational
, strna(operational_state
), off_color_operational
,
274 on_color_setup
, strna(setup_state
), off_color_setup
);
278 printf("\n%i links listed.\n", c
);
283 /* IEEE Organizationally Unique Identifier vendor string */
284 static int ieee_oui(sd_hwdb
*hwdb
, const struct ether_addr
*mac
, char **ret
) {
285 const char *description
;
286 char modalias
[STRLEN("OUI:XXYYXXYYXXYY") + 1], *desc
;
297 /* skip commonly misused 00:00:00 (Xerox) prefix */
298 if (memcmp(mac
, "\0\0\0", 3) == 0)
301 xsprintf(modalias
, "OUI:" ETHER_ADDR_FORMAT_STR
,
302 ETHER_ADDR_FORMAT_VAL(*mac
));
304 r
= sd_hwdb_get(hwdb
, modalias
, "ID_OUI_FROM_DATABASE", &description
);
308 desc
= strdup(description
);
317 static int get_gateway_description(
322 union in_addr_union
*gateway
,
323 char **gateway_description
) {
324 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
325 sd_netlink_message
*m
;
329 assert(ifindex
>= 0);
330 assert(IN_SET(family
, AF_INET
, AF_INET6
));
332 assert(gateway_description
);
334 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_GETNEIGH
, ifindex
, family
);
338 r
= sd_netlink_message_request_dump(req
, true);
342 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
346 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
347 union in_addr_union gw
= IN_ADDR_NULL
;
348 struct ether_addr mac
= ETHER_ADDR_NULL
;
352 r
= sd_netlink_message_get_errno(m
);
354 log_error_errno(r
, "got error: %m");
358 r
= sd_netlink_message_get_type(m
, &type
);
360 log_error_errno(r
, "could not get type: %m");
364 if (type
!= RTM_NEWNEIGH
) {
365 log_error("type is not RTM_NEWNEIGH");
369 r
= sd_rtnl_message_neigh_get_family(m
, &fam
);
371 log_error_errno(r
, "could not get family: %m");
376 log_error("family is not correct");
380 r
= sd_rtnl_message_neigh_get_ifindex(m
, &ifi
);
382 log_error_errno(r
, "could not get ifindex: %m");
386 if (ifindex
> 0 && ifi
!= ifindex
)
391 r
= sd_netlink_message_read_in_addr(m
, NDA_DST
, &gw
.in
);
397 r
= sd_netlink_message_read_in6_addr(m
, NDA_DST
, &gw
.in6
);
406 if (!in_addr_equal(fam
, &gw
, gateway
))
409 r
= sd_netlink_message_read_ether_addr(m
, NDA_LLADDR
, &mac
);
413 r
= ieee_oui(hwdb
, &mac
, gateway_description
);
423 static int dump_gateways(
428 _cleanup_free_
struct local_address
*local
= NULL
;
434 n
= local_gateways(rtnl
, ifindex
, AF_UNSPEC
, &local
);
438 for (i
= 0; i
< n
; i
++) {
439 _cleanup_free_
char *gateway
= NULL
, *description
= NULL
;
441 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &gateway
);
445 r
= get_gateway_description(rtnl
, hwdb
, local
[i
].ifindex
, local
[i
].family
, &local
[i
].address
, &description
);
447 log_debug_errno(r
, "Could not get description of gateway: %m");
450 (int) strlen(prefix
),
451 i
== 0 ? prefix
: "",
455 printf(" (%s)", description
);
457 /* Show interface name for the entry if we show
458 * entries for all interfaces */
460 char name
[IF_NAMESIZE
+1];
462 if (if_indextoname(local
[i
].ifindex
, name
)) {
463 fputs(" on ", stdout
);
466 printf(" on %%%i", local
[i
].ifindex
);
475 static int dump_addresses(
480 _cleanup_free_
struct local_address
*local
= NULL
;
486 n
= local_addresses(rtnl
, ifindex
, AF_UNSPEC
, &local
);
490 for (i
= 0; i
< n
; i
++) {
491 _cleanup_free_
char *pretty
= NULL
;
493 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &pretty
);
498 (int) strlen(prefix
),
499 i
== 0 ? prefix
: "",
503 char name
[IF_NAMESIZE
+1];
505 if (if_indextoname(local
[i
].ifindex
, name
)) {
506 fputs(" on ", stdout
);
509 printf(" on %%%i", local
[i
].ifindex
);
518 static int dump_address_labels(sd_netlink
*rtnl
) {
519 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
520 sd_netlink_message
*m
;
525 r
= sd_rtnl_message_new_addrlabel(rtnl
, &req
, RTM_GETADDRLABEL
, 0, AF_INET6
);
527 return log_error_errno(r
, "Could not allocate RTM_GETADDRLABEL message: %m");
529 r
= sd_netlink_message_request_dump(req
, true);
533 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
537 printf("%10s/%s %30s\n", "Prefix", "Prefixlen", "Label");
539 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
540 _cleanup_free_
char *pretty
= NULL
;
541 union in_addr_union prefix
= IN_ADDR_NULL
;
545 r
= sd_netlink_message_get_errno(m
);
547 log_error_errno(r
, "got error: %m");
551 r
= sd_netlink_message_read_u32(m
, IFAL_LABEL
, &label
);
552 if (r
< 0 && r
!= -ENODATA
) {
553 log_error_errno(r
, "Could not read IFAL_LABEL, ignoring: %m");
557 r
= sd_netlink_message_read_in6_addr(m
, IFAL_ADDRESS
, &prefix
.in6
);
561 r
= in_addr_to_string(AF_INET6
, &prefix
, &pretty
);
565 r
= sd_rtnl_message_addrlabel_get_prefixlen(m
, &prefixlen
);
569 printf("%10s/%-5u %30u\n", pretty
, prefixlen
, label
);
575 static int list_address_labels(int argc
, char *argv
[], void *userdata
) {
576 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
579 r
= sd_netlink_open(&rtnl
);
581 return log_error_errno(r
, "Failed to connect to netlink: %m");
583 dump_address_labels(rtnl
);
588 static int open_lldp_neighbors(int ifindex
, FILE **ret
) {
589 _cleanup_free_
char *p
= NULL
;
592 if (asprintf(&p
, "/run/systemd/netif/lldp/%i", ifindex
) < 0)
603 static int next_lldp_neighbor(FILE *f
, sd_lldp_neighbor
**ret
) {
604 _cleanup_free_
void *raw
= NULL
;
612 l
= fread(&u
, 1, sizeof(u
), f
);
613 if (l
== 0 && feof(f
))
618 /* each LLDP packet is at most MTU size, but let's allow up to 4KiB just in case */
619 if (le64toh(u
) >= 4096)
622 raw
= new(uint8_t, le64toh(u
));
626 if (fread(raw
, 1, le64toh(u
), f
) != le64toh(u
))
629 r
= sd_lldp_neighbor_from_raw(ret
, raw
, le64toh(u
));
636 static int dump_lldp_neighbors(const char *prefix
, int ifindex
) {
637 _cleanup_fclose_
FILE *f
= NULL
;
643 r
= open_lldp_neighbors(ifindex
, &f
);
648 const char *system_name
= NULL
, *port_id
= NULL
, *port_description
= NULL
;
649 _cleanup_(sd_lldp_neighbor_unrefp
) sd_lldp_neighbor
*n
= NULL
;
651 r
= next_lldp_neighbor(f
, &n
);
658 (int) strlen(prefix
),
659 c
== 0 ? prefix
: "");
661 (void) sd_lldp_neighbor_get_system_name(n
, &system_name
);
662 (void) sd_lldp_neighbor_get_port_id_as_string(n
, &port_id
);
663 (void) sd_lldp_neighbor_get_port_description(n
, &port_description
);
665 printf("%s on port %s", strna(system_name
), strna(port_id
));
667 if (!isempty(port_description
))
668 printf(" (%s)", port_description
);
678 static void dump_ifindexes(const char *prefix
, const int *ifindexes
) {
683 if (!ifindexes
|| ifindexes
[0] <= 0)
686 for (c
= 0; ifindexes
[c
] > 0; c
++) {
687 char name
[IF_NAMESIZE
+1];
690 (int) strlen(prefix
),
691 c
== 0 ? prefix
: "");
693 if (if_indextoname(ifindexes
[c
], name
))
696 printf("%i", ifindexes
[c
]);
702 static void dump_list(const char *prefix
, char **l
) {
710 (int) strlen(prefix
),
711 i
== l
? prefix
: "",
716 static int link_status_one(
719 const LinkInfo
*info
) {
721 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **search_domains
= NULL
, **route_domains
= NULL
;
722 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
, *tz
= NULL
;
723 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
724 char devid
[2 + DECIMAL_STR_MAX(int)];
725 _cleanup_free_
char *t
= NULL
, *network
= NULL
;
726 const char *driver
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *link
= NULL
;
727 const char *on_color_operational
, *off_color_operational
,
728 *on_color_setup
, *off_color_setup
;
729 _cleanup_free_
int *carrier_bound_to
= NULL
, *carrier_bound_by
= NULL
;
735 (void) sd_network_link_get_operational_state(info
->ifindex
, &operational_state
);
736 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
738 r
= sd_network_link_get_setup_state(info
->ifindex
, &setup_state
);
739 if (r
== -ENODATA
) /* If there's no info available about this iface, it's unmanaged by networkd */
740 setup_state
= strdup("unmanaged");
741 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
743 (void) sd_network_link_get_dns(info
->ifindex
, &dns
);
744 (void) sd_network_link_get_search_domains(info
->ifindex
, &search_domains
);
745 (void) sd_network_link_get_route_domains(info
->ifindex
, &route_domains
);
746 (void) sd_network_link_get_ntp(info
->ifindex
, &ntp
);
748 xsprintf(devid
, "n%i", info
->ifindex
);
750 (void) sd_device_new_from_device_id(&d
, devid
);
753 (void) sd_device_get_property_value(d
, "ID_NET_LINK_FILE", &link
);
754 (void) sd_device_get_property_value(d
, "ID_NET_DRIVER", &driver
);
755 (void) sd_device_get_property_value(d
, "ID_PATH", &path
);
757 if (sd_device_get_property_value(d
, "ID_VENDOR_FROM_DATABASE", &vendor
) < 0)
758 (void) sd_device_get_property_value(d
, "ID_VENDOR", &vendor
);
760 if (sd_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE", &model
) < 0)
761 (void) sd_device_get_property_value(d
, "ID_MODEL", &model
);
764 t
= link_get_type_string(info
->iftype
, d
);
766 (void) sd_network_link_get_network_file(info
->ifindex
, &network
);
768 (void) sd_network_link_get_carrier_bound_to(info
->ifindex
, &carrier_bound_to
);
769 (void) sd_network_link_get_carrier_bound_by(info
->ifindex
, &carrier_bound_by
);
771 printf("%s%s%s %i: %s\n", on_color_operational
, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE
), off_color_operational
, info
->ifindex
, info
->name
);
773 printf(" Link File: %s\n"
774 " Network File: %s\n"
776 " State: %s%s%s (%s%s%s)\n",
780 on_color_operational
, strna(operational_state
), off_color_operational
,
781 on_color_setup
, strna(setup_state
), off_color_setup
);
784 printf(" Path: %s\n", path
);
786 printf(" Driver: %s\n", driver
);
788 printf(" Vendor: %s\n", vendor
);
790 printf(" Model: %s\n", model
);
792 if (info
->has_mac_address
) {
793 _cleanup_free_
char *description
= NULL
;
794 char ea
[ETHER_ADDR_TO_STRING_MAX
];
796 (void) ieee_oui(hwdb
, &info
->mac_address
, &description
);
799 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info
->mac_address
, ea
), description
);
801 printf(" HW Address: %s\n", ether_addr_to_string(&info
->mac_address
, ea
));
805 printf(" MTU: %" PRIu32
"\n", info
->mtu
);
806 if (info
->has_min_mtu
)
807 printf(" Minimum MTU: %" PRIu32
"\n", info
->min_mtu
);
808 if (info
->has_max_mtu
)
809 printf(" Maximum MTU: %" PRIu32
"\n", info
->max_mtu
);
811 if (info
->has_tx_queues
)
812 printf("Transmit Queue Length: %" PRIu32
"\n", info
->tx_queues
);
813 if (info
->has_rx_queues
)
814 printf(" Receive Queue Length: %" PRIu32
"\n", info
->rx_queues
);
816 (void) dump_addresses(rtnl
, " Address: ", info
->ifindex
);
817 (void) dump_gateways(rtnl
, hwdb
, " Gateway: ", info
->ifindex
);
819 dump_list(" DNS: ", dns
);
820 dump_list(" Search Domains: ", search_domains
);
821 dump_list(" Route Domains: ", route_domains
);
823 dump_list(" NTP: ", ntp
);
825 dump_ifindexes("Carrier Bound To: ", carrier_bound_to
);
826 dump_ifindexes("Carrier Bound By: ", carrier_bound_by
);
828 (void) sd_network_link_get_timezone(info
->ifindex
, &tz
);
830 printf(" Time Zone: %s\n", tz
);
832 (void) dump_lldp_neighbors(" Connected To: ", info
->ifindex
);
837 static int system_status(sd_netlink
*rtnl
, sd_hwdb
*hwdb
) {
838 _cleanup_free_
char *operational_state
= NULL
;
839 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **search_domains
= NULL
, **route_domains
= NULL
;
840 const char *on_color_operational
, *off_color_operational
;
844 (void) sd_network_get_operational_state(&operational_state
);
845 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
847 printf("%s%s%s State: %s%s%s\n",
848 on_color_operational
, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE
), off_color_operational
,
849 on_color_operational
, strna(operational_state
), off_color_operational
);
851 (void) dump_addresses(rtnl
, " Address: ", 0);
852 (void) dump_gateways(rtnl
, hwdb
, " Gateway: ", 0);
854 (void) sd_network_get_dns(&dns
);
855 dump_list(" DNS: ", dns
);
857 (void) sd_network_get_search_domains(&search_domains
);
858 dump_list("Search Domains: ", search_domains
);
860 (void) sd_network_get_route_domains(&route_domains
);
861 dump_list(" Route Domains: ", route_domains
);
863 (void) sd_network_get_ntp(&ntp
);
864 dump_list(" NTP: ", ntp
);
869 static int link_status(int argc
, char *argv
[], void *userdata
) {
870 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
871 _cleanup_(sd_hwdb_unrefp
) sd_hwdb
*hwdb
= NULL
;
872 _cleanup_free_ LinkInfo
*links
= NULL
;
875 (void) pager_open(arg_pager_flags
);
877 r
= sd_netlink_open(&rtnl
);
879 return log_error_errno(r
, "Failed to connect to netlink: %m");
881 r
= sd_hwdb_new(&hwdb
);
883 log_debug_errno(r
, "Failed to open hardware database: %m");
886 c
= acquire_link_info(rtnl
, NULL
, &links
);
888 return system_status(rtnl
, hwdb
);
890 c
= acquire_link_info(rtnl
, argv
+ 1, &links
);
894 for (i
= 0; i
< c
; i
++) {
898 link_status_one(rtnl
, hwdb
, links
+ i
);
904 static char *lldp_capabilities_to_string(uint16_t x
) {
905 static const char characters
[] = {
906 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
911 ret
= new(char, ELEMENTSOF(characters
) + 1);
915 for (i
= 0; i
< ELEMENTSOF(characters
); i
++)
916 ret
[i
] = (x
& (1U << i
)) ? characters
[i
] : '.';
922 static void lldp_capabilities_legend(uint16_t x
) {
923 unsigned w
, i
, cols
= columns();
924 static const char* const table
[] = {
928 "w - WLAN Access Point",
931 "d - DOCSIS cable device",
935 "m - Two-port MAC Relay (TPMR)",
941 printf("\nCapability Flags:\n");
942 for (w
= 0, i
= 0; i
< ELEMENTSOF(table
); i
++)
943 if (x
& (1U << i
) || arg_all
) {
946 newline
= w
+ strlen(table
[i
]) + (w
== 0 ? 0 : 2) > cols
;
949 w
+= printf("%s%s%s", newline
? "\n" : "", w
== 0 ? "" : "; ", table
[i
]);
954 static int link_lldp_status(int argc
, char *argv
[], void *userdata
) {
955 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
956 _cleanup_free_ LinkInfo
*links
= NULL
;
960 r
= sd_netlink_open(&rtnl
);
962 return log_error_errno(r
, "Failed to connect to netlink: %m");
964 c
= acquire_link_info(rtnl
, argc
> 1 ? argv
+ 1 : NULL
, &links
);
968 (void) pager_open(arg_pager_flags
);
971 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
979 for (i
= 0; i
< c
; i
++) {
980 _cleanup_fclose_
FILE *f
= NULL
;
982 r
= open_lldp_neighbors(links
[i
].ifindex
, &f
);
986 log_warning_errno(r
, "Failed to open LLDP data for %i, ignoring: %m", links
[i
].ifindex
);
991 _cleanup_free_
char *cid
= NULL
, *pid
= NULL
, *sname
= NULL
, *pdesc
= NULL
;
992 const char *chassis_id
= NULL
, *port_id
= NULL
, *system_name
= NULL
, *port_description
= NULL
, *capabilities
= NULL
;
993 _cleanup_(sd_lldp_neighbor_unrefp
) sd_lldp_neighbor
*n
= NULL
;
996 r
= next_lldp_neighbor(f
, &n
);
998 log_warning_errno(r
, "Failed to read neighbor data: %m");
1004 (void) sd_lldp_neighbor_get_chassis_id_as_string(n
, &chassis_id
);
1005 (void) sd_lldp_neighbor_get_port_id_as_string(n
, &port_id
);
1006 (void) sd_lldp_neighbor_get_system_name(n
, &system_name
);
1007 (void) sd_lldp_neighbor_get_port_description(n
, &port_description
);
1010 cid
= ellipsize(chassis_id
, 17, 100);
1016 pid
= ellipsize(port_id
, 17, 100);
1022 sname
= ellipsize(system_name
, 16, 100);
1024 system_name
= sname
;
1027 if (port_description
) {
1028 pdesc
= ellipsize(port_description
, 16, 100);
1030 port_description
= pdesc
;
1033 if (sd_lldp_neighbor_get_enabled_capabilities(n
, &cc
) >= 0) {
1034 capabilities
= lldp_capabilities_to_string(cc
);
1038 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
1042 strna(capabilities
),
1044 strna(port_description
));
1051 lldp_capabilities_legend(all
);
1052 printf("\n%i neighbors listed.\n", m
);
1058 static int help(void) {
1059 _cleanup_free_
char *link
= NULL
;
1062 r
= terminal_urlify_man("networkctl", "1", &link
);
1066 printf("%s [OPTIONS...]\n\n"
1067 "Query and control the networking subsystem.\n\n"
1068 " -h --help Show this help\n"
1069 " --version Show package version\n"
1070 " --no-pager Do not pipe output into a pager\n"
1071 " --no-legend Do not show the headers and footers\n"
1072 " -a --all Show status for all links\n\n"
1074 " list [PATTERN...] List links\n"
1075 " status [PATTERN...] Show link status\n"
1076 " lldp [PATTERN...] Show LLDP neighbors\n"
1077 " label Show current address label entries in the kernel\n"
1078 "\nSee the %s for details.\n"
1079 , program_invocation_short_name
1086 static int parse_argv(int argc
, char *argv
[]) {
1089 ARG_VERSION
= 0x100,
1094 static const struct option options
[] = {
1095 { "help", no_argument
, NULL
, 'h' },
1096 { "version", no_argument
, NULL
, ARG_VERSION
},
1097 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1098 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1099 { "all", no_argument
, NULL
, 'a' },
1108 while ((c
= getopt_long(argc
, argv
, "ha", options
, NULL
)) >= 0) {
1119 arg_pager_flags
|= PAGER_DISABLE
;
1134 assert_not_reached("Unhandled option");
1141 static int networkctl_main(int argc
, char *argv
[]) {
1142 static const Verb verbs
[] = {
1143 { "list", VERB_ANY
, VERB_ANY
, VERB_DEFAULT
, list_links
},
1144 { "status", VERB_ANY
, VERB_ANY
, 0, link_status
},
1145 { "lldp", VERB_ANY
, VERB_ANY
, 0, link_lldp_status
},
1146 { "label", VERB_ANY
, VERB_ANY
, 0, list_address_labels
},
1150 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1153 static void warn_networkd_missing(void) {
1155 if (access("/run/systemd/netif/state", F_OK
) >= 0)
1158 fprintf(stderr
, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
1161 static int run(int argc
, char* argv
[]) {
1164 log_show_color(true);
1165 log_parse_environment();
1168 r
= parse_argv(argc
, argv
);
1172 warn_networkd_missing();
1174 return networkctl_main(argc
, argv
);
1177 DEFINE_MAIN_FUNCTION(run
);