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 char *link_get_type_string(unsigned short iftype
, sd_device
*d
) {
64 const char *devtype
= NULL
;
66 (void) sd_device_get_devtype(d
, &devtype
);
67 if (!isempty(devtype
))
68 return strdup(devtype
);
71 t
= arphrd_to_name(iftype
);
83 static void operational_state_to_color(const char *state
, const char **on
, const char **off
) {
87 if (streq_ptr(state
, "routable")) {
88 *on
= ansi_highlight_green();
90 } else if (streq_ptr(state
, "degraded")) {
91 *on
= ansi_highlight_yellow();
97 static void setup_state_to_color(const char *state
, const char **on
, const char **off
) {
101 if (streq_ptr(state
, "configured")) {
102 *on
= ansi_highlight_green();
103 *off
= ansi_normal();
104 } else if (streq_ptr(state
, "configuring")) {
105 *on
= ansi_highlight_yellow();
106 *off
= ansi_normal();
107 } else if (STRPTR_IN_SET(state
, "failed", "linger")) {
108 *on
= ansi_highlight_red();
109 *off
= ansi_normal();
114 typedef struct LinkInfo
{
115 char name
[IFNAMSIZ
+1];
117 unsigned short iftype
;
118 struct ether_addr mac_address
;
121 bool has_mac_address
:1;
125 static int link_info_compare(const void *a
, const void *b
) {
126 const LinkInfo
*x
= a
, *y
= b
;
128 return x
->ifindex
- y
->ifindex
;
131 static int decode_link(sd_netlink_message
*m
, LinkInfo
*info
) {
139 r
= sd_netlink_message_get_type(m
, &type
);
143 if (type
!= RTM_NEWLINK
)
146 r
= sd_rtnl_message_link_get_ifindex(m
, &info
->ifindex
);
150 r
= sd_netlink_message_read_string(m
, IFLA_IFNAME
, &name
);
154 r
= sd_rtnl_message_link_get_type(m
, &info
->iftype
);
158 strscpy(info
->name
, sizeof info
->name
, name
);
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
) &&
171 static int acquire_link_info_strv(sd_netlink
*rtnl
, char **l
, LinkInfo
**ret
) {
172 _cleanup_free_ LinkInfo
*links
= NULL
;
180 links
= new(LinkInfo
, strv_length(l
));
185 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
188 if (parse_ifindex(*i
, &ifindex
) >= 0)
189 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, ifindex
);
191 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
193 return rtnl_log_create_error(r
);
195 r
= sd_netlink_message_append_string(req
, IFLA_IFNAME
, *i
);
198 return rtnl_log_create_error(r
);
200 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
202 return log_error_errno(r
, "Failed to request link: %m");
204 r
= decode_link(reply
, links
+ c
);
211 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
219 static int acquire_link_info_all(sd_netlink
*rtnl
, LinkInfo
**ret
) {
220 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
221 _cleanup_free_ LinkInfo
*links
= NULL
;
222 size_t allocated
= 0, c
= 0;
223 sd_netlink_message
*i
;
229 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
231 return rtnl_log_create_error(r
);
233 r
= sd_netlink_message_request_dump(req
, true);
235 return rtnl_log_create_error(r
);
237 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
239 return log_error_errno(r
, "Failed to enumerate links: %m");
241 for (i
= reply
; i
; i
= sd_netlink_message_next(i
)) {
242 if (!GREEDY_REALLOC(links
, allocated
, c
+1))
245 r
= decode_link(i
, links
+ c
);
252 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
260 static int list_links(int argc
, char *argv
[], void *userdata
) {
261 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
262 _cleanup_free_ LinkInfo
*links
= NULL
;
265 r
= sd_netlink_open(&rtnl
);
267 return log_error_errno(r
, "Failed to connect to netlink: %m");
270 c
= acquire_link_info_strv(rtnl
, argv
+ 1, &links
);
272 c
= acquire_link_info_all(rtnl
, &links
);
276 (void) pager_open(arg_no_pager
, false);
279 printf("%3s %-16s %-18s %-11s %-10s\n",
286 for (i
= 0; i
< c
; i
++) {
287 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
;
288 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
289 const char *on_color_operational
, *off_color_operational
,
290 *on_color_setup
, *off_color_setup
;
291 char devid
[2 + DECIMAL_STR_MAX(int)];
292 _cleanup_free_
char *t
= NULL
;
294 (void) sd_network_link_get_operational_state(links
[i
].ifindex
, &operational_state
);
295 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
297 r
= sd_network_link_get_setup_state(links
[i
].ifindex
, &setup_state
);
298 if (r
== -ENODATA
) /* If there's no info available about this iface, it's unmanaged by networkd */
299 setup_state
= strdup("unmanaged");
300 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
302 xsprintf(devid
, "n%i", links
[i
].ifindex
);
303 (void) sd_device_new_from_device_id(&d
, devid
);
305 t
= link_get_type_string(links
[i
].iftype
, d
);
307 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
308 links
[i
].ifindex
, links
[i
].name
, strna(t
),
309 on_color_operational
, strna(operational_state
), off_color_operational
,
310 on_color_setup
, strna(setup_state
), off_color_setup
);
314 printf("\n%i links listed.\n", c
);
319 /* IEEE Organizationally Unique Identifier vendor string */
320 static int ieee_oui(sd_hwdb
*hwdb
, const struct ether_addr
*mac
, char **ret
) {
321 const char *description
;
322 char modalias
[STRLEN("OUI:XXYYXXYYXXYY") + 1], *desc
;
333 /* skip commonly misused 00:00:00 (Xerox) prefix */
334 if (memcmp(mac
, "\0\0\0", 3) == 0)
337 xsprintf(modalias
, "OUI:" ETHER_ADDR_FORMAT_STR
,
338 ETHER_ADDR_FORMAT_VAL(*mac
));
340 r
= sd_hwdb_get(hwdb
, modalias
, "ID_OUI_FROM_DATABASE", &description
);
344 desc
= strdup(description
);
353 static int get_gateway_description(
358 union in_addr_union
*gateway
,
359 char **gateway_description
) {
360 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
361 sd_netlink_message
*m
;
365 assert(ifindex
>= 0);
366 assert(IN_SET(family
, AF_INET
, AF_INET6
));
368 assert(gateway_description
);
370 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_GETNEIGH
, ifindex
, family
);
374 r
= sd_netlink_message_request_dump(req
, true);
378 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
382 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
383 union in_addr_union gw
= {};
384 struct ether_addr mac
= {};
388 r
= sd_netlink_message_get_errno(m
);
390 log_error_errno(r
, "got error: %m");
394 r
= sd_netlink_message_get_type(m
, &type
);
396 log_error_errno(r
, "could not get type: %m");
400 if (type
!= RTM_NEWNEIGH
) {
401 log_error("type is not RTM_NEWNEIGH");
405 r
= sd_rtnl_message_neigh_get_family(m
, &fam
);
407 log_error_errno(r
, "could not get family: %m");
412 log_error("family is not correct");
416 r
= sd_rtnl_message_neigh_get_ifindex(m
, &ifi
);
418 log_error_errno(r
, "could not get ifindex: %m");
422 if (ifindex
> 0 && ifi
!= ifindex
)
427 r
= sd_netlink_message_read_in_addr(m
, NDA_DST
, &gw
.in
);
433 r
= sd_netlink_message_read_in6_addr(m
, NDA_DST
, &gw
.in6
);
442 if (!in_addr_equal(fam
, &gw
, gateway
))
445 r
= sd_netlink_message_read_ether_addr(m
, NDA_LLADDR
, &mac
);
449 r
= ieee_oui(hwdb
, &mac
, gateway_description
);
459 static int dump_gateways(
464 _cleanup_free_
struct local_address
*local
= NULL
;
470 n
= local_gateways(rtnl
, ifindex
, AF_UNSPEC
, &local
);
474 for (i
= 0; i
< n
; i
++) {
475 _cleanup_free_
char *gateway
= NULL
, *description
= NULL
;
477 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &gateway
);
481 r
= get_gateway_description(rtnl
, hwdb
, local
[i
].ifindex
, local
[i
].family
, &local
[i
].address
, &description
);
483 log_debug_errno(r
, "Could not get description of gateway: %m");
486 (int) strlen(prefix
),
487 i
== 0 ? prefix
: "",
491 printf(" (%s)", description
);
493 /* Show interface name for the entry if we show
494 * entries for all interfaces */
496 char name
[IF_NAMESIZE
+1];
498 if (if_indextoname(local
[i
].ifindex
, name
)) {
499 fputs(" on ", stdout
);
502 printf(" on %%%i", local
[i
].ifindex
);
511 static int dump_addresses(
516 _cleanup_free_
struct local_address
*local
= NULL
;
522 n
= local_addresses(rtnl
, ifindex
, AF_UNSPEC
, &local
);
526 for (i
= 0; i
< n
; i
++) {
527 _cleanup_free_
char *pretty
= NULL
;
529 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &pretty
);
534 (int) strlen(prefix
),
535 i
== 0 ? prefix
: "",
539 char name
[IF_NAMESIZE
+1];
541 if (if_indextoname(local
[i
].ifindex
, name
)) {
542 fputs(" on ", stdout
);
545 printf(" on %%%i", local
[i
].ifindex
);
554 static int dump_address_labels(sd_netlink
*rtnl
) {
555 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
556 sd_netlink_message
*m
;
561 r
= sd_rtnl_message_new_addrlabel(rtnl
, &req
, RTM_GETADDRLABEL
, 0, AF_INET6
);
563 return log_error_errno(r
, "Could not allocate RTM_GETADDRLABEL message: %m");
565 r
= sd_netlink_message_request_dump(req
, true);
569 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
573 printf("%10s/%s %30s\n", "Prefix", "Prefixlen", "Label");
575 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
576 _cleanup_free_
char *pretty
= NULL
;
577 union in_addr_union prefix
= {};
581 r
= sd_netlink_message_get_errno(m
);
583 log_error_errno(r
, "got error: %m");
587 r
= sd_netlink_message_read_u32(m
, IFAL_LABEL
, &label
);
588 if (r
< 0 && r
!= -ENODATA
) {
589 log_error_errno(r
, "Could not read IFAL_LABEL, ignoring: %m");
593 r
= sd_netlink_message_read_in6_addr(m
, IFAL_ADDRESS
, &prefix
.in6
);
597 r
= in_addr_to_string(AF_INET6
, &prefix
, &pretty
);
601 r
= sd_rtnl_message_addrlabel_get_prefixlen(m
, &prefixlen
);
605 printf("%10s/%-5u %30u\n", pretty
, prefixlen
, label
);
611 static int list_address_labels(int argc
, char *argv
[], void *userdata
) {
612 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
615 r
= sd_netlink_open(&rtnl
);
617 return log_error_errno(r
, "Failed to connect to netlink: %m");
619 dump_address_labels(rtnl
);
624 static int open_lldp_neighbors(int ifindex
, FILE **ret
) {
625 _cleanup_free_
char *p
= NULL
;
628 if (asprintf(&p
, "/run/systemd/netif/lldp/%i", ifindex
) < 0)
639 static int next_lldp_neighbor(FILE *f
, sd_lldp_neighbor
**ret
) {
640 _cleanup_free_
void *raw
= NULL
;
648 l
= fread(&u
, 1, sizeof(u
), f
);
649 if (l
== 0 && feof(f
))
654 raw
= new(uint8_t, le64toh(u
));
658 if (fread(raw
, 1, le64toh(u
), f
) != le64toh(u
))
661 r
= sd_lldp_neighbor_from_raw(ret
, raw
, le64toh(u
));
668 static int dump_lldp_neighbors(const char *prefix
, int ifindex
) {
669 _cleanup_fclose_
FILE *f
= NULL
;
675 r
= open_lldp_neighbors(ifindex
, &f
);
680 const char *system_name
= NULL
, *port_id
= NULL
, *port_description
= NULL
;
681 _cleanup_(sd_lldp_neighbor_unrefp
) sd_lldp_neighbor
*n
= NULL
;
683 r
= next_lldp_neighbor(f
, &n
);
690 (int) strlen(prefix
),
691 c
== 0 ? prefix
: "");
693 (void) sd_lldp_neighbor_get_system_name(n
, &system_name
);
694 (void) sd_lldp_neighbor_get_port_id_as_string(n
, &port_id
);
695 (void) sd_lldp_neighbor_get_port_description(n
, &port_description
);
697 printf("%s on port %s", strna(system_name
), strna(port_id
));
699 if (!isempty(port_description
))
700 printf(" (%s)", port_description
);
710 static void dump_ifindexes(const char *prefix
, const int *ifindexes
) {
715 if (!ifindexes
|| ifindexes
[0] <= 0)
718 for (c
= 0; ifindexes
[c
] > 0; c
++) {
719 char name
[IF_NAMESIZE
+1];
722 (int) strlen(prefix
),
723 c
== 0 ? prefix
: "");
725 if (if_indextoname(ifindexes
[c
], name
))
728 printf("%i", ifindexes
[c
]);
734 static void dump_list(const char *prefix
, char **l
) {
742 (int) strlen(prefix
),
743 i
== l
? prefix
: "",
748 static int link_status_one(
751 const LinkInfo
*info
) {
753 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **search_domains
= NULL
, **route_domains
= NULL
;
754 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
, *tz
= NULL
;
755 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
756 char devid
[2 + DECIMAL_STR_MAX(int)];
757 _cleanup_free_
char *t
= NULL
, *network
= NULL
;
758 const char *driver
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *link
= NULL
;
759 const char *on_color_operational
, *off_color_operational
,
760 *on_color_setup
, *off_color_setup
;
761 _cleanup_free_
int *carrier_bound_to
= NULL
, *carrier_bound_by
= NULL
;
767 (void) sd_network_link_get_operational_state(info
->ifindex
, &operational_state
);
768 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
770 r
= sd_network_link_get_setup_state(info
->ifindex
, &setup_state
);
771 if (r
== -ENODATA
) /* If there's no info available about this iface, it's unmanaged by networkd */
772 setup_state
= strdup("unmanaged");
773 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
775 (void) sd_network_link_get_dns(info
->ifindex
, &dns
);
776 (void) sd_network_link_get_search_domains(info
->ifindex
, &search_domains
);
777 (void) sd_network_link_get_route_domains(info
->ifindex
, &route_domains
);
778 (void) sd_network_link_get_ntp(info
->ifindex
, &ntp
);
780 xsprintf(devid
, "n%i", info
->ifindex
);
782 (void) sd_device_new_from_device_id(&d
, devid
);
785 (void) sd_device_get_property_value(d
, "ID_NET_LINK_FILE", &link
);
786 (void) sd_device_get_property_value(d
, "ID_NET_DRIVER", &driver
);
787 (void) sd_device_get_property_value(d
, "ID_PATH", &path
);
789 r
= sd_device_get_property_value(d
, "ID_VENDOR_FROM_DATABASE", &vendor
);
791 (void) sd_device_get_property_value(d
, "ID_VENDOR", &vendor
);
793 r
= sd_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE", &model
);
795 (void) sd_device_get_property_value(d
, "ID_MODEL", &model
);
798 t
= link_get_type_string(info
->iftype
, d
);
800 (void) sd_network_link_get_network_file(info
->ifindex
, &network
);
802 (void) sd_network_link_get_carrier_bound_to(info
->ifindex
, &carrier_bound_to
);
803 (void) sd_network_link_get_carrier_bound_by(info
->ifindex
, &carrier_bound_by
);
805 printf("%s%s%s %i: %s\n", on_color_operational
, special_glyph(BLACK_CIRCLE
), off_color_operational
, info
->ifindex
, info
->name
);
807 printf(" Link File: %s\n"
808 " Network File: %s\n"
810 " State: %s%s%s (%s%s%s)\n",
814 on_color_operational
, strna(operational_state
), off_color_operational
,
815 on_color_setup
, strna(setup_state
), off_color_setup
);
818 printf(" Path: %s\n", path
);
820 printf(" Driver: %s\n", driver
);
822 printf(" Vendor: %s\n", vendor
);
824 printf(" Model: %s\n", model
);
826 if (info
->has_mac_address
) {
827 _cleanup_free_
char *description
= NULL
;
828 char ea
[ETHER_ADDR_TO_STRING_MAX
];
830 (void) ieee_oui(hwdb
, &info
->mac_address
, &description
);
833 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info
->mac_address
, ea
), description
);
835 printf(" HW Address: %s\n", ether_addr_to_string(&info
->mac_address
, ea
));
839 printf(" MTU: %u\n", info
->mtu
);
841 (void) dump_addresses(rtnl
, " Address: ", info
->ifindex
);
842 (void) dump_gateways(rtnl
, hwdb
, " Gateway: ", info
->ifindex
);
844 dump_list(" DNS: ", dns
);
845 dump_list(" Search Domains: ", search_domains
);
846 dump_list(" Route Domains: ", route_domains
);
848 dump_list(" NTP: ", ntp
);
850 dump_ifindexes("Carrier Bound To: ", carrier_bound_to
);
851 dump_ifindexes("Carrier Bound By: ", carrier_bound_by
);
853 (void) sd_network_link_get_timezone(info
->ifindex
, &tz
);
855 printf(" Time Zone: %s\n", tz
);
857 (void) dump_lldp_neighbors(" Connected To: ", info
->ifindex
);
862 static int system_status(sd_netlink
*rtnl
, sd_hwdb
*hwdb
) {
863 _cleanup_free_
char *operational_state
= NULL
;
864 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **search_domains
= NULL
, **route_domains
= NULL
;
865 const char *on_color_operational
, *off_color_operational
;
869 (void) sd_network_get_operational_state(&operational_state
);
870 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
872 printf("%s%s%s State: %s%s%s\n",
873 on_color_operational
, special_glyph(BLACK_CIRCLE
), off_color_operational
,
874 on_color_operational
, strna(operational_state
), off_color_operational
);
876 (void) dump_addresses(rtnl
, " Address: ", 0);
877 (void) dump_gateways(rtnl
, hwdb
, " Gateway: ", 0);
879 (void) sd_network_get_dns(&dns
);
880 dump_list(" DNS: ", dns
);
882 (void) sd_network_get_search_domains(&search_domains
);
883 dump_list("Search Domains: ", search_domains
);
885 (void) sd_network_get_route_domains(&route_domains
);
886 dump_list(" Route Domains: ", route_domains
);
888 (void) sd_network_get_ntp(&ntp
);
889 dump_list(" NTP: ", ntp
);
894 static int link_status(int argc
, char *argv
[], void *userdata
) {
895 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
896 _cleanup_(sd_hwdb_unrefp
) sd_hwdb
*hwdb
= NULL
;
897 _cleanup_free_ LinkInfo
*links
= NULL
;
900 (void) pager_open(arg_no_pager
, false);
902 r
= sd_netlink_open(&rtnl
);
904 return log_error_errno(r
, "Failed to connect to netlink: %m");
906 r
= sd_hwdb_new(&hwdb
);
908 log_debug_errno(r
, "Failed to open hardware database: %m");
911 c
= acquire_link_info_all(rtnl
, &links
);
913 return system_status(rtnl
, hwdb
);
915 c
= acquire_link_info_strv(rtnl
, argv
+ 1, &links
);
919 for (i
= 0; i
< c
; i
++) {
923 link_status_one(rtnl
, hwdb
, links
+ i
);
929 static char *lldp_capabilities_to_string(uint16_t x
) {
930 static const char characters
[] = {
931 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
936 ret
= new(char, ELEMENTSOF(characters
) + 1);
940 for (i
= 0; i
< ELEMENTSOF(characters
); i
++)
941 ret
[i
] = (x
& (1U << i
)) ? characters
[i
] : '.';
947 static void lldp_capabilities_legend(uint16_t x
) {
948 unsigned w
, i
, cols
= columns();
949 static const char* const table
[] = {
953 "w - WLAN Access Point",
956 "d - DOCSIS cable device",
960 "m - Two-port MAC Relay (TPMR)",
966 printf("\nCapability Flags:\n");
967 for (w
= 0, i
= 0; i
< ELEMENTSOF(table
); i
++)
968 if (x
& (1U << i
) || arg_all
) {
971 newline
= w
+ strlen(table
[i
]) + (w
== 0 ? 0 : 2) > cols
;
974 w
+= printf("%s%s%s", newline
? "\n" : "", w
== 0 ? "" : "; ", table
[i
]);
979 static int link_lldp_status(int argc
, char *argv
[], void *userdata
) {
980 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
981 _cleanup_free_ LinkInfo
*links
= NULL
;
985 r
= sd_netlink_open(&rtnl
);
987 return log_error_errno(r
, "Failed to connect to netlink: %m");
990 c
= acquire_link_info_strv(rtnl
, argv
+ 1, &links
);
992 c
= acquire_link_info_all(rtnl
, &links
);
996 (void) pager_open(arg_no_pager
, false);
999 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
1005 "PORT DESCRIPTION");
1007 for (i
= 0; i
< c
; i
++) {
1008 _cleanup_fclose_
FILE *f
= NULL
;
1010 r
= open_lldp_neighbors(links
[i
].ifindex
, &f
);
1014 log_warning_errno(r
, "Failed to open LLDP data for %i, ignoring: %m", links
[i
].ifindex
);
1019 _cleanup_free_
char *cid
= NULL
, *pid
= NULL
, *sname
= NULL
, *pdesc
= NULL
;
1020 const char *chassis_id
= NULL
, *port_id
= NULL
, *system_name
= NULL
, *port_description
= NULL
, *capabilities
= NULL
;
1021 _cleanup_(sd_lldp_neighbor_unrefp
) sd_lldp_neighbor
*n
= NULL
;
1024 r
= next_lldp_neighbor(f
, &n
);
1026 log_warning_errno(r
, "Failed to read neighbor data: %m");
1032 (void) sd_lldp_neighbor_get_chassis_id_as_string(n
, &chassis_id
);
1033 (void) sd_lldp_neighbor_get_port_id_as_string(n
, &port_id
);
1034 (void) sd_lldp_neighbor_get_system_name(n
, &system_name
);
1035 (void) sd_lldp_neighbor_get_port_description(n
, &port_description
);
1038 cid
= ellipsize(chassis_id
, 17, 100);
1044 pid
= ellipsize(port_id
, 17, 100);
1050 sname
= ellipsize(system_name
, 16, 100);
1052 system_name
= sname
;
1055 if (port_description
) {
1056 pdesc
= ellipsize(port_description
, 16, 100);
1058 port_description
= pdesc
;
1061 if (sd_lldp_neighbor_get_enabled_capabilities(n
, &cc
) >= 0) {
1062 capabilities
= lldp_capabilities_to_string(cc
);
1066 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
1070 strna(capabilities
),
1072 strna(port_description
));
1079 lldp_capabilities_legend(all
);
1080 printf("\n%i neighbors listed.\n", m
);
1086 static void help(void) {
1087 printf("%s [OPTIONS...]\n\n"
1088 "Query and control the networking subsystem.\n\n"
1089 " -h --help Show this help\n"
1090 " --version Show package version\n"
1091 " --no-pager Do not pipe output into a pager\n"
1092 " --no-legend Do not show the headers and footers\n"
1093 " -a --all Show status for all links\n\n"
1095 " list [LINK...] List links\n"
1096 " status [LINK...] Show link status\n"
1097 " lldp [LINK...] Show LLDP neighbors\n"
1098 " label Show current address label entries in the kernel\n"
1099 , program_invocation_short_name
);
1102 static int parse_argv(int argc
, char *argv
[]) {
1105 ARG_VERSION
= 0x100,
1110 static const struct option options
[] = {
1111 { "help", no_argument
, NULL
, 'h' },
1112 { "version", no_argument
, NULL
, ARG_VERSION
},
1113 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1114 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1115 { "all", no_argument
, NULL
, 'a' },
1124 while ((c
= getopt_long(argc
, argv
, "ha", options
, NULL
)) >= 0) {
1136 arg_no_pager
= true;
1151 assert_not_reached("Unhandled option");
1158 static int networkctl_main(int argc
, char *argv
[]) {
1159 static const Verb verbs
[] = {
1160 { "list", VERB_ANY
, VERB_ANY
, VERB_DEFAULT
, list_links
},
1161 { "status", VERB_ANY
, VERB_ANY
, 0, link_status
},
1162 { "lldp", VERB_ANY
, VERB_ANY
, 0, link_lldp_status
},
1163 { "label", VERB_ANY
, VERB_ANY
, 0, list_address_labels
},
1167 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1170 static void warn_networkd_missing(void) {
1172 if (access("/run/systemd/netif/state", F_OK
) >= 0)
1175 fprintf(stderr
, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
1178 int main(int argc
, char* argv
[]) {
1181 log_parse_environment();
1184 r
= parse_argv(argc
, argv
);
1188 warn_networkd_missing();
1190 r
= networkctl_main(argc
, argv
);
1195 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;