1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/if_addrlabel.h>
26 #include "sd-device.h"
29 #include "sd-netlink.h"
30 #include "sd-network.h"
32 #include "alloc-util.h"
33 #include "arphrd-list.h"
34 #include "device-util.h"
35 #include "ether-addr-util.h"
37 #include "hwdb-util.h"
38 #include "local-addresses.h"
39 #include "locale-util.h"
41 #include "netlink-util.h"
43 #include "parse-util.h"
44 #include "socket-util.h"
45 #include "sparse-endian.h"
46 #include "stdio-util.h"
47 #include "string-table.h"
48 #include "string-util.h"
51 #include "terminal-util.h"
55 static bool arg_no_pager
= false;
56 static bool arg_legend
= true;
57 static bool arg_all
= false;
59 static int link_get_type_string(unsigned short iftype
, sd_device
*d
, char **ret
) {
65 if (iftype
== ARPHRD_ETHER
&& d
) {
66 const char *devtype
= NULL
, *id
= NULL
;
67 /* WLANs have iftype ARPHRD_ETHER, but we want
68 * to show a more useful type string for
71 (void) sd_device_get_devtype(d
, &devtype
);
73 if (streq_ptr(devtype
, "wlan"))
75 else if (streq_ptr(devtype
, "wwan"))
88 t
= arphrd_to_name(iftype
);
104 static void operational_state_to_color(const char *state
, const char **on
, const char **off
) {
108 if (streq_ptr(state
, "routable")) {
109 *on
= ansi_highlight_green();
110 *off
= ansi_normal();
111 } else if (streq_ptr(state
, "degraded")) {
112 *on
= ansi_highlight_yellow();
113 *off
= ansi_normal();
118 static void setup_state_to_color(const char *state
, const char **on
, const char **off
) {
122 if (streq_ptr(state
, "configured")) {
123 *on
= ansi_highlight_green();
124 *off
= ansi_normal();
125 } else if (streq_ptr(state
, "configuring")) {
126 *on
= ansi_highlight_yellow();
127 *off
= ansi_normal();
128 } else if (STRPTR_IN_SET(state
, "failed", "linger")) {
129 *on
= ansi_highlight_red();
130 *off
= ansi_normal();
135 typedef struct LinkInfo
{
136 char name
[IFNAMSIZ
+1];
138 unsigned short iftype
;
139 struct ether_addr mac_address
;
142 bool has_mac_address
:1;
146 static int link_info_compare(const void *a
, const void *b
) {
147 const LinkInfo
*x
= a
, *y
= b
;
149 return x
->ifindex
- y
->ifindex
;
152 static int decode_link(sd_netlink_message
*m
, LinkInfo
*info
) {
160 r
= sd_netlink_message_get_type(m
, &type
);
164 if (type
!= RTM_NEWLINK
)
167 r
= sd_rtnl_message_link_get_ifindex(m
, &info
->ifindex
);
171 r
= sd_netlink_message_read_string(m
, IFLA_IFNAME
, &name
);
175 r
= sd_rtnl_message_link_get_type(m
, &info
->iftype
);
179 strscpy(info
->name
, sizeof info
->name
, name
);
181 info
->has_mac_address
=
182 sd_netlink_message_read_ether_addr(m
, IFLA_ADDRESS
, &info
->mac_address
) >= 0 &&
183 memcmp(&info
->mac_address
, ÐER_ADDR_NULL
, sizeof(struct ether_addr
)) != 0;
186 sd_netlink_message_read_u32(m
, IFLA_MTU
, &info
->mtu
) &&
192 static int acquire_link_info_strv(sd_netlink
*rtnl
, char **l
, LinkInfo
**ret
) {
193 _cleanup_free_ LinkInfo
*links
= NULL
;
201 links
= new(LinkInfo
, strv_length(l
));
206 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
209 if (parse_ifindex(*i
, &ifindex
) >= 0)
210 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, ifindex
);
212 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
214 return rtnl_log_create_error(r
);
216 r
= sd_netlink_message_append_string(req
, IFLA_IFNAME
, *i
);
219 return rtnl_log_create_error(r
);
221 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
223 return log_error_errno(r
, "Failed to request link: %m");
225 r
= decode_link(reply
, links
+ c
);
232 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
240 static int acquire_link_info_all(sd_netlink
*rtnl
, LinkInfo
**ret
) {
241 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
242 _cleanup_free_ LinkInfo
*links
= NULL
;
243 size_t allocated
= 0, c
= 0;
244 sd_netlink_message
*i
;
250 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
252 return rtnl_log_create_error(r
);
254 r
= sd_netlink_message_request_dump(req
, true);
256 return rtnl_log_create_error(r
);
258 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
260 return log_error_errno(r
, "Failed to enumerate links: %m");
262 for (i
= reply
; i
; i
= sd_netlink_message_next(i
)) {
263 if (!GREEDY_REALLOC(links
, allocated
, c
+1))
266 r
= decode_link(i
, links
+ c
);
273 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
281 static int list_links(int argc
, char *argv
[], void *userdata
) {
282 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
283 _cleanup_free_ LinkInfo
*links
= NULL
;
286 r
= sd_netlink_open(&rtnl
);
288 return log_error_errno(r
, "Failed to connect to netlink: %m");
291 c
= acquire_link_info_strv(rtnl
, argv
+ 1, &links
);
293 c
= acquire_link_info_all(rtnl
, &links
);
297 pager_open(arg_no_pager
, false);
300 printf("%3s %-16s %-18s %-11s %-10s\n",
307 for (i
= 0; i
< c
; i
++) {
308 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
;
309 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
310 const char *on_color_operational
, *off_color_operational
,
311 *on_color_setup
, *off_color_setup
;
312 char devid
[2 + DECIMAL_STR_MAX(int)];
313 _cleanup_free_
char *t
= NULL
;
315 (void) sd_network_link_get_operational_state(links
[i
].ifindex
, &operational_state
);
316 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
318 r
= sd_network_link_get_setup_state(links
[i
].ifindex
, &setup_state
);
319 if (r
== -ENODATA
) /* If there's no info available about this iface, it's unmanaged by networkd */
320 setup_state
= strdup("unmanaged");
321 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
323 xsprintf(devid
, "n%i", links
[i
].ifindex
);
324 (void) sd_device_new_from_device_id(&d
, devid
);
326 (void) link_get_type_string(links
[i
].iftype
, d
, &t
);
328 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
329 links
[i
].ifindex
, links
[i
].name
, strna(t
),
330 on_color_operational
, strna(operational_state
), off_color_operational
,
331 on_color_setup
, strna(setup_state
), off_color_setup
);
335 printf("\n%i links listed.\n", c
);
340 /* IEEE Organizationally Unique Identifier vendor string */
341 static int ieee_oui(sd_hwdb
*hwdb
, const struct ether_addr
*mac
, char **ret
) {
342 const char *description
;
343 char modalias
[strlen("OUI:XXYYXXYYXXYY") + 1], *desc
;
354 /* skip commonly misused 00:00:00 (Xerox) prefix */
355 if (memcmp(mac
, "\0\0\0", 3) == 0)
358 xsprintf(modalias
, "OUI:" ETHER_ADDR_FORMAT_STR
,
359 ETHER_ADDR_FORMAT_VAL(*mac
));
361 r
= sd_hwdb_get(hwdb
, modalias
, "ID_OUI_FROM_DATABASE", &description
);
365 desc
= strdup(description
);
374 static int get_gateway_description(
379 union in_addr_union
*gateway
,
380 char **gateway_description
) {
381 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
382 sd_netlink_message
*m
;
386 assert(ifindex
>= 0);
387 assert(IN_SET(family
, AF_INET
, AF_INET6
));
389 assert(gateway_description
);
391 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_GETNEIGH
, ifindex
, family
);
395 r
= sd_netlink_message_request_dump(req
, true);
399 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
403 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
404 union in_addr_union gw
= {};
405 struct ether_addr mac
= {};
409 r
= sd_netlink_message_get_errno(m
);
411 log_error_errno(r
, "got error: %m");
415 r
= sd_netlink_message_get_type(m
, &type
);
417 log_error_errno(r
, "could not get type: %m");
421 if (type
!= RTM_NEWNEIGH
) {
422 log_error("type is not RTM_NEWNEIGH");
426 r
= sd_rtnl_message_neigh_get_family(m
, &fam
);
428 log_error_errno(r
, "could not get family: %m");
433 log_error("family is not correct");
437 r
= sd_rtnl_message_neigh_get_ifindex(m
, &ifi
);
439 log_error_errno(r
, "could not get ifindex: %m");
443 if (ifindex
> 0 && ifi
!= ifindex
)
448 r
= sd_netlink_message_read_in_addr(m
, NDA_DST
, &gw
.in
);
454 r
= sd_netlink_message_read_in6_addr(m
, NDA_DST
, &gw
.in6
);
463 if (!in_addr_equal(fam
, &gw
, gateway
))
466 r
= sd_netlink_message_read_ether_addr(m
, NDA_LLADDR
, &mac
);
470 r
= ieee_oui(hwdb
, &mac
, gateway_description
);
480 static int dump_gateways(
485 _cleanup_free_
struct local_address
*local
= NULL
;
491 n
= local_gateways(rtnl
, ifindex
, AF_UNSPEC
, &local
);
495 for (i
= 0; i
< n
; i
++) {
496 _cleanup_free_
char *gateway
= NULL
, *description
= NULL
;
498 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &gateway
);
502 r
= get_gateway_description(rtnl
, hwdb
, local
[i
].ifindex
, local
[i
].family
, &local
[i
].address
, &description
);
504 log_debug_errno(r
, "Could not get description of gateway: %m");
507 (int) strlen(prefix
),
508 i
== 0 ? prefix
: "",
512 printf(" (%s)", description
);
514 /* Show interface name for the entry if we show
515 * entries for all interfaces */
517 char name
[IF_NAMESIZE
+1];
519 if (if_indextoname(local
[i
].ifindex
, name
)) {
520 fputs(" on ", stdout
);
523 printf(" on %%%i", local
[i
].ifindex
);
532 static int dump_addresses(
537 _cleanup_free_
struct local_address
*local
= NULL
;
543 n
= local_addresses(rtnl
, ifindex
, AF_UNSPEC
, &local
);
547 for (i
= 0; i
< n
; i
++) {
548 _cleanup_free_
char *pretty
= NULL
;
550 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &pretty
);
555 (int) strlen(prefix
),
556 i
== 0 ? prefix
: "",
560 char name
[IF_NAMESIZE
+1];
562 if (if_indextoname(local
[i
].ifindex
, name
)) {
563 fputs(" on ", stdout
);
566 printf(" on %%%i", local
[i
].ifindex
);
575 static int dump_address_labels(sd_netlink
*rtnl
) {
576 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
577 sd_netlink_message
*m
;
582 r
= sd_rtnl_message_new_addrlabel(rtnl
, &req
, RTM_GETADDRLABEL
, 0, AF_INET6
);
584 return log_error_errno(r
, "Could not allocate RTM_GETADDRLABEL message: %m");
586 r
= sd_netlink_message_request_dump(req
, true);
590 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
594 printf("%10s/%s %30s\n", "Prefix", "Prefixlen", "Label");
596 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
597 _cleanup_free_
char *pretty
= NULL
;
598 union in_addr_union prefix
= {};
602 r
= sd_netlink_message_get_errno(m
);
604 log_error_errno(r
, "got error: %m");
608 r
= sd_netlink_message_read_u32(m
, IFAL_LABEL
, &label
);
609 if (r
< 0 && r
!= -ENODATA
) {
610 log_error_errno(r
, "Could not read IFAL_LABEL, ignoring: %m");
614 r
= sd_netlink_message_read_in6_addr(m
, IFAL_ADDRESS
, &prefix
.in6
);
618 r
= in_addr_to_string(AF_INET6
, &prefix
, &pretty
);
622 r
= sd_rtnl_message_addrlabel_get_prefixlen(m
, &prefixlen
);
626 printf("%10s/%-5u %30u\n", pretty
, prefixlen
, label
);
632 static int list_address_labels(int argc
, char *argv
[], void *userdata
) {
633 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
636 r
= sd_netlink_open(&rtnl
);
638 return log_error_errno(r
, "Failed to connect to netlink: %m");
640 dump_address_labels(rtnl
);
645 static int open_lldp_neighbors(int ifindex
, FILE **ret
) {
646 _cleanup_free_
char *p
= NULL
;
649 if (asprintf(&p
, "/run/systemd/netif/lldp/%i", ifindex
) < 0)
660 static int next_lldp_neighbor(FILE *f
, sd_lldp_neighbor
**ret
) {
661 _cleanup_free_
void *raw
= NULL
;
669 l
= fread(&u
, 1, sizeof(u
), f
);
670 if (l
== 0 && feof(f
))
675 raw
= new(uint8_t, le64toh(u
));
679 if (fread(raw
, 1, le64toh(u
), f
) != le64toh(u
))
682 r
= sd_lldp_neighbor_from_raw(ret
, raw
, le64toh(u
));
689 static int dump_lldp_neighbors(const char *prefix
, int ifindex
) {
690 _cleanup_fclose_
FILE *f
= NULL
;
696 r
= open_lldp_neighbors(ifindex
, &f
);
701 const char *system_name
= NULL
, *port_id
= NULL
, *port_description
= NULL
;
702 _cleanup_(sd_lldp_neighbor_unrefp
) sd_lldp_neighbor
*n
= NULL
;
704 r
= next_lldp_neighbor(f
, &n
);
711 (int) strlen(prefix
),
712 c
== 0 ? prefix
: "");
714 (void) sd_lldp_neighbor_get_system_name(n
, &system_name
);
715 (void) sd_lldp_neighbor_get_port_id_as_string(n
, &port_id
);
716 (void) sd_lldp_neighbor_get_port_description(n
, &port_description
);
718 printf("%s on port %s", strna(system_name
), strna(port_id
));
720 if (!isempty(port_description
))
721 printf(" (%s)", port_description
);
731 static void dump_ifindexes(const char *prefix
, const int *ifindexes
) {
736 if (!ifindexes
|| ifindexes
[0] <= 0)
739 for (c
= 0; ifindexes
[c
] > 0; c
++) {
740 char name
[IF_NAMESIZE
+1];
743 (int) strlen(prefix
),
744 c
== 0 ? prefix
: "");
746 if (if_indextoname(ifindexes
[c
], name
))
749 printf("%i", ifindexes
[c
]);
755 static void dump_list(const char *prefix
, char **l
) {
763 (int) strlen(prefix
),
764 i
== l
? prefix
: "",
769 static int link_status_one(
772 const LinkInfo
*info
) {
774 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **search_domains
= NULL
, **route_domains
= NULL
;
775 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
, *tz
= NULL
;
776 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
777 char devid
[2 + DECIMAL_STR_MAX(int)];
778 _cleanup_free_
char *t
= NULL
, *network
= NULL
;
779 const char *driver
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *link
= NULL
;
780 const char *on_color_operational
, *off_color_operational
,
781 *on_color_setup
, *off_color_setup
;
782 _cleanup_free_
int *carrier_bound_to
= NULL
, *carrier_bound_by
= NULL
;
788 (void) sd_network_link_get_operational_state(info
->ifindex
, &operational_state
);
789 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
791 r
= sd_network_link_get_setup_state(info
->ifindex
, &setup_state
);
792 if (r
== -ENODATA
) /* If there's no info available about this iface, it's unmanaged by networkd */
793 setup_state
= strdup("unmanaged");
794 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
796 (void) sd_network_link_get_dns(info
->ifindex
, &dns
);
797 (void) sd_network_link_get_search_domains(info
->ifindex
, &search_domains
);
798 (void) sd_network_link_get_route_domains(info
->ifindex
, &route_domains
);
799 (void) sd_network_link_get_ntp(info
->ifindex
, &ntp
);
801 xsprintf(devid
, "n%i", info
->ifindex
);
803 (void) sd_device_new_from_device_id(&d
, devid
);
806 (void) sd_device_get_property_value(d
, "ID_NET_LINK_FILE", &link
);
807 (void) sd_device_get_property_value(d
, "ID_NET_DRIVER", &driver
);
808 (void) sd_device_get_property_value(d
, "ID_PATH", &path
);
810 r
= sd_device_get_property_value(d
, "ID_VENDOR_FROM_DATABASE", &vendor
);
812 (void) sd_device_get_property_value(d
, "ID_VENDOR", &vendor
);
814 r
= sd_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE", &model
);
816 (void) sd_device_get_property_value(d
, "ID_MODEL", &model
);
819 (void) link_get_type_string(info
->iftype
, d
, &t
);
821 (void) sd_network_link_get_network_file(info
->ifindex
, &network
);
823 (void) sd_network_link_get_carrier_bound_to(info
->ifindex
, &carrier_bound_to
);
824 (void) sd_network_link_get_carrier_bound_by(info
->ifindex
, &carrier_bound_by
);
826 printf("%s%s%s %i: %s\n", on_color_operational
, special_glyph(BLACK_CIRCLE
), off_color_operational
, info
->ifindex
, info
->name
);
828 printf(" Link File: %s\n"
829 " Network File: %s\n"
831 " State: %s%s%s (%s%s%s)\n",
835 on_color_operational
, strna(operational_state
), off_color_operational
,
836 on_color_setup
, strna(setup_state
), off_color_setup
);
839 printf(" Path: %s\n", path
);
841 printf(" Driver: %s\n", driver
);
843 printf(" Vendor: %s\n", vendor
);
845 printf(" Model: %s\n", model
);
847 if (info
->has_mac_address
) {
848 _cleanup_free_
char *description
= NULL
;
849 char ea
[ETHER_ADDR_TO_STRING_MAX
];
851 (void) ieee_oui(hwdb
, &info
->mac_address
, &description
);
854 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info
->mac_address
, ea
), description
);
856 printf(" HW Address: %s\n", ether_addr_to_string(&info
->mac_address
, ea
));
860 printf(" MTU: %u\n", info
->mtu
);
862 (void) dump_addresses(rtnl
, " Address: ", info
->ifindex
);
863 (void) dump_gateways(rtnl
, hwdb
, " Gateway: ", info
->ifindex
);
865 dump_list(" DNS: ", dns
);
866 dump_list(" Search Domains: ", search_domains
);
867 dump_list(" Route Domains: ", route_domains
);
869 dump_list(" NTP: ", ntp
);
871 dump_ifindexes("Carrier Bound To: ", carrier_bound_to
);
872 dump_ifindexes("Carrier Bound By: ", carrier_bound_by
);
874 (void) sd_network_link_get_timezone(info
->ifindex
, &tz
);
876 printf(" Time Zone: %s\n", tz
);
878 (void) dump_lldp_neighbors(" Connected To: ", info
->ifindex
);
883 static int system_status(sd_netlink
*rtnl
, sd_hwdb
*hwdb
) {
884 _cleanup_free_
char *operational_state
= NULL
;
885 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **search_domains
= NULL
, **route_domains
= NULL
;
886 const char *on_color_operational
, *off_color_operational
;
890 (void) sd_network_get_operational_state(&operational_state
);
891 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
893 printf("%s%s%s State: %s%s%s\n",
894 on_color_operational
, special_glyph(BLACK_CIRCLE
), off_color_operational
,
895 on_color_operational
, strna(operational_state
), off_color_operational
);
897 (void) dump_addresses(rtnl
, " Address: ", 0);
898 (void) dump_gateways(rtnl
, hwdb
, " Gateway: ", 0);
900 (void) sd_network_get_dns(&dns
);
901 dump_list(" DNS: ", dns
);
903 (void) sd_network_get_search_domains(&search_domains
);
904 dump_list("Search Domains: ", search_domains
);
906 (void) sd_network_get_route_domains(&route_domains
);
907 dump_list(" Route Domains: ", route_domains
);
909 (void) sd_network_get_ntp(&ntp
);
910 dump_list(" NTP: ", ntp
);
915 static int link_status(int argc
, char *argv
[], void *userdata
) {
916 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
917 _cleanup_(sd_hwdb_unrefp
) sd_hwdb
*hwdb
= NULL
;
918 _cleanup_free_ LinkInfo
*links
= NULL
;
921 pager_open(arg_no_pager
, false);
923 r
= sd_netlink_open(&rtnl
);
925 return log_error_errno(r
, "Failed to connect to netlink: %m");
927 r
= sd_hwdb_new(&hwdb
);
929 log_debug_errno(r
, "Failed to open hardware database: %m");
932 c
= acquire_link_info_all(rtnl
, &links
);
934 return system_status(rtnl
, hwdb
);
936 c
= acquire_link_info_strv(rtnl
, argv
+ 1, &links
);
940 for (i
= 0; i
< c
; i
++) {
944 link_status_one(rtnl
, hwdb
, links
+ i
);
950 static char *lldp_capabilities_to_string(uint16_t x
) {
951 static const char characters
[] = {
952 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
957 ret
= new(char, ELEMENTSOF(characters
) + 1);
961 for (i
= 0; i
< ELEMENTSOF(characters
); i
++)
962 ret
[i
] = (x
& (1U << i
)) ? characters
[i
] : '.';
968 static void lldp_capabilities_legend(uint16_t x
) {
969 unsigned w
, i
, cols
= columns();
970 static const char* const table
[] = {
974 "w - WLAN Access Point",
977 "d - DOCSIS cable device",
981 "m - Two-port MAC Relay (TPMR)",
987 printf("\nCapability Flags:\n");
988 for (w
= 0, i
= 0; i
< ELEMENTSOF(table
); i
++)
989 if (x
& (1U << i
) || arg_all
) {
992 newline
= w
+ strlen(table
[i
]) + (w
== 0 ? 0 : 2) > cols
;
995 w
+= printf("%s%s%s", newline
? "\n" : "", w
== 0 ? "" : "; ", table
[i
]);
1000 static int link_lldp_status(int argc
, char *argv
[], void *userdata
) {
1001 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
1002 _cleanup_free_ LinkInfo
*links
= NULL
;
1006 r
= sd_netlink_open(&rtnl
);
1008 return log_error_errno(r
, "Failed to connect to netlink: %m");
1011 c
= acquire_link_info_strv(rtnl
, argv
+ 1, &links
);
1013 c
= acquire_link_info_all(rtnl
, &links
);
1017 pager_open(arg_no_pager
, false);
1020 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
1026 "PORT DESCRIPTION");
1028 for (i
= 0; i
< c
; i
++) {
1029 _cleanup_fclose_
FILE *f
= NULL
;
1031 r
= open_lldp_neighbors(links
[i
].ifindex
, &f
);
1035 log_warning_errno(r
, "Failed to open LLDP data for %i, ignoring: %m", links
[i
].ifindex
);
1040 _cleanup_free_
char *cid
= NULL
, *pid
= NULL
, *sname
= NULL
, *pdesc
= NULL
;
1041 const char *chassis_id
= NULL
, *port_id
= NULL
, *system_name
= NULL
, *port_description
= NULL
, *capabilities
= NULL
;
1042 _cleanup_(sd_lldp_neighbor_unrefp
) sd_lldp_neighbor
*n
= NULL
;
1045 r
= next_lldp_neighbor(f
, &n
);
1047 log_warning_errno(r
, "Failed to read neighbor data: %m");
1053 (void) sd_lldp_neighbor_get_chassis_id_as_string(n
, &chassis_id
);
1054 (void) sd_lldp_neighbor_get_port_id_as_string(n
, &port_id
);
1055 (void) sd_lldp_neighbor_get_system_name(n
, &system_name
);
1056 (void) sd_lldp_neighbor_get_port_description(n
, &port_description
);
1059 cid
= ellipsize(chassis_id
, 17, 100);
1065 pid
= ellipsize(port_id
, 17, 100);
1071 sname
= ellipsize(system_name
, 16, 100);
1073 system_name
= sname
;
1076 if (port_description
) {
1077 pdesc
= ellipsize(port_description
, 16, 100);
1079 port_description
= pdesc
;
1082 if (sd_lldp_neighbor_get_enabled_capabilities(n
, &cc
) >= 0) {
1083 capabilities
= lldp_capabilities_to_string(cc
);
1087 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
1091 strna(capabilities
),
1093 strna(port_description
));
1100 lldp_capabilities_legend(all
);
1101 printf("\n%i neighbors listed.\n", m
);
1107 static void help(void) {
1108 printf("%s [OPTIONS...]\n\n"
1109 "Query and control the networking subsystem.\n\n"
1110 " -h --help Show this help\n"
1111 " --version Show package version\n"
1112 " --no-pager Do not pipe output into a pager\n"
1113 " --no-legend Do not show the headers and footers\n"
1114 " -a --all Show status for all links\n\n"
1116 " list [LINK...] List links\n"
1117 " status [LINK...] Show link status\n"
1118 " lldp [LINK...] Show LLDP neighbors\n"
1119 " label Show current address label entries in the kernel\n"
1120 , program_invocation_short_name
);
1123 static int parse_argv(int argc
, char *argv
[]) {
1126 ARG_VERSION
= 0x100,
1131 static const struct option options
[] = {
1132 { "help", no_argument
, NULL
, 'h' },
1133 { "version", no_argument
, NULL
, ARG_VERSION
},
1134 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1135 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1136 { "all", no_argument
, NULL
, 'a' },
1145 while ((c
= getopt_long(argc
, argv
, "ha", options
, NULL
)) >= 0) {
1157 arg_no_pager
= true;
1172 assert_not_reached("Unhandled option");
1179 static int networkctl_main(int argc
, char *argv
[]) {
1180 const Verb verbs
[] = {
1181 { "list", VERB_ANY
, VERB_ANY
, VERB_DEFAULT
, list_links
},
1182 { "status", VERB_ANY
, VERB_ANY
, 0, link_status
},
1183 { "lldp", VERB_ANY
, VERB_ANY
, 0, link_lldp_status
},
1184 { "label", VERB_ANY
, VERB_ANY
, 0, list_address_labels
},
1188 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1191 static void warn_networkd_missing(void) {
1193 if (access("/run/systemd/netif/state", F_OK
) >= 0)
1196 fprintf(stderr
, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
1199 int main(int argc
, char* argv
[]) {
1202 log_parse_environment();
1205 r
= parse_argv(argc
, argv
);
1209 warn_networkd_missing();
1211 r
= networkctl_main(argc
, argv
);
1216 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;