1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "sd-device.h"
28 #include "sd-netlink.h"
29 #include "sd-network.h"
31 #include "alloc-util.h"
32 #include "arphrd-list.h"
33 #include "device-util.h"
34 #include "ether-addr-util.h"
35 #include "hwdb-util.h"
37 #include "local-addresses.h"
38 #include "locale-util.h"
39 #include "locale-util.h"
40 #include "netlink-util.h"
42 #include "parse-util.h"
43 #include "socket-util.h"
44 #include "string-table.h"
45 #include "string-util.h"
47 #include "terminal-util.h"
51 static bool arg_no_pager
= false;
52 static bool arg_legend
= true;
53 static bool arg_all
= false;
55 static void pager_open_if_enabled(void) {
63 static int link_get_type_string(int iftype
, sd_device
*d
, char **ret
) {
69 if (iftype
== ARPHRD_ETHER
&& d
) {
70 const char *devtype
= NULL
, *id
= NULL
;
71 /* WLANs have iftype ARPHRD_ETHER, but we want
72 * to show a more useful type string for
75 (void)sd_device_get_devtype(d
, &devtype
);
77 if (streq_ptr(devtype
, "wlan"))
79 else if (streq_ptr(devtype
, "wwan"))
92 t
= arphrd_to_name(iftype
);
108 typedef struct LinkInfo
{
114 static int link_info_compare(const void *a
, const void *b
) {
115 const LinkInfo
*x
= a
, *y
= b
;
117 return x
->ifindex
- y
->ifindex
;
120 static int decode_and_sort_links(sd_netlink_message
*m
, LinkInfo
**ret
) {
121 _cleanup_free_ LinkInfo
*links
= NULL
;
122 size_t size
= 0, c
= 0;
123 sd_netlink_message
*i
;
126 for (i
= m
; i
; i
= sd_netlink_message_next(i
)) {
132 r
= sd_netlink_message_get_type(i
, &type
);
136 if (type
!= RTM_NEWLINK
)
139 r
= sd_rtnl_message_link_get_ifindex(i
, &ifindex
);
143 r
= sd_netlink_message_read_string(i
, IFLA_IFNAME
, &name
);
147 r
= sd_rtnl_message_link_get_type(i
, &iftype
);
151 if (!GREEDY_REALLOC(links
, size
, c
+1))
154 links
[c
].name
= name
;
155 links
[c
].ifindex
= ifindex
;
156 links
[c
].iftype
= iftype
;
160 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
168 static void operational_state_to_color(const char *state
, const char **on
, const char **off
) {
172 if (streq_ptr(state
, "routable")) {
173 *on
= ansi_highlight_green();
174 *off
= ansi_normal();
175 } else if (streq_ptr(state
, "degraded")) {
176 *on
= ansi_highlight_yellow();
177 *off
= ansi_normal();
182 static void setup_state_to_color(const char *state
, const char **on
, const char **off
) {
186 if (streq_ptr(state
, "configured")) {
187 *on
= ansi_highlight_green();
188 *off
= ansi_normal();
189 } else if (streq_ptr(state
, "configuring")) {
190 *on
= ansi_highlight_yellow();
191 *off
= ansi_normal();
192 } else if (streq_ptr(state
, "failed") || streq_ptr(state
, "linger")) {
193 *on
= ansi_highlight_red();
194 *off
= ansi_normal();
199 static int list_links(int argc
, char *argv
[], void *userdata
) {
200 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
201 _cleanup_netlink_unref_ sd_netlink
*rtnl
= NULL
;
202 _cleanup_free_ LinkInfo
*links
= NULL
;
205 pager_open_if_enabled();
207 r
= sd_netlink_open(&rtnl
);
209 return log_error_errno(r
, "Failed to connect to netlink: %m");
211 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
213 return rtnl_log_create_error(r
);
215 r
= sd_netlink_message_request_dump(req
, true);
217 return rtnl_log_create_error(r
);
219 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
221 return log_error_errno(r
, "Failed to enumerate links: %m");
224 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
226 c
= decode_and_sort_links(reply
, &links
);
228 return rtnl_log_parse_error(c
);
230 for (i
= 0; i
< c
; i
++) {
231 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
;
232 _cleanup_device_unref_ sd_device
*d
= NULL
;
233 const char *on_color_operational
, *off_color_operational
,
234 *on_color_setup
, *off_color_setup
;
235 char devid
[2 + DECIMAL_STR_MAX(int)];
236 _cleanup_free_
char *t
= NULL
;
238 sd_network_link_get_operational_state(links
[i
].ifindex
, &operational_state
);
239 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
241 sd_network_link_get_setup_state(links
[i
].ifindex
, &setup_state
);
242 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
244 sprintf(devid
, "n%i", links
[i
].ifindex
);
245 (void)sd_device_new_from_device_id(&d
, devid
);
247 link_get_type_string(links
[i
].iftype
, d
, &t
);
249 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
250 links
[i
].ifindex
, links
[i
].name
, strna(t
),
251 on_color_operational
, strna(operational_state
), off_color_operational
,
252 on_color_setup
, strna(setup_state
), off_color_setup
);
256 printf("\n%i links listed.\n", c
);
261 /* IEEE Organizationally Unique Identifier vendor string */
262 static int ieee_oui(sd_hwdb
*hwdb
, struct ether_addr
*mac
, char **ret
) {
263 const char *description
;
264 char modalias
[strlen("OUI:XXYYXXYYXXYY") + 1], *desc
;
275 /* skip commonly misused 00:00:00 (Xerox) prefix */
276 if (memcmp(mac
, "\0\0\0", 3) == 0)
279 snprintf(modalias
, sizeof(modalias
), "OUI:" ETHER_ADDR_FORMAT_STR
, ETHER_ADDR_FORMAT_VAL(*mac
));
281 r
= sd_hwdb_get(hwdb
, modalias
, "ID_OUI_FROM_DATABASE", &description
);
285 desc
= strdup(description
);
294 static int get_gateway_description(
299 union in_addr_union
*gateway
,
300 char **gateway_description
) {
301 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
302 sd_netlink_message
*m
;
306 assert(ifindex
>= 0);
307 assert(family
== AF_INET
|| family
== AF_INET6
);
309 assert(gateway_description
);
311 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_GETNEIGH
, ifindex
, family
);
315 r
= sd_netlink_message_request_dump(req
, true);
319 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
323 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
324 union in_addr_union gw
= {};
325 struct ether_addr mac
= {};
329 r
= sd_netlink_message_get_errno(m
);
331 log_error_errno(r
, "got error: %m");
335 r
= sd_netlink_message_get_type(m
, &type
);
337 log_error_errno(r
, "could not get type: %m");
341 if (type
!= RTM_NEWNEIGH
) {
342 log_error("type is not RTM_NEWNEIGH");
346 r
= sd_rtnl_message_neigh_get_family(m
, &fam
);
348 log_error_errno(r
, "could not get family: %m");
353 log_error("family is not correct");
357 r
= sd_rtnl_message_neigh_get_ifindex(m
, &ifi
);
359 log_error_errno(r
, "could not get ifindex: %m");
363 if (ifindex
> 0 && ifi
!= ifindex
)
368 r
= sd_netlink_message_read_in_addr(m
, NDA_DST
, &gw
.in
);
374 r
= sd_netlink_message_read_in6_addr(m
, NDA_DST
, &gw
.in6
);
383 if (!in_addr_equal(fam
, &gw
, gateway
))
386 r
= sd_netlink_message_read_ether_addr(m
, NDA_LLADDR
, &mac
);
390 r
= ieee_oui(hwdb
, &mac
, gateway_description
);
400 static int dump_gateways(
405 _cleanup_free_
struct local_address
*local
= NULL
;
408 n
= local_gateways(rtnl
, ifindex
, AF_UNSPEC
, &local
);
412 for (i
= 0; i
< n
; i
++) {
413 _cleanup_free_
char *gateway
= NULL
, *description
= NULL
;
415 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &gateway
);
419 r
= get_gateway_description(rtnl
, hwdb
, local
[i
].ifindex
, local
[i
].family
, &local
[i
].address
, &description
);
421 log_debug_errno(r
, "Could not get description of gateway: %m");
424 (int) strlen(prefix
),
425 i
== 0 ? prefix
: "",
429 printf(" (%s)", description
);
431 /* Show interface name for the entry if we show
432 * entries for all interfaces */
434 char name
[IF_NAMESIZE
+1];
436 if (if_indextoname(local
[i
].ifindex
, name
)) {
437 fputs(" on ", stdout
);
440 printf(" on %%%i", local
[i
].ifindex
);
449 static int dump_addresses(
454 _cleanup_free_
struct local_address
*local
= NULL
;
457 n
= local_addresses(rtnl
, ifindex
, AF_UNSPEC
, &local
);
461 for (i
= 0; i
< n
; i
++) {
462 _cleanup_free_
char *pretty
= NULL
;
464 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &pretty
);
469 (int) strlen(prefix
),
470 i
== 0 ? prefix
: "",
474 char name
[IF_NAMESIZE
+1];
476 if (if_indextoname(local
[i
].ifindex
, name
)) {
477 fputs(" on ", stdout
);
480 printf(" on %%%i", local
[i
].ifindex
);
489 static void dump_list(const char *prefix
, char **l
) {
494 (int) strlen(prefix
),
495 i
== l
? prefix
: "",
500 static int link_status_one(
504 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **domains
= NULL
;
505 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
, *tz
= NULL
;
506 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
507 _cleanup_device_unref_ sd_device
*d
= NULL
;
508 char devid
[2 + DECIMAL_STR_MAX(int)];
509 _cleanup_free_
char *t
= NULL
, *network
= NULL
;
510 const char *driver
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *link
= NULL
;
511 const char *on_color_operational
, *off_color_operational
,
512 *on_color_setup
, *off_color_setup
;
513 _cleanup_strv_free_
char **carrier_bound_to
= NULL
;
514 _cleanup_strv_free_
char **carrier_bound_by
= NULL
;
524 if (safe_atoi(name
, &ifindex
) >= 0 && ifindex
> 0)
525 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, ifindex
);
527 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
529 return rtnl_log_create_error(r
);
531 r
= sd_netlink_message_append_string(req
, IFLA_IFNAME
, name
);
535 return rtnl_log_create_error(r
);
537 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
539 return log_error_errno(r
, "Failed to query link: %m");
541 r
= sd_rtnl_message_link_get_ifindex(reply
, &ifindex
);
543 return rtnl_log_parse_error(r
);
545 r
= sd_netlink_message_read_string(reply
, IFLA_IFNAME
, &name
);
547 return rtnl_log_parse_error(r
);
549 r
= sd_rtnl_message_link_get_type(reply
, &iftype
);
551 return rtnl_log_parse_error(r
);
553 have_mac
= sd_netlink_message_read_ether_addr(reply
, IFLA_ADDRESS
, &e
) >= 0;
557 bool all_zeroes
= true;
559 for (p
= (uint8_t*) &e
; p
< (uint8_t*) &e
+ sizeof(e
); p
++)
569 sd_netlink_message_read_u32(reply
, IFLA_MTU
, &mtu
);
571 sd_network_link_get_operational_state(ifindex
, &operational_state
);
572 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
574 sd_network_link_get_setup_state(ifindex
, &setup_state
);
575 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
577 sd_network_link_get_dns(ifindex
, &dns
);
578 sd_network_link_get_domains(ifindex
, &domains
);
579 r
= sd_network_link_get_wildcard_domain(ifindex
);
583 wildcard
= strdup("*");
587 if (strv_consume(&domains
, wildcard
) < 0)
591 sprintf(devid
, "n%i", ifindex
);
593 (void)sd_device_new_from_device_id(&d
, devid
);
596 (void)sd_device_get_property_value(d
, "ID_NET_LINK_FILE", &link
);
597 (void)sd_device_get_property_value(d
, "ID_NET_DRIVER", &driver
);
598 (void)sd_device_get_property_value(d
, "ID_PATH", &path
);
600 r
= sd_device_get_property_value(d
, "ID_VENDOR_FROM_DATABASE", &vendor
);
602 (void)sd_device_get_property_value(d
, "ID_VENDOR", &vendor
);
604 r
= sd_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE", &model
);
606 (void)sd_device_get_property_value(d
, "ID_MODEL", &model
);
609 link_get_type_string(iftype
, d
, &t
);
611 sd_network_link_get_network_file(ifindex
, &network
);
613 sd_network_link_get_carrier_bound_to(ifindex
, &carrier_bound_to
);
614 sd_network_link_get_carrier_bound_by(ifindex
, &carrier_bound_by
);
616 printf("%s%s%s %i: %s\n", on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
, ifindex
, name
);
618 printf(" Link File: %s\n"
619 " Network File: %s\n"
621 " State: %s%s%s (%s%s%s)\n",
625 on_color_operational
, strna(operational_state
), off_color_operational
,
626 on_color_setup
, strna(setup_state
), off_color_setup
);
629 printf(" Path: %s\n", path
);
631 printf(" Driver: %s\n", driver
);
633 printf(" Vendor: %s\n", vendor
);
635 printf(" Model: %s\n", model
);
638 _cleanup_free_
char *description
= NULL
;
639 char ea
[ETHER_ADDR_TO_STRING_MAX
];
641 ieee_oui(hwdb
, &e
, &description
);
644 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e
, ea
), description
);
646 printf(" HW Address: %s\n", ether_addr_to_string(&e
, ea
));
650 printf(" MTU: %u\n", mtu
);
652 dump_addresses(rtnl
, " Address: ", ifindex
);
653 dump_gateways(rtnl
, hwdb
, " Gateway: ", ifindex
);
655 if (!strv_isempty(dns
))
656 dump_list(" DNS: ", dns
);
657 if (!strv_isempty(domains
))
658 dump_list(" Domain: ", domains
);
660 (void) sd_network_link_get_ntp(ifindex
, &ntp
);
661 if (!strv_isempty(ntp
))
662 dump_list(" NTP: ", ntp
);
664 if (!strv_isempty(carrier_bound_to
))
665 dump_list("Carrier Bound To: ", carrier_bound_to
);
667 if (!strv_isempty(carrier_bound_by
))
668 dump_list("Carrier Bound By: ", carrier_bound_by
);
670 (void) sd_network_link_get_timezone(ifindex
, &tz
);
672 printf(" Time Zone: %s", tz
);
677 static int link_status(int argc
, char *argv
[], void *userdata
) {
678 _cleanup_hwdb_unref_ sd_hwdb
*hwdb
= NULL
;
679 _cleanup_netlink_unref_ sd_netlink
*rtnl
= NULL
;
683 r
= sd_netlink_open(&rtnl
);
685 return log_error_errno(r
, "Failed to connect to netlink: %m");
687 r
= sd_hwdb_new(&hwdb
);
689 log_debug_errno(r
, "Failed to open hardware database: %m");
691 if (argc
<= 1 && !arg_all
) {
692 _cleanup_free_
char *operational_state
= NULL
;
693 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **domains
= NULL
;
694 const char *on_color_operational
, *off_color_operational
;
696 sd_network_get_operational_state(&operational_state
);
697 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
699 printf("%s%s%s State: %s%s%s\n",
700 on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
,
701 on_color_operational
, strna(operational_state
), off_color_operational
);
703 dump_addresses(rtnl
, " Address: ", 0);
704 dump_gateways(rtnl
, hwdb
, " Gateway: ", 0);
706 sd_network_get_dns(&dns
);
707 if (!strv_isempty(dns
))
708 dump_list(" DNS: ", dns
);
710 sd_network_get_domains(&domains
);
711 if (!strv_isempty(domains
))
712 dump_list(" Domain: ", domains
);
714 sd_network_get_ntp(&ntp
);
715 if (!strv_isempty(ntp
))
716 dump_list(" NTP: ", ntp
);
721 pager_open_if_enabled();
724 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
725 _cleanup_free_ LinkInfo
*links
= NULL
;
728 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
730 return rtnl_log_create_error(r
);
732 r
= sd_netlink_message_request_dump(req
, true);
734 return rtnl_log_create_error(r
);
736 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
738 return log_error_errno(r
, "Failed to enumerate links: %m");
740 c
= decode_and_sort_links(reply
, &links
);
742 return rtnl_log_parse_error(c
);
744 for (i
= 0; i
< c
; i
++) {
748 link_status_one(rtnl
, hwdb
, links
[i
].name
);
751 STRV_FOREACH(name
, argv
+ 1) {
752 if (name
!= argv
+ 1)
755 link_status_one(rtnl
, hwdb
, *name
);
762 const char *lldp_system_capability_to_string(LLDPSystemCapabilities d
) _const_
;
763 LLDPSystemCapabilities
lldp_system_capability_from_string(const char *d
) _pure_
;
765 static const char* const lldp_system_capability_table
[_LLDP_SYSTEM_CAPABILITIES_MAX
+ 1] = {
766 [LLDP_SYSTEM_CAPABILITIES_OTHER
] = "O",
767 [LLDP_SYSTEM_CAPABILITIES_REPEATER
] = "P",
768 [LLDP_SYSTEM_CAPABILITIES_BRIDGE
] = "B",
769 [LLDP_SYSTEM_CAPABILITIES_WLAN_AP
] = "W",
770 [LLDP_SYSTEM_CAPABILITIES_ROUTER
] = "R",
771 [LLDP_SYSTEM_CAPABILITIES_PHONE
] = "T",
772 [LLDP_SYSTEM_CAPABILITIES_DOCSIS
] = "D",
773 [LLDP_SYSTEM_CAPABILITIES_STATION
] = "A",
774 [LLDP_SYSTEM_CAPABILITIES_CVLAN
] = "C",
775 [LLDP_SYSTEM_CAPABILITIES_SVLAN
] = "S",
776 [LLDP_SYSTEM_CAPABILITIES_TPMR
] = "M",
777 [_LLDP_SYSTEM_CAPABILITIES_MAX
] = "N/A",
780 DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability
, LLDPSystemCapabilities
);
782 static char *lldp_system_caps(uint16_t cap
) {
783 _cleanup_free_
char *s
= NULL
, *t
= NULL
;
790 if (cap
& LLDP_SYSTEM_CAPABILITIES_OTHER
) {
791 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER
), " ", NULL
);
799 if (cap
& LLDP_SYSTEM_CAPABILITIES_REPEATER
) {
800 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER
), " ", NULL
);
808 if (cap
& LLDP_SYSTEM_CAPABILITIES_BRIDGE
) {
809 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE
), " ", NULL
);
817 if (cap
& LLDP_SYSTEM_CAPABILITIES_WLAN_AP
) {
818 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP
), " ", NULL
);
826 if (cap
& LLDP_SYSTEM_CAPABILITIES_ROUTER
) {
827 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER
), " ", NULL
);
835 if (cap
& LLDP_SYSTEM_CAPABILITIES_PHONE
) {
836 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE
), " ", NULL
);
844 if (cap
& LLDP_SYSTEM_CAPABILITIES_DOCSIS
) {
845 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS
), " ", NULL
);
853 if (cap
& LLDP_SYSTEM_CAPABILITIES_STATION
) {
854 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION
), " ", NULL
);
862 if (cap
& LLDP_SYSTEM_CAPABILITIES_CVLAN
) {
863 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN
), " ", NULL
);
871 if (cap
& LLDP_SYSTEM_CAPABILITIES_SVLAN
) {
872 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN
), " ", NULL
);
880 if (cap
& LLDP_SYSTEM_CAPABILITIES_TPMR
) {
881 s
= strappend(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR
));
889 s
= strappend(t
, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX
));
896 t
= strappend(s
, "]");
909 static int link_lldp_status(int argc
, char *argv
[], void *userdata
) {
910 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
911 _cleanup_netlink_unref_ sd_netlink
*rtnl
= NULL
;
912 _cleanup_free_ LinkInfo
*links
= NULL
;
913 const char *state
, *word
;
921 pager_open_if_enabled();
923 r
= sd_netlink_open(&rtnl
);
925 return log_error_errno(r
, "Failed to connect to netlink: %m");
927 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
929 return rtnl_log_create_error(r
);
931 r
= sd_netlink_message_request_dump(req
, true);
933 return rtnl_log_create_error(r
);
935 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
937 return log_error_errno(r
, "Failed to enumerate links: %m");
939 c
= decode_and_sort_links(reply
, &links
);
941 return rtnl_log_parse_error(c
);
944 printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
946 for (i
= j
= 0; i
< c
; i
++) {
947 _cleanup_free_
char *chassis
= NULL
, *port
= NULL
, *cap
= NULL
, *lldp
= NULL
;
948 _cleanup_strv_free_
char **l
= NULL
;
950 r
= sd_network_link_get_lldp(links
[i
].ifindex
, &lldp
);
954 l
= strv_split_newlines(lldp
);
959 FOREACH_WORD_QUOTED(word
, ll
, *s
, state
) {
960 _cleanup_free_
char *t
= NULL
, *a
= NULL
, *b
= NULL
;
962 t
= strndup(word
, ll
);
966 r
= split_pair(t
, "=", &a
, &b
);
970 if (streq(a
, "_Chassis")) {
971 r
= free_and_strdup(&chassis
, b
);
975 } else if (streq(a
, "_Port")) {
976 r
= free_and_strdup(&port
, b
);
980 } else if (streq(a
, "_TTL")) {
981 long long unsigned x
= 0;
984 r
= safe_atollu(b
, &x
);
985 if (r
< 0 || (usec_t
) x
!= x
)
986 return log_warning_errno(r
< 0 ? r
: ERANGE
,
987 "Failed to parse TTL \"%s\": %m", b
);
989 time
= now(clock_boottime_or_monotonic());
993 ttl
= (double) (x
- time
) / USEC_PER_SEC
;
995 } else if (streq(a
, "_CAP")) {
996 sscanf(b
, "%x", &capability
);
998 cap
= lldp_system_caps(capability
);
1004 printf("%10s %24s %16s %16f %16s\n",
1006 strna(chassis
), strna(port
),
1014 printf("\nCapability Codes:\n"
1015 "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
1016 "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
1017 "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
1019 printf("Total entries displayed: %d\n", j
);
1025 static void help(void) {
1026 printf("%s [OPTIONS...]\n\n"
1027 "Query and control the networking subsystem.\n\n"
1028 " -h --help Show this help\n"
1029 " --version Show package version\n"
1030 " --no-pager Do not pipe output into a pager\n"
1031 " --no-legend Do not show the headers and footers\n"
1032 " -a --all Show status for all links\n\n"
1034 " list List links\n"
1035 " status [LINK...] Show link status\n"
1036 " lldp Show lldp information\n"
1037 , program_invocation_short_name
);
1040 static int parse_argv(int argc
, char *argv
[]) {
1043 ARG_VERSION
= 0x100,
1048 static const struct option options
[] = {
1049 { "help", no_argument
, NULL
, 'h' },
1050 { "version", no_argument
, NULL
, ARG_VERSION
},
1051 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1052 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1053 { "all", no_argument
, NULL
, 'a' },
1062 while ((c
= getopt_long(argc
, argv
, "ha", options
, NULL
)) >= 0) {
1074 arg_no_pager
= true;
1089 assert_not_reached("Unhandled option");
1096 static int networkctl_main(int argc
, char *argv
[]) {
1097 const Verb verbs
[] = {
1098 { "list", VERB_ANY
, 1, VERB_DEFAULT
, list_links
},
1099 { "status", 1, VERB_ANY
, 0, link_status
},
1100 { "lldp", VERB_ANY
, 1, VERB_DEFAULT
, link_lldp_status
},
1104 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1107 int main(int argc
, char* argv
[]) {
1110 log_parse_environment();
1113 r
= parse_argv(argc
, argv
);
1117 r
= networkctl_main(argc
, argv
);
1122 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;