2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include "sd-device.h"
27 #include "sd-netlink.h"
28 #include "sd-network.h"
30 #include "alloc-util.h"
31 #include "arphrd-list.h"
32 #include "device-util.h"
33 #include "ether-addr-util.h"
35 #include "hwdb-util.h"
37 #include "local-addresses.h"
38 #include "locale-util.h"
39 #include "netlink-util.h"
41 #include "parse-util.h"
42 #include "socket-util.h"
43 #include "sparse-endian.h"
44 #include "stdio-util.h"
45 #include "string-table.h"
46 #include "string-util.h"
48 #include "terminal-util.h"
52 static bool arg_no_pager
= false;
53 static bool arg_legend
= true;
54 static bool arg_all
= false;
56 static void pager_open_if_enabled(void) {
64 static int link_get_type_string(unsigned short iftype
, sd_device
*d
, char **ret
) {
70 if (iftype
== ARPHRD_ETHER
&& d
) {
71 const char *devtype
= NULL
, *id
= NULL
;
72 /* WLANs have iftype ARPHRD_ETHER, but we want
73 * to show a more useful type string for
76 (void) sd_device_get_devtype(d
, &devtype
);
78 if (streq_ptr(devtype
, "wlan"))
80 else if (streq_ptr(devtype
, "wwan"))
93 t
= arphrd_to_name(iftype
);
109 static void operational_state_to_color(const char *state
, const char **on
, const char **off
) {
113 if (streq_ptr(state
, "routable")) {
114 *on
= ansi_highlight_green();
115 *off
= ansi_normal();
116 } else if (streq_ptr(state
, "degraded")) {
117 *on
= ansi_highlight_yellow();
118 *off
= ansi_normal();
123 static void setup_state_to_color(const char *state
, const char **on
, const char **off
) {
127 if (streq_ptr(state
, "configured")) {
128 *on
= ansi_highlight_green();
129 *off
= ansi_normal();
130 } else if (streq_ptr(state
, "configuring")) {
131 *on
= ansi_highlight_yellow();
132 *off
= ansi_normal();
133 } else if (streq_ptr(state
, "failed") || streq_ptr(state
, "linger")) {
134 *on
= ansi_highlight_red();
135 *off
= ansi_normal();
140 typedef struct LinkInfo
{
141 char name
[IFNAMSIZ
+1];
143 unsigned short iftype
;
144 struct ether_addr mac_address
;
147 bool has_mac_address
:1;
151 static int link_info_compare(const void *a
, const void *b
) {
152 const LinkInfo
*x
= a
, *y
= b
;
154 return x
->ifindex
- y
->ifindex
;
157 static int decode_link(sd_netlink_message
*m
, LinkInfo
*info
) {
158 static const struct ether_addr null_address
= {};
166 r
= sd_netlink_message_get_type(m
, &type
);
170 if (type
!= RTM_NEWLINK
)
173 r
= sd_rtnl_message_link_get_ifindex(m
, &info
->ifindex
);
177 r
= sd_netlink_message_read_string(m
, IFLA_IFNAME
, &name
);
181 r
= sd_rtnl_message_link_get_type(m
, &info
->iftype
);
185 strncpy(info
->name
, name
, sizeof(info
->name
));
187 info
->has_mac_address
=
188 sd_netlink_message_read_ether_addr(m
, IFLA_ADDRESS
, &info
->mac_address
) >= 0 &&
189 memcmp(&info
->mac_address
, &null_address
, sizeof(struct ether_addr
)) != 0;
192 sd_netlink_message_read_u32(m
, IFLA_MTU
, &info
->mtu
) &&
198 static int acquire_link_info_strv(sd_netlink
*rtnl
, char **l
, LinkInfo
**ret
) {
199 _cleanup_free_ LinkInfo
*links
= NULL
;
207 links
= new(LinkInfo
, strv_length(l
));
212 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
215 if (parse_ifindex(*i
, &ifindex
) >= 0)
216 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, ifindex
);
218 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
220 return rtnl_log_create_error(r
);
222 r
= sd_netlink_message_append_string(req
, IFLA_IFNAME
, *i
);
225 return rtnl_log_create_error(r
);
227 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
229 return log_error_errno(r
, "Failed to request link: %m");
231 r
= decode_link(reply
, links
+ c
);
238 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
246 static int acquire_link_info_all(sd_netlink
*rtnl
, LinkInfo
**ret
) {
247 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
248 _cleanup_free_ LinkInfo
*links
= NULL
;
249 size_t allocated
= 0, c
= 0;
250 sd_netlink_message
*i
;
256 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
258 return rtnl_log_create_error(r
);
260 r
= sd_netlink_message_request_dump(req
, true);
262 return rtnl_log_create_error(r
);
264 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
266 return log_error_errno(r
, "Failed to enumerate links: %m");
268 for (i
= reply
; i
; i
= sd_netlink_message_next(i
)) {
269 if (!GREEDY_REALLOC(links
, allocated
, c
+1))
272 r
= decode_link(i
, links
+ c
);
279 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
287 static int list_links(int argc
, char *argv
[], void *userdata
) {
288 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
289 _cleanup_free_ LinkInfo
*links
= NULL
;
292 r
= sd_netlink_open(&rtnl
);
294 return log_error_errno(r
, "Failed to connect to netlink: %m");
297 c
= acquire_link_info_strv(rtnl
, argv
+ 1, &links
);
299 c
= acquire_link_info_all(rtnl
, &links
);
303 pager_open_if_enabled();
306 printf("%3s %-16s %-18s %-11s %-10s\n",
313 for (i
= 0; i
< c
; i
++) {
314 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
;
315 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
316 const char *on_color_operational
, *off_color_operational
,
317 *on_color_setup
, *off_color_setup
;
318 char devid
[2 + DECIMAL_STR_MAX(int)];
319 _cleanup_free_
char *t
= NULL
;
321 (void) sd_network_link_get_operational_state(links
[i
].ifindex
, &operational_state
);
322 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
324 r
= sd_network_link_get_setup_state(links
[i
].ifindex
, &setup_state
);
325 if (r
== -ENODATA
) /* If there's no info available about this iface, it's unmanaged by networkd */
326 setup_state
= strdup("unmanaged");
327 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
329 xsprintf(devid
, "n%i", links
[i
].ifindex
);
330 (void) sd_device_new_from_device_id(&d
, devid
);
332 (void) link_get_type_string(links
[i
].iftype
, d
, &t
);
334 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
335 links
[i
].ifindex
, links
[i
].name
, strna(t
),
336 on_color_operational
, strna(operational_state
), off_color_operational
,
337 on_color_setup
, strna(setup_state
), off_color_setup
);
341 printf("\n%i links listed.\n", c
);
346 /* IEEE Organizationally Unique Identifier vendor string */
347 static int ieee_oui(sd_hwdb
*hwdb
, const struct ether_addr
*mac
, char **ret
) {
348 const char *description
;
349 char modalias
[strlen("OUI:XXYYXXYYXXYY") + 1], *desc
;
360 /* skip commonly misused 00:00:00 (Xerox) prefix */
361 if (memcmp(mac
, "\0\0\0", 3) == 0)
364 xsprintf(modalias
, "OUI:" ETHER_ADDR_FORMAT_STR
,
365 ETHER_ADDR_FORMAT_VAL(*mac
));
367 r
= sd_hwdb_get(hwdb
, modalias
, "ID_OUI_FROM_DATABASE", &description
);
371 desc
= strdup(description
);
380 static int get_gateway_description(
385 union in_addr_union
*gateway
,
386 char **gateway_description
) {
387 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
388 sd_netlink_message
*m
;
392 assert(ifindex
>= 0);
393 assert(family
== AF_INET
|| family
== AF_INET6
);
395 assert(gateway_description
);
397 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_GETNEIGH
, ifindex
, family
);
401 r
= sd_netlink_message_request_dump(req
, true);
405 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
409 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
410 union in_addr_union gw
= {};
411 struct ether_addr mac
= {};
415 r
= sd_netlink_message_get_errno(m
);
417 log_error_errno(r
, "got error: %m");
421 r
= sd_netlink_message_get_type(m
, &type
);
423 log_error_errno(r
, "could not get type: %m");
427 if (type
!= RTM_NEWNEIGH
) {
428 log_error("type is not RTM_NEWNEIGH");
432 r
= sd_rtnl_message_neigh_get_family(m
, &fam
);
434 log_error_errno(r
, "could not get family: %m");
439 log_error("family is not correct");
443 r
= sd_rtnl_message_neigh_get_ifindex(m
, &ifi
);
445 log_error_errno(r
, "could not get ifindex: %m");
449 if (ifindex
> 0 && ifi
!= ifindex
)
454 r
= sd_netlink_message_read_in_addr(m
, NDA_DST
, &gw
.in
);
460 r
= sd_netlink_message_read_in6_addr(m
, NDA_DST
, &gw
.in6
);
469 if (!in_addr_equal(fam
, &gw
, gateway
))
472 r
= sd_netlink_message_read_ether_addr(m
, NDA_LLADDR
, &mac
);
476 r
= ieee_oui(hwdb
, &mac
, gateway_description
);
486 static int dump_gateways(
491 _cleanup_free_
struct local_address
*local
= NULL
;
497 n
= local_gateways(rtnl
, ifindex
, AF_UNSPEC
, &local
);
501 for (i
= 0; i
< n
; i
++) {
502 _cleanup_free_
char *gateway
= NULL
, *description
= NULL
;
504 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &gateway
);
508 r
= get_gateway_description(rtnl
, hwdb
, local
[i
].ifindex
, local
[i
].family
, &local
[i
].address
, &description
);
510 log_debug_errno(r
, "Could not get description of gateway: %m");
513 (int) strlen(prefix
),
514 i
== 0 ? prefix
: "",
518 printf(" (%s)", description
);
520 /* Show interface name for the entry if we show
521 * entries for all interfaces */
523 char name
[IF_NAMESIZE
+1];
525 if (if_indextoname(local
[i
].ifindex
, name
)) {
526 fputs(" on ", stdout
);
529 printf(" on %%%i", local
[i
].ifindex
);
538 static int dump_addresses(
543 _cleanup_free_
struct local_address
*local
= NULL
;
549 n
= local_addresses(rtnl
, ifindex
, AF_UNSPEC
, &local
);
553 for (i
= 0; i
< n
; i
++) {
554 _cleanup_free_
char *pretty
= NULL
;
556 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &pretty
);
561 (int) strlen(prefix
),
562 i
== 0 ? prefix
: "",
566 char name
[IF_NAMESIZE
+1];
568 if (if_indextoname(local
[i
].ifindex
, name
)) {
569 fputs(" on ", stdout
);
572 printf(" on %%%i", local
[i
].ifindex
);
581 static int open_lldp_neighbors(int ifindex
, FILE **ret
) {
582 _cleanup_free_
char *p
= NULL
;
585 if (asprintf(&p
, "/run/systemd/netif/lldp/%i", ifindex
) < 0)
596 static int next_lldp_neighbor(FILE *f
, sd_lldp_neighbor
**ret
) {
597 _cleanup_free_
void *raw
= NULL
;
605 l
= fread(&u
, 1, sizeof(u
), f
);
606 if (l
== 0 && feof(f
))
611 raw
= new(uint8_t, le64toh(u
));
615 if (fread(raw
, 1, le64toh(u
), f
) != le64toh(u
))
618 r
= sd_lldp_neighbor_from_raw(ret
, raw
, le64toh(u
));
625 static int dump_lldp_neighbors(const char *prefix
, int ifindex
) {
626 _cleanup_fclose_
FILE *f
= NULL
;
632 r
= open_lldp_neighbors(ifindex
, &f
);
637 const char *system_name
= NULL
, *port_id
= NULL
, *port_description
= NULL
;
638 _cleanup_(sd_lldp_neighbor_unrefp
) sd_lldp_neighbor
*n
= NULL
;
640 r
= next_lldp_neighbor(f
, &n
);
647 (int) strlen(prefix
),
648 c
== 0 ? prefix
: "");
650 (void) sd_lldp_neighbor_get_system_name(n
, &system_name
);
651 (void) sd_lldp_neighbor_get_port_id_as_string(n
, &port_id
);
652 (void) sd_lldp_neighbor_get_port_description(n
, &port_description
);
654 printf("%s on port %s", strna(system_name
), strna(port_id
));
656 if (!isempty(port_description
))
657 printf(" (%s)", port_description
);
667 static void dump_ifindexes(const char *prefix
, const int *ifindexes
) {
672 if (!ifindexes
|| ifindexes
[0] <= 0)
675 for (c
= 0; ifindexes
[c
] > 0; c
++) {
676 char name
[IF_NAMESIZE
+1];
679 (int) strlen(prefix
),
680 c
== 0 ? prefix
: "");
682 if (if_indextoname(ifindexes
[c
], name
))
685 printf("%i", ifindexes
[c
]);
691 static void dump_list(const char *prefix
, char **l
) {
699 (int) strlen(prefix
),
700 i
== l
? prefix
: "",
705 static int link_status_one(
708 const LinkInfo
*info
) {
710 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **search_domains
= NULL
, **route_domains
= NULL
;
711 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
, *tz
= NULL
;
712 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
713 char devid
[2 + DECIMAL_STR_MAX(int)];
714 _cleanup_free_
char *t
= NULL
, *network
= NULL
;
715 const char *driver
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *link
= NULL
;
716 const char *on_color_operational
, *off_color_operational
,
717 *on_color_setup
, *off_color_setup
;
718 _cleanup_free_
int *carrier_bound_to
= NULL
, *carrier_bound_by
= NULL
;
724 (void) sd_network_link_get_operational_state(info
->ifindex
, &operational_state
);
725 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
727 r
= sd_network_link_get_setup_state(info
->ifindex
, &setup_state
);
728 if (r
== -ENODATA
) /* If there's no info available about this iface, it's unmanaged by networkd */
729 setup_state
= strdup("unmanaged");
730 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
732 (void) sd_network_link_get_dns(info
->ifindex
, &dns
);
733 (void) sd_network_link_get_search_domains(info
->ifindex
, &search_domains
);
734 (void) sd_network_link_get_route_domains(info
->ifindex
, &route_domains
);
735 (void) sd_network_link_get_ntp(info
->ifindex
, &ntp
);
737 xsprintf(devid
, "n%i", info
->ifindex
);
739 (void) sd_device_new_from_device_id(&d
, devid
);
742 (void) sd_device_get_property_value(d
, "ID_NET_LINK_FILE", &link
);
743 (void) sd_device_get_property_value(d
, "ID_NET_DRIVER", &driver
);
744 (void) sd_device_get_property_value(d
, "ID_PATH", &path
);
746 r
= sd_device_get_property_value(d
, "ID_VENDOR_FROM_DATABASE", &vendor
);
748 (void) sd_device_get_property_value(d
, "ID_VENDOR", &vendor
);
750 r
= sd_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE", &model
);
752 (void) sd_device_get_property_value(d
, "ID_MODEL", &model
);
755 (void) link_get_type_string(info
->iftype
, d
, &t
);
757 (void) sd_network_link_get_network_file(info
->ifindex
, &network
);
759 (void) sd_network_link_get_carrier_bound_to(info
->ifindex
, &carrier_bound_to
);
760 (void) sd_network_link_get_carrier_bound_by(info
->ifindex
, &carrier_bound_by
);
762 printf("%s%s%s %i: %s\n", on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
, info
->ifindex
, info
->name
);
764 printf(" Link File: %s\n"
765 " Network File: %s\n"
767 " State: %s%s%s (%s%s%s)\n",
771 on_color_operational
, strna(operational_state
), off_color_operational
,
772 on_color_setup
, strna(setup_state
), off_color_setup
);
775 printf(" Path: %s\n", path
);
777 printf(" Driver: %s\n", driver
);
779 printf(" Vendor: %s\n", vendor
);
781 printf(" Model: %s\n", model
);
783 if (info
->has_mac_address
) {
784 _cleanup_free_
char *description
= NULL
;
785 char ea
[ETHER_ADDR_TO_STRING_MAX
];
787 (void) ieee_oui(hwdb
, &info
->mac_address
, &description
);
790 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info
->mac_address
, ea
), description
);
792 printf(" HW Address: %s\n", ether_addr_to_string(&info
->mac_address
, ea
));
796 printf(" MTU: %u\n", info
->mtu
);
798 (void) dump_addresses(rtnl
, " Address: ", info
->ifindex
);
799 (void) dump_gateways(rtnl
, hwdb
, " Gateway: ", info
->ifindex
);
801 dump_list(" DNS: ", dns
);
802 dump_list(" Search Domains: ", search_domains
);
803 dump_list(" Route Domains: ", route_domains
);
805 dump_list(" NTP: ", ntp
);
807 dump_ifindexes("Carrier Bound To: ", carrier_bound_to
);
808 dump_ifindexes("Carrier Bound By: ", carrier_bound_by
);
810 (void) sd_network_link_get_timezone(info
->ifindex
, &tz
);
812 printf(" Time Zone: %s\n", tz
);
814 (void) dump_lldp_neighbors(" Connected To: ", info
->ifindex
);
819 static int system_status(sd_netlink
*rtnl
, sd_hwdb
*hwdb
) {
820 _cleanup_free_
char *operational_state
= NULL
;
821 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **search_domains
= NULL
, **route_domains
= NULL
;
822 const char *on_color_operational
, *off_color_operational
;
826 (void) sd_network_get_operational_state(&operational_state
);
827 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
829 printf("%s%s%s State: %s%s%s\n",
830 on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
,
831 on_color_operational
, strna(operational_state
), off_color_operational
);
833 (void) dump_addresses(rtnl
, " Address: ", 0);
834 (void) dump_gateways(rtnl
, hwdb
, " Gateway: ", 0);
836 (void) sd_network_get_dns(&dns
);
837 dump_list(" DNS: ", dns
);
839 (void) sd_network_get_search_domains(&search_domains
);
840 dump_list("Search Domains: ", search_domains
);
842 (void) sd_network_get_route_domains(&route_domains
);
843 dump_list(" Route Domains: ", route_domains
);
845 (void) sd_network_get_ntp(&ntp
);
846 dump_list(" NTP: ", ntp
);
851 static int link_status(int argc
, char *argv
[], void *userdata
) {
852 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
853 _cleanup_(sd_hwdb_unrefp
) sd_hwdb
*hwdb
= NULL
;
854 _cleanup_free_ LinkInfo
*links
= NULL
;
857 pager_open_if_enabled();
859 r
= sd_netlink_open(&rtnl
);
861 return log_error_errno(r
, "Failed to connect to netlink: %m");
863 r
= sd_hwdb_new(&hwdb
);
865 log_debug_errno(r
, "Failed to open hardware database: %m");
868 c
= acquire_link_info_all(rtnl
, &links
);
870 return system_status(rtnl
, hwdb
);
872 c
= acquire_link_info_strv(rtnl
, argv
+ 1, &links
);
876 for (i
= 0; i
< c
; i
++) {
880 link_status_one(rtnl
, hwdb
, links
+ i
);
886 static char *lldp_capabilities_to_string(uint16_t x
) {
887 static const char characters
[] = {
888 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
893 ret
= new(char, ELEMENTSOF(characters
) + 1);
897 for (i
= 0; i
< ELEMENTSOF(characters
); i
++)
898 ret
[i
] = (x
& (1U << i
)) ? characters
[i
] : '.';
904 static void lldp_capabilities_legend(uint16_t x
) {
905 unsigned w
, i
, cols
= columns();
906 static const char* const table
[] = {
910 "w - WLAN Access Point",
913 "d - DOCSIS cable device",
917 "m - Two-port MAC Relay (TPMR)",
923 printf("\nCapability Flags:\n");
924 for (w
= 0, i
= 0; i
< ELEMENTSOF(table
); i
++)
925 if (x
& (1U << i
) || arg_all
) {
928 newline
= w
+ strlen(table
[i
]) + (w
== 0 ? 0 : 2) > cols
;
931 w
+= printf("%s%s%s", newline
? "\n" : "", w
== 0 ? "" : "; ", table
[i
]);
936 static int link_lldp_status(int argc
, char *argv
[], void *userdata
) {
937 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
938 _cleanup_free_ LinkInfo
*links
= NULL
;
942 r
= sd_netlink_open(&rtnl
);
944 return log_error_errno(r
, "Failed to connect to netlink: %m");
947 c
= acquire_link_info_strv(rtnl
, argv
+ 1, &links
);
949 c
= acquire_link_info_all(rtnl
, &links
);
953 pager_open_if_enabled();
956 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
964 for (i
= 0; i
< c
; i
++) {
965 _cleanup_fclose_
FILE *f
= NULL
;
967 r
= open_lldp_neighbors(links
[i
].ifindex
, &f
);
971 log_warning_errno(r
, "Failed to open LLDP data for %i, ignoring: %m", links
[i
].ifindex
);
976 _cleanup_free_
char *cid
= NULL
, *pid
= NULL
, *sname
= NULL
, *pdesc
= NULL
;
977 const char *chassis_id
= NULL
, *port_id
= NULL
, *system_name
= NULL
, *port_description
= NULL
, *capabilities
= NULL
;
978 _cleanup_(sd_lldp_neighbor_unrefp
) sd_lldp_neighbor
*n
= NULL
;
981 r
= next_lldp_neighbor(f
, &n
);
983 log_warning_errno(r
, "Failed to read neighbor data: %m");
989 (void) sd_lldp_neighbor_get_chassis_id_as_string(n
, &chassis_id
);
990 (void) sd_lldp_neighbor_get_port_id_as_string(n
, &port_id
);
991 (void) sd_lldp_neighbor_get_system_name(n
, &system_name
);
992 (void) sd_lldp_neighbor_get_port_description(n
, &port_description
);
995 cid
= ellipsize(chassis_id
, 17, 100);
1001 pid
= ellipsize(port_id
, 17, 100);
1007 sname
= ellipsize(system_name
, 16, 100);
1009 system_name
= sname
;
1012 if (port_description
) {
1013 pdesc
= ellipsize(port_description
, 16, 100);
1015 port_description
= pdesc
;
1018 if (sd_lldp_neighbor_get_enabled_capabilities(n
, &cc
) >= 0) {
1019 capabilities
= lldp_capabilities_to_string(cc
);
1023 printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
1027 strna(capabilities
),
1029 strna(port_description
));
1036 lldp_capabilities_legend(all
);
1037 printf("\n%i neighbors listed.\n", m
);
1043 static void help(void) {
1044 printf("%s [OPTIONS...]\n\n"
1045 "Query and control the networking subsystem.\n\n"
1046 " -h --help Show this help\n"
1047 " --version Show package version\n"
1048 " --no-pager Do not pipe output into a pager\n"
1049 " --no-legend Do not show the headers and footers\n"
1050 " -a --all Show status for all links\n\n"
1052 " list [LINK...] List links\n"
1053 " status [LINK...] Show link status\n"
1054 " lldp [LINK...] Show LLDP neighbors\n"
1055 , program_invocation_short_name
);
1058 static int parse_argv(int argc
, char *argv
[]) {
1061 ARG_VERSION
= 0x100,
1066 static const struct option options
[] = {
1067 { "help", no_argument
, NULL
, 'h' },
1068 { "version", no_argument
, NULL
, ARG_VERSION
},
1069 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1070 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1071 { "all", no_argument
, NULL
, 'a' },
1080 while ((c
= getopt_long(argc
, argv
, "ha", options
, NULL
)) >= 0) {
1092 arg_no_pager
= true;
1107 assert_not_reached("Unhandled option");
1114 static int networkctl_main(int argc
, char *argv
[]) {
1115 const Verb verbs
[] = {
1116 { "list", VERB_ANY
, VERB_ANY
, VERB_DEFAULT
, list_links
},
1117 { "status", VERB_ANY
, VERB_ANY
, 0, link_status
},
1118 { "lldp", VERB_ANY
, VERB_ANY
, 0, link_lldp_status
},
1122 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1125 static void warn_networkd_missing(void) {
1127 if (access("/run/systemd/netif/state", F_OK
) >= 0)
1130 fprintf(stderr
, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
1133 int main(int argc
, char* argv
[]) {
1136 log_parse_environment();
1139 r
= parse_argv(argc
, argv
);
1143 warn_networkd_missing();
1145 r
= networkctl_main(argc
, argv
);
1150 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;