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-network.h"
36 #include "rtnl-util.h"
37 #include "udev-util.h"
38 #include "hwdb-util.h"
39 #include "arphrd-list.h"
40 #include "local-addresses.h"
41 #include "socket-util.h"
42 #include "ether-addr-util.h"
45 static bool arg_no_pager
= false;
46 static bool arg_legend
= true;
47 static bool arg_all
= false;
49 static void pager_open_if_enabled(void) {
57 static int link_get_type_string(int iftype
, struct udev_device
*d
, char **ret
) {
61 if (iftype
== ARPHRD_ETHER
&& d
) {
62 const char *devtype
, *id
= NULL
;
63 /* WLANs have iftype ARPHRD_ETHER, but we want
64 * to show a more useful type string for
67 devtype
= udev_device_get_devtype(d
);
68 if (streq_ptr(devtype
, "wlan"))
70 else if (streq_ptr(devtype
, "wwan"))
83 t
= arphrd_to_name(iftype
);
99 typedef struct LinkInfo
{
105 static int link_info_compare(const void *a
, const void *b
) {
106 const LinkInfo
*x
= a
, *y
= b
;
108 return x
->ifindex
- y
->ifindex
;
111 static int decode_and_sort_links(sd_rtnl_message
*m
, LinkInfo
**ret
) {
112 _cleanup_free_ LinkInfo
*links
= NULL
;
113 size_t size
= 0, c
= 0;
117 for (i
= m
; i
; i
= sd_rtnl_message_next(i
)) {
123 r
= sd_rtnl_message_get_type(i
, &type
);
127 if (type
!= RTM_NEWLINK
)
130 r
= sd_rtnl_message_link_get_ifindex(i
, &ifindex
);
134 r
= sd_rtnl_message_read_string(i
, IFLA_IFNAME
, &name
);
138 r
= sd_rtnl_message_link_get_type(i
, &iftype
);
142 if (!GREEDY_REALLOC(links
, size
, c
+1))
145 links
[c
].name
= name
;
146 links
[c
].ifindex
= ifindex
;
147 links
[c
].iftype
= iftype
;
151 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
159 static void operational_state_to_color(const char *state
, const char **on
, const char **off
) {
163 if (streq_ptr(state
, "routable")) {
164 *on
= ansi_highlight_green();
165 *off
= ansi_highlight_off();
166 } else if (streq_ptr(state
, "degraded")) {
167 *on
= ansi_highlight_yellow();
168 *off
= ansi_highlight_off();
173 static void setup_state_to_color(const char *state
, const char **on
, const char **off
) {
177 if (streq_ptr(state
, "configured")) {
178 *on
= ansi_highlight_green();
179 *off
= ansi_highlight_off();
180 } else if (streq_ptr(state
, "configuring")) {
181 *on
= ansi_highlight_yellow();
182 *off
= ansi_highlight_off();
183 } else if (streq_ptr(state
, "failed") || streq_ptr(state
, "linger")) {
184 *on
= ansi_highlight_red();
185 *off
= ansi_highlight_off();
190 static int list_links(int argc
, char *argv
[], void *userdata
) {
191 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
192 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
193 _cleanup_rtnl_unref_ sd_rtnl
*rtnl
= NULL
;
194 _cleanup_free_ LinkInfo
*links
= NULL
;
197 pager_open_if_enabled();
199 r
= sd_rtnl_open(&rtnl
, 0);
201 return log_error_errno(r
, "Failed to connect to netlink: %m");
205 return log_error_errno(errno
, "Failed to connect to udev: %m");
207 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
209 return rtnl_log_create_error(r
);
211 r
= sd_rtnl_message_request_dump(req
, true);
213 return rtnl_log_create_error(r
);
215 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
217 return log_error_errno(r
, "Failed to enumerate links: %m");
220 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
222 c
= decode_and_sort_links(reply
, &links
);
224 return rtnl_log_parse_error(c
);
226 for (i
= 0; i
< c
; i
++) {
227 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
;
228 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
229 const char *on_color_operational
, *off_color_operational
,
230 *on_color_setup
, *off_color_setup
;
231 char devid
[2 + DECIMAL_STR_MAX(int)];
232 _cleanup_free_
char *t
= NULL
;
234 sd_network_link_get_operational_state(links
[i
].ifindex
, &operational_state
);
235 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
237 sd_network_link_get_setup_state(links
[i
].ifindex
, &setup_state
);
238 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
240 sprintf(devid
, "n%i", links
[i
].ifindex
);
241 d
= udev_device_new_from_device_id(udev
, devid
);
243 link_get_type_string(links
[i
].iftype
, d
, &t
);
245 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
246 links
[i
].ifindex
, links
[i
].name
, strna(t
),
247 on_color_operational
, strna(operational_state
), off_color_operational
,
248 on_color_setup
, strna(setup_state
), off_color_setup
);
252 printf("\n%i links listed.\n", c
);
257 /* IEEE Organizationally Unique Identifier vendor string */
258 static int ieee_oui(sd_hwdb
*hwdb
, struct ether_addr
*mac
, char **ret
) {
259 const char *description
;
260 char modalias
[strlen("OUI:XXYYXXYYXXYY") + 1], *desc
;
271 /* skip commonly misused 00:00:00 (Xerox) prefix */
272 if (memcmp(mac
, "\0\0\0", 3) == 0)
275 snprintf(modalias
, sizeof(modalias
), "OUI:" ETHER_ADDR_FORMAT_STR
, ETHER_ADDR_FORMAT_VAL(*mac
));
277 r
= sd_hwdb_get(hwdb
, modalias
, "ID_OUI_FROM_DATABASE", &description
);
281 desc
= strdup(description
);
290 static int get_gateway_description(
295 union in_addr_union
*gateway
,
296 char **gateway_description
) {
297 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
302 assert(ifindex
>= 0);
303 assert(family
== AF_INET
|| family
== AF_INET6
);
305 assert(gateway_description
);
307 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_GETNEIGH
, ifindex
, family
);
311 r
= sd_rtnl_message_request_dump(req
, true);
315 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
319 for (m
= reply
; m
; m
= sd_rtnl_message_next(m
)) {
320 union in_addr_union gw
= {};
321 struct ether_addr mac
= {};
325 r
= sd_rtnl_message_get_errno(m
);
327 log_error_errno(r
, "got error: %m");
331 r
= sd_rtnl_message_get_type(m
, &type
);
333 log_error_errno(r
, "could not get type: %m");
337 if (type
!= RTM_NEWNEIGH
) {
338 log_error("type is not RTM_NEWNEIGH");
342 r
= sd_rtnl_message_neigh_get_family(m
, &fam
);
344 log_error_errno(r
, "could not get family: %m");
349 log_error("family is not correct");
353 r
= sd_rtnl_message_neigh_get_ifindex(m
, &ifi
);
355 log_error_errno(r
, "could not get ifindex: %m");
359 if (ifindex
> 0 && ifi
!= ifindex
)
364 r
= sd_rtnl_message_read_in_addr(m
, NDA_DST
, &gw
.in
);
370 r
= sd_rtnl_message_read_in6_addr(m
, NDA_DST
, &gw
.in6
);
379 if (!in_addr_equal(fam
, &gw
, gateway
))
382 r
= sd_rtnl_message_read_ether_addr(m
, NDA_LLADDR
, &mac
);
386 r
= ieee_oui(hwdb
, &mac
, gateway_description
);
396 static int dump_gateways(
401 _cleanup_free_
struct local_address
*local
= NULL
;
404 n
= local_gateways(rtnl
, ifindex
, AF_UNSPEC
, &local
);
408 for (i
= 0; i
< n
; i
++) {
409 _cleanup_free_
char *gateway
= NULL
, *description
= NULL
;
411 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &gateway
);
415 r
= get_gateway_description(rtnl
, hwdb
, local
[i
].ifindex
, local
[i
].family
, &local
[i
].address
, &description
);
417 log_debug_errno(r
, "Could not get description of gateway: %m");
420 (int) strlen(prefix
),
421 i
== 0 ? prefix
: "",
425 printf(" (%s)", description
);
427 /* Show interface name for the entry if we show
428 * entries for all interfaces */
430 char name
[IF_NAMESIZE
+1];
432 if (if_indextoname(local
[i
].ifindex
, name
)) {
433 fputs(" on ", stdout
);
436 printf(" on %%%i", local
[i
].ifindex
);
445 static int dump_addresses(
450 _cleanup_free_
struct local_address
*local
= NULL
;
453 n
= local_addresses(rtnl
, ifindex
, AF_UNSPEC
, &local
);
457 for (i
= 0; i
< n
; i
++) {
458 _cleanup_free_
char *pretty
= NULL
;
460 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &pretty
);
465 (int) strlen(prefix
),
466 i
== 0 ? prefix
: "",
470 char name
[IF_NAMESIZE
+1];
472 if (if_indextoname(local
[i
].ifindex
, name
)) {
473 fputs(" on ", stdout
);
476 printf(" on %%%i", local
[i
].ifindex
);
485 static void dump_list(const char *prefix
, char **l
) {
490 (int) strlen(prefix
),
491 i
== l
? prefix
: "",
496 static int link_status_one(
502 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **domains
= NULL
;
503 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
;
504 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
505 _cleanup_udev_device_unref_
struct udev_device
*d
= NULL
;
506 char devid
[2 + DECIMAL_STR_MAX(int)];
507 _cleanup_free_
char *t
= NULL
, *network
= NULL
;
508 const char *driver
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *link
= NULL
;
509 const char *on_color_operational
, *off_color_operational
,
510 *on_color_setup
, *off_color_setup
;
511 _cleanup_strv_free_
char **carrier_bound_to
= NULL
;
512 _cleanup_strv_free_
char **carrier_bound_by
= NULL
;
523 if (safe_atoi(name
, &ifindex
) >= 0 && ifindex
> 0)
524 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, ifindex
);
526 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
528 return rtnl_log_create_error(r
);
530 r
= sd_rtnl_message_append_string(req
, IFLA_IFNAME
, name
);
534 return rtnl_log_create_error(r
);
536 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
538 return log_error_errno(r
, "Failed to query link: %m");
540 r
= sd_rtnl_message_link_get_ifindex(reply
, &ifindex
);
542 return rtnl_log_parse_error(r
);
544 r
= sd_rtnl_message_read_string(reply
, IFLA_IFNAME
, &name
);
546 return rtnl_log_parse_error(r
);
548 r
= sd_rtnl_message_link_get_type(reply
, &iftype
);
550 return rtnl_log_parse_error(r
);
552 have_mac
= sd_rtnl_message_read_ether_addr(reply
, IFLA_ADDRESS
, &e
) >= 0;
556 bool all_zeroes
= true;
558 for (p
= (uint8_t*) &e
; p
< (uint8_t*) &e
+ sizeof(e
); p
++)
568 sd_rtnl_message_read_u32(reply
, IFLA_MTU
, &mtu
);
570 sd_network_link_get_operational_state(ifindex
, &operational_state
);
571 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
573 sd_network_link_get_setup_state(ifindex
, &setup_state
);
574 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
576 sd_network_link_get_dns(ifindex
, &dns
);
577 sd_network_link_get_ntp(ifindex
, &ntp
);
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
);
592 d
= udev_device_new_from_device_id(udev
, devid
);
594 link
= udev_device_get_property_value(d
, "ID_NET_LINK_FILE");
595 driver
= udev_device_get_property_value(d
, "ID_NET_DRIVER");
596 path
= udev_device_get_property_value(d
, "ID_PATH");
598 vendor
= udev_device_get_property_value(d
, "ID_VENDOR_FROM_DATABASE");
600 vendor
= udev_device_get_property_value(d
, "ID_VENDOR");
602 model
= udev_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE");
604 model
= udev_device_get_property_value(d
, "ID_MODEL");
607 link_get_type_string(iftype
, d
, &t
);
609 sd_network_link_get_network_file(ifindex
, &network
);
611 sd_network_link_get_carrier_bound_to(ifindex
, &carrier_bound_to
);
612 sd_network_link_get_carrier_bound_by(ifindex
, &carrier_bound_by
);
614 printf("%s%s%s %i: %s\n", on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
, ifindex
, name
);
616 printf(" Link File: %s\n"
617 " Network File: %s\n"
619 " State: %s%s%s (%s%s%s)\n",
623 on_color_operational
, strna(operational_state
), off_color_operational
,
624 on_color_setup
, strna(setup_state
), off_color_setup
);
627 printf(" Path: %s\n", path
);
629 printf(" Driver: %s\n", driver
);
631 printf(" Vendor: %s\n", vendor
);
633 printf(" Model: %s\n", model
);
636 _cleanup_free_
char *description
= NULL
;
637 char ea
[ETHER_ADDR_TO_STRING_MAX
];
639 ieee_oui(hwdb
, &e
, &description
);
642 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e
, ea
), description
);
644 printf(" HW Address: %s\n", ether_addr_to_string(&e
, ea
));
648 printf(" MTU: %u\n", mtu
);
650 dump_addresses(rtnl
, " Address: ", ifindex
);
651 dump_gateways(rtnl
, hwdb
, " Gateway: ", ifindex
);
653 if (!strv_isempty(dns
))
654 dump_list(" DNS: ", dns
);
655 if (!strv_isempty(domains
))
656 dump_list(" Domain: ", domains
);
657 if (!strv_isempty(ntp
))
658 dump_list(" NTP: ", ntp
);
660 if (!strv_isempty(carrier_bound_to
))
661 dump_list("Carrier Bound To: ", carrier_bound_to
);
663 if (!strv_isempty(carrier_bound_by
))
664 dump_list("Carrier Bound By: ", carrier_bound_by
);
669 static int link_status(int argc
, char *argv
[], void *userdata
) {
670 _cleanup_hwdb_unref_ sd_hwdb
*hwdb
= NULL
;
671 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
672 _cleanup_rtnl_unref_ sd_rtnl
*rtnl
= NULL
;
676 r
= sd_rtnl_open(&rtnl
, 0);
678 return log_error_errno(r
, "Failed to connect to netlink: %m");
682 return log_error_errno(errno
, "Failed to connect to udev: %m");
684 r
= sd_hwdb_new(&hwdb
);
686 log_debug_errno(r
, "Failed to open hardware database: %m");
688 if (argc
<= 1 && !arg_all
) {
689 _cleanup_free_
char *operational_state
= NULL
;
690 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **domains
= NULL
;
691 const char *on_color_operational
, *off_color_operational
;
693 sd_network_get_operational_state(&operational_state
);
694 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
696 printf("%s%s%s State: %s%s%s\n",
697 on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
,
698 on_color_operational
, strna(operational_state
), off_color_operational
);
700 dump_addresses(rtnl
, " Address: ", 0);
701 dump_gateways(rtnl
, hwdb
, " Gateway: ", 0);
703 sd_network_get_dns(&dns
);
704 if (!strv_isempty(dns
))
705 dump_list(" DNS: ", dns
);
707 sd_network_get_domains(&domains
);
708 if (!strv_isempty(domains
))
709 dump_list(" Domain: ", domains
);
711 sd_network_get_ntp(&ntp
);
712 if (!strv_isempty(ntp
))
713 dump_list(" NTP: ", ntp
);
718 pager_open_if_enabled();
721 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
722 _cleanup_free_ LinkInfo
*links
= NULL
;
725 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
727 return rtnl_log_create_error(r
);
729 r
= sd_rtnl_message_request_dump(req
, true);
731 return rtnl_log_create_error(r
);
733 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
735 return log_error_errno(r
, "Failed to enumerate links: %m");
737 c
= decode_and_sort_links(reply
, &links
);
739 return rtnl_log_parse_error(c
);
741 for (i
= 0; i
< c
; i
++) {
745 link_status_one(rtnl
, udev
, hwdb
, links
[i
].name
);
748 STRV_FOREACH(name
, argv
+ 1) {
749 if (name
!= argv
+ 1)
752 link_status_one(rtnl
, udev
, hwdb
, *name
);
759 const char *lldp_system_capability_to_string(LLDPSystemCapabilities d
) _const_
;
760 LLDPSystemCapabilities
lldp_system_capability_from_string(const char *d
) _pure_
;
762 static const char* const lldp_system_capability_table
[_LLDP_SYSTEM_CAPABILITIES_MAX
+ 1] = {
763 [LLDP_SYSTEM_CAPABILITIES_OTHER
] = "O",
764 [LLDP_SYSTEM_CAPABILITIES_REPEATER
] = "P",
765 [LLDP_SYSTEM_CAPABILITIES_BRIDGE
] = "B",
766 [LLDP_SYSTEM_CAPABILITIES_WLAN_AP
] = "W",
767 [LLDP_SYSTEM_CAPABILITIES_ROUTER
] = "R",
768 [LLDP_SYSTEM_CAPABILITIES_PHONE
] = "T",
769 [LLDP_SYSTEM_CAPABILITIES_DOCSIS
] = "D",
770 [LLDP_SYSTEM_CAPABILITIES_STATION
] = "A",
771 [LLDP_SYSTEM_CAPABILITIES_CVLAN
] = "C",
772 [LLDP_SYSTEM_CAPABILITIES_SVLAN
] = "S",
773 [LLDP_SYSTEM_CAPABILITIES_TPMR
] = "M",
774 [_LLDP_SYSTEM_CAPABILITIES_MAX
] = "N/A",
777 DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability
, LLDPSystemCapabilities
);
779 static char *lldp_system_caps(uint16_t cap
) {
780 _cleanup_free_
char *s
= NULL
, *t
= NULL
;
787 if (cap
& LLDP_SYSTEM_CAPABILITIES_OTHER
) {
788 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER
), " ", NULL
);
796 if (cap
& LLDP_SYSTEM_CAPABILITIES_REPEATER
) {
797 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER
), " ", NULL
);
805 if (cap
& LLDP_SYSTEM_CAPABILITIES_BRIDGE
) {
806 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE
), " ", NULL
);
814 if (cap
& LLDP_SYSTEM_CAPABILITIES_WLAN_AP
) {
815 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP
), " ", NULL
);
823 if (cap
& LLDP_SYSTEM_CAPABILITIES_ROUTER
) {
824 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER
), " ", NULL
);
832 if (cap
& LLDP_SYSTEM_CAPABILITIES_PHONE
) {
833 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE
), " ", NULL
);
841 if (cap
& LLDP_SYSTEM_CAPABILITIES_DOCSIS
) {
842 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS
), " ", NULL
);
850 if (cap
& LLDP_SYSTEM_CAPABILITIES_STATION
) {
851 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION
), " ", NULL
);
859 if (cap
& LLDP_SYSTEM_CAPABILITIES_CVLAN
) {
860 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN
), " ", NULL
);
868 if (cap
& LLDP_SYSTEM_CAPABILITIES_SVLAN
) {
869 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN
), " ", NULL
);
877 if (cap
& LLDP_SYSTEM_CAPABILITIES_TPMR
) {
878 s
= strappend(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR
));
886 s
= strappend(t
, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX
));
893 t
= strappend(s
, "]");
906 static int link_lldp_status(int argc
, char *argv
[], void *userdata
) {
907 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
908 _cleanup_rtnl_unref_ sd_rtnl
*rtnl
= NULL
;
909 _cleanup_free_ LinkInfo
*links
= NULL
;
910 const char *state
, *word
;
918 pager_open_if_enabled();
920 r
= sd_rtnl_open(&rtnl
, 0);
922 return log_error_errno(r
, "Failed to connect to netlink: %m");
924 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
926 return rtnl_log_create_error(r
);
928 r
= sd_rtnl_message_request_dump(req
, true);
930 return rtnl_log_create_error(r
);
932 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
934 return log_error_errno(r
, "Failed to enumerate links: %m");
936 c
= decode_and_sort_links(reply
, &links
);
938 return rtnl_log_parse_error(c
);
941 printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
943 for (i
= j
= 0; i
< c
; i
++) {
944 _cleanup_free_
char *chassis
= NULL
, *port
= NULL
, *cap
= NULL
, *lldp
= NULL
;
945 _cleanup_strv_free_
char **l
= NULL
;
947 r
= sd_network_link_get_lldp(links
[i
].ifindex
, &lldp
);
951 l
= strv_split_newlines(lldp
);
956 FOREACH_WORD_QUOTED(word
, ll
, *s
, state
) {
957 _cleanup_free_
char *t
= NULL
, *a
= NULL
, *b
= NULL
;
959 t
= strndup(word
, ll
);
963 r
= split_pair(t
, "=", &a
, &b
);
967 if (streq(a
, "_Chassis")) {
972 } else if (streq(a
, "_Port")) {
977 } else if (streq(a
, "_TTL")) {
978 long long unsigned x
;
981 r
= safe_atollu(b
, &x
);
982 if (r
< 0 || (usec_t
) x
!= x
)
983 return log_warning_errno(r
< 0 ? r
: ERANGE
,
984 "Failed to parse TTL \"%s\": %m", b
);
986 time
= now(CLOCK_BOOTTIME
);
990 ttl
= (double) (x
- time
) / USEC_PER_SEC
;
992 } else if (streq(a
, "_CAP")) {
993 sscanf(b
, "%x", &capability
);
995 cap
= lldp_system_caps(capability
);
1001 printf("%10s %24s %16s %16f %16s\n",
1003 strna(chassis
), strna(port
),
1011 printf("\nCapability Codes:\n"
1012 "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
1013 "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
1014 "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
1016 printf("Total entries displayed: %d\n", j
);
1022 static void help(void) {
1023 printf("%s [OPTIONS...]\n\n"
1024 "Query and control the networking subsystem.\n\n"
1025 " -h --help Show this help\n"
1026 " --version Show package version\n"
1027 " --no-pager Do not pipe output into a pager\n"
1028 " --no-legend Do not show the headers and footers\n"
1029 " -a --all Show status for all links\n\n"
1031 " list List links\n"
1032 " status [LINK...] Show link status\n"
1033 " lldp Show lldp information\n"
1034 , program_invocation_short_name
);
1037 static int parse_argv(int argc
, char *argv
[]) {
1040 ARG_VERSION
= 0x100,
1045 static const struct option options
[] = {
1046 { "help", no_argument
, NULL
, 'h' },
1047 { "version", no_argument
, NULL
, ARG_VERSION
},
1048 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1049 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1050 { "all", no_argument
, NULL
, 'a' },
1059 while ((c
= getopt_long(argc
, argv
, "ha", options
, NULL
)) >= 0) {
1068 puts(PACKAGE_STRING
);
1069 puts(SYSTEMD_FEATURES
);
1073 arg_no_pager
= true;
1088 assert_not_reached("Unhandled option");
1095 static int networkctl_main(int argc
, char *argv
[]) {
1096 const Verb verbs
[] = {
1097 { "list", VERB_ANY
, 1, VERB_DEFAULT
, list_links
},
1098 { "status", 1, VERB_ANY
, 0, link_status
},
1099 { "lldp", VERB_ANY
, 1, VERB_DEFAULT
, link_lldp_status
},
1103 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1106 int main(int argc
, char* argv
[]) {
1109 log_parse_environment();
1112 r
= parse_argv(argc
, argv
);
1116 r
= networkctl_main(argc
, argv
);
1121 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;