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"
27 #include "sd-netlink.h"
29 #include "sd-device.h"
36 #include "netlink-util.h"
37 #include "device-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"
44 #include "terminal-util.h"
46 static bool arg_no_pager
= false;
47 static bool arg_legend
= true;
48 static bool arg_all
= false;
50 static void pager_open_if_enabled(void) {
58 static int link_get_type_string(int iftype
, sd_device
*d
, char **ret
) {
64 if (iftype
== ARPHRD_ETHER
&& d
) {
65 const char *devtype
= NULL
, *id
= NULL
;
66 /* WLANs have iftype ARPHRD_ETHER, but we want
67 * to show a more useful type string for
70 (void)sd_device_get_devtype(d
, &devtype
);
72 if (streq_ptr(devtype
, "wlan"))
74 else if (streq_ptr(devtype
, "wwan"))
87 t
= arphrd_to_name(iftype
);
103 typedef struct LinkInfo
{
109 static int link_info_compare(const void *a
, const void *b
) {
110 const LinkInfo
*x
= a
, *y
= b
;
112 return x
->ifindex
- y
->ifindex
;
115 static int decode_and_sort_links(sd_netlink_message
*m
, LinkInfo
**ret
) {
116 _cleanup_free_ LinkInfo
*links
= NULL
;
117 size_t size
= 0, c
= 0;
118 sd_netlink_message
*i
;
121 for (i
= m
; i
; i
= sd_netlink_message_next(i
)) {
127 r
= sd_netlink_message_get_type(i
, &type
);
131 if (type
!= RTM_NEWLINK
)
134 r
= sd_rtnl_message_link_get_ifindex(i
, &ifindex
);
138 r
= sd_netlink_message_read_string(i
, IFLA_IFNAME
, &name
);
142 r
= sd_rtnl_message_link_get_type(i
, &iftype
);
146 if (!GREEDY_REALLOC(links
, size
, c
+1))
149 links
[c
].name
= name
;
150 links
[c
].ifindex
= ifindex
;
151 links
[c
].iftype
= iftype
;
155 qsort_safe(links
, c
, sizeof(LinkInfo
), link_info_compare
);
163 static void operational_state_to_color(const char *state
, const char **on
, const char **off
) {
167 if (streq_ptr(state
, "routable")) {
168 *on
= ansi_highlight_green();
169 *off
= ansi_highlight_off();
170 } else if (streq_ptr(state
, "degraded")) {
171 *on
= ansi_highlight_yellow();
172 *off
= ansi_highlight_off();
177 static void setup_state_to_color(const char *state
, const char **on
, const char **off
) {
181 if (streq_ptr(state
, "configured")) {
182 *on
= ansi_highlight_green();
183 *off
= ansi_highlight_off();
184 } else if (streq_ptr(state
, "configuring")) {
185 *on
= ansi_highlight_yellow();
186 *off
= ansi_highlight_off();
187 } else if (streq_ptr(state
, "failed") || streq_ptr(state
, "linger")) {
188 *on
= ansi_highlight_red();
189 *off
= ansi_highlight_off();
194 static int list_links(int argc
, char *argv
[], void *userdata
) {
195 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
196 _cleanup_netlink_unref_ sd_netlink
*rtnl
= NULL
;
197 _cleanup_free_ LinkInfo
*links
= NULL
;
200 pager_open_if_enabled();
202 r
= sd_netlink_open(&rtnl
);
204 return log_error_errno(r
, "Failed to connect to netlink: %m");
206 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
208 return rtnl_log_create_error(r
);
210 r
= sd_netlink_message_request_dump(req
, true);
212 return rtnl_log_create_error(r
);
214 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
216 return log_error_errno(r
, "Failed to enumerate links: %m");
219 printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
221 c
= decode_and_sort_links(reply
, &links
);
223 return rtnl_log_parse_error(c
);
225 for (i
= 0; i
< c
; i
++) {
226 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
;
227 _cleanup_device_unref_ sd_device
*d
= NULL
;
228 const char *on_color_operational
, *off_color_operational
,
229 *on_color_setup
, *off_color_setup
;
230 char devid
[2 + DECIMAL_STR_MAX(int)];
231 _cleanup_free_
char *t
= NULL
;
233 sd_network_link_get_operational_state(links
[i
].ifindex
, &operational_state
);
234 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
236 sd_network_link_get_setup_state(links
[i
].ifindex
, &setup_state
);
237 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
239 sprintf(devid
, "n%i", links
[i
].ifindex
);
240 (void)sd_device_new_from_device_id(&d
, devid
);
242 link_get_type_string(links
[i
].iftype
, d
, &t
);
244 printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
245 links
[i
].ifindex
, links
[i
].name
, strna(t
),
246 on_color_operational
, strna(operational_state
), off_color_operational
,
247 on_color_setup
, strna(setup_state
), off_color_setup
);
251 printf("\n%i links listed.\n", c
);
256 /* IEEE Organizationally Unique Identifier vendor string */
257 static int ieee_oui(sd_hwdb
*hwdb
, struct ether_addr
*mac
, char **ret
) {
258 const char *description
;
259 char modalias
[strlen("OUI:XXYYXXYYXXYY") + 1], *desc
;
270 /* skip commonly misused 00:00:00 (Xerox) prefix */
271 if (memcmp(mac
, "\0\0\0", 3) == 0)
274 snprintf(modalias
, sizeof(modalias
), "OUI:" ETHER_ADDR_FORMAT_STR
, ETHER_ADDR_FORMAT_VAL(*mac
));
276 r
= sd_hwdb_get(hwdb
, modalias
, "ID_OUI_FROM_DATABASE", &description
);
280 desc
= strdup(description
);
289 static int get_gateway_description(
294 union in_addr_union
*gateway
,
295 char **gateway_description
) {
296 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
297 sd_netlink_message
*m
;
301 assert(ifindex
>= 0);
302 assert(family
== AF_INET
|| family
== AF_INET6
);
304 assert(gateway_description
);
306 r
= sd_rtnl_message_new_neigh(rtnl
, &req
, RTM_GETNEIGH
, ifindex
, family
);
310 r
= sd_netlink_message_request_dump(req
, true);
314 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
318 for (m
= reply
; m
; m
= sd_netlink_message_next(m
)) {
319 union in_addr_union gw
= {};
320 struct ether_addr mac
= {};
324 r
= sd_netlink_message_get_errno(m
);
326 log_error_errno(r
, "got error: %m");
330 r
= sd_netlink_message_get_type(m
, &type
);
332 log_error_errno(r
, "could not get type: %m");
336 if (type
!= RTM_NEWNEIGH
) {
337 log_error("type is not RTM_NEWNEIGH");
341 r
= sd_rtnl_message_neigh_get_family(m
, &fam
);
343 log_error_errno(r
, "could not get family: %m");
348 log_error("family is not correct");
352 r
= sd_rtnl_message_neigh_get_ifindex(m
, &ifi
);
354 log_error_errno(r
, "could not get ifindex: %m");
358 if (ifindex
> 0 && ifi
!= ifindex
)
363 r
= sd_netlink_message_read_in_addr(m
, NDA_DST
, &gw
.in
);
369 r
= sd_netlink_message_read_in6_addr(m
, NDA_DST
, &gw
.in6
);
378 if (!in_addr_equal(fam
, &gw
, gateway
))
381 r
= sd_netlink_message_read_ether_addr(m
, NDA_LLADDR
, &mac
);
385 r
= ieee_oui(hwdb
, &mac
, gateway_description
);
395 static int dump_gateways(
400 _cleanup_free_
struct local_address
*local
= NULL
;
403 n
= local_gateways(rtnl
, ifindex
, AF_UNSPEC
, &local
);
407 for (i
= 0; i
< n
; i
++) {
408 _cleanup_free_
char *gateway
= NULL
, *description
= NULL
;
410 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &gateway
);
414 r
= get_gateway_description(rtnl
, hwdb
, local
[i
].ifindex
, local
[i
].family
, &local
[i
].address
, &description
);
416 log_debug_errno(r
, "Could not get description of gateway: %m");
419 (int) strlen(prefix
),
420 i
== 0 ? prefix
: "",
424 printf(" (%s)", description
);
426 /* Show interface name for the entry if we show
427 * entries for all interfaces */
429 char name
[IF_NAMESIZE
+1];
431 if (if_indextoname(local
[i
].ifindex
, name
)) {
432 fputs(" on ", stdout
);
435 printf(" on %%%i", local
[i
].ifindex
);
444 static int dump_addresses(
449 _cleanup_free_
struct local_address
*local
= NULL
;
452 n
= local_addresses(rtnl
, ifindex
, AF_UNSPEC
, &local
);
456 for (i
= 0; i
< n
; i
++) {
457 _cleanup_free_
char *pretty
= NULL
;
459 r
= in_addr_to_string(local
[i
].family
, &local
[i
].address
, &pretty
);
464 (int) strlen(prefix
),
465 i
== 0 ? prefix
: "",
469 char name
[IF_NAMESIZE
+1];
471 if (if_indextoname(local
[i
].ifindex
, name
)) {
472 fputs(" on ", stdout
);
475 printf(" on %%%i", local
[i
].ifindex
);
484 static void dump_list(const char *prefix
, char **l
) {
489 (int) strlen(prefix
),
490 i
== l
? prefix
: "",
495 static int link_status_one(
499 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **domains
= NULL
;
500 _cleanup_free_
char *setup_state
= NULL
, *operational_state
= NULL
, *tz
= NULL
;
501 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
502 _cleanup_device_unref_ sd_device
*d
= NULL
;
503 char devid
[2 + DECIMAL_STR_MAX(int)];
504 _cleanup_free_
char *t
= NULL
, *network
= NULL
;
505 const char *driver
= NULL
, *path
= NULL
, *vendor
= NULL
, *model
= NULL
, *link
= NULL
;
506 const char *on_color_operational
, *off_color_operational
,
507 *on_color_setup
, *off_color_setup
;
508 _cleanup_strv_free_
char **carrier_bound_to
= NULL
;
509 _cleanup_strv_free_
char **carrier_bound_by
= NULL
;
519 if (safe_atoi(name
, &ifindex
) >= 0 && ifindex
> 0)
520 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, ifindex
);
522 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
524 return rtnl_log_create_error(r
);
526 r
= sd_netlink_message_append_string(req
, IFLA_IFNAME
, name
);
530 return rtnl_log_create_error(r
);
532 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
534 return log_error_errno(r
, "Failed to query link: %m");
536 r
= sd_rtnl_message_link_get_ifindex(reply
, &ifindex
);
538 return rtnl_log_parse_error(r
);
540 r
= sd_netlink_message_read_string(reply
, IFLA_IFNAME
, &name
);
542 return rtnl_log_parse_error(r
);
544 r
= sd_rtnl_message_link_get_type(reply
, &iftype
);
546 return rtnl_log_parse_error(r
);
548 have_mac
= sd_netlink_message_read_ether_addr(reply
, IFLA_ADDRESS
, &e
) >= 0;
552 bool all_zeroes
= true;
554 for (p
= (uint8_t*) &e
; p
< (uint8_t*) &e
+ sizeof(e
); p
++)
564 sd_netlink_message_read_u32(reply
, IFLA_MTU
, &mtu
);
566 sd_network_link_get_operational_state(ifindex
, &operational_state
);
567 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
569 sd_network_link_get_setup_state(ifindex
, &setup_state
);
570 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
572 sd_network_link_get_dns(ifindex
, &dns
);
573 sd_network_link_get_domains(ifindex
, &domains
);
574 r
= sd_network_link_get_wildcard_domain(ifindex
);
578 wildcard
= strdup("*");
582 if (strv_consume(&domains
, wildcard
) < 0)
586 sprintf(devid
, "n%i", ifindex
);
588 (void)sd_device_new_from_device_id(&d
, devid
);
591 (void)sd_device_get_property_value(d
, "ID_NET_LINK_FILE", &link
);
592 (void)sd_device_get_property_value(d
, "ID_NET_DRIVER", &driver
);
593 (void)sd_device_get_property_value(d
, "ID_PATH", &path
);
595 r
= sd_device_get_property_value(d
, "ID_VENDOR_FROM_DATABASE", &vendor
);
597 (void)sd_device_get_property_value(d
, "ID_VENDOR", &vendor
);
599 r
= sd_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE", &model
);
601 (void)sd_device_get_property_value(d
, "ID_MODEL", &model
);
604 link_get_type_string(iftype
, d
, &t
);
606 sd_network_link_get_network_file(ifindex
, &network
);
608 sd_network_link_get_carrier_bound_to(ifindex
, &carrier_bound_to
);
609 sd_network_link_get_carrier_bound_by(ifindex
, &carrier_bound_by
);
611 printf("%s%s%s %i: %s\n", on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
, ifindex
, name
);
613 printf(" Link File: %s\n"
614 " Network File: %s\n"
616 " State: %s%s%s (%s%s%s)\n",
620 on_color_operational
, strna(operational_state
), off_color_operational
,
621 on_color_setup
, strna(setup_state
), off_color_setup
);
624 printf(" Path: %s\n", path
);
626 printf(" Driver: %s\n", driver
);
628 printf(" Vendor: %s\n", vendor
);
630 printf(" Model: %s\n", model
);
633 _cleanup_free_
char *description
= NULL
;
634 char ea
[ETHER_ADDR_TO_STRING_MAX
];
636 ieee_oui(hwdb
, &e
, &description
);
639 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e
, ea
), description
);
641 printf(" HW Address: %s\n", ether_addr_to_string(&e
, ea
));
645 printf(" MTU: %u\n", mtu
);
647 dump_addresses(rtnl
, " Address: ", ifindex
);
648 dump_gateways(rtnl
, hwdb
, " Gateway: ", ifindex
);
650 if (!strv_isempty(dns
))
651 dump_list(" DNS: ", dns
);
652 if (!strv_isempty(domains
))
653 dump_list(" Domain: ", domains
);
655 (void) sd_network_link_get_ntp(ifindex
, &ntp
);
656 if (!strv_isempty(ntp
))
657 dump_list(" NTP: ", ntp
);
659 if (!strv_isempty(carrier_bound_to
))
660 dump_list("Carrier Bound To: ", carrier_bound_to
);
662 if (!strv_isempty(carrier_bound_by
))
663 dump_list("Carrier Bound By: ", carrier_bound_by
);
665 (void) sd_network_link_get_timezone(ifindex
, &tz
);
667 printf(" Time Zone: %s", tz
);
672 static int link_status(int argc
, char *argv
[], void *userdata
) {
673 _cleanup_hwdb_unref_ sd_hwdb
*hwdb
= NULL
;
674 _cleanup_netlink_unref_ sd_netlink
*rtnl
= NULL
;
678 r
= sd_netlink_open(&rtnl
);
680 return log_error_errno(r
, "Failed to connect to netlink: %m");
682 r
= sd_hwdb_new(&hwdb
);
684 log_debug_errno(r
, "Failed to open hardware database: %m");
686 if (argc
<= 1 && !arg_all
) {
687 _cleanup_free_
char *operational_state
= NULL
;
688 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **domains
= NULL
;
689 const char *on_color_operational
, *off_color_operational
;
691 sd_network_get_operational_state(&operational_state
);
692 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
694 printf("%s%s%s State: %s%s%s\n",
695 on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
,
696 on_color_operational
, strna(operational_state
), off_color_operational
);
698 dump_addresses(rtnl
, " Address: ", 0);
699 dump_gateways(rtnl
, hwdb
, " Gateway: ", 0);
701 sd_network_get_dns(&dns
);
702 if (!strv_isempty(dns
))
703 dump_list(" DNS: ", dns
);
705 sd_network_get_domains(&domains
);
706 if (!strv_isempty(domains
))
707 dump_list(" Domain: ", domains
);
709 sd_network_get_ntp(&ntp
);
710 if (!strv_isempty(ntp
))
711 dump_list(" NTP: ", ntp
);
716 pager_open_if_enabled();
719 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
720 _cleanup_free_ LinkInfo
*links
= NULL
;
723 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
725 return rtnl_log_create_error(r
);
727 r
= sd_netlink_message_request_dump(req
, true);
729 return rtnl_log_create_error(r
);
731 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
733 return log_error_errno(r
, "Failed to enumerate links: %m");
735 c
= decode_and_sort_links(reply
, &links
);
737 return rtnl_log_parse_error(c
);
739 for (i
= 0; i
< c
; i
++) {
743 link_status_one(rtnl
, hwdb
, links
[i
].name
);
746 STRV_FOREACH(name
, argv
+ 1) {
747 if (name
!= argv
+ 1)
750 link_status_one(rtnl
, hwdb
, *name
);
757 const char *lldp_system_capability_to_string(LLDPSystemCapabilities d
) _const_
;
758 LLDPSystemCapabilities
lldp_system_capability_from_string(const char *d
) _pure_
;
760 static const char* const lldp_system_capability_table
[_LLDP_SYSTEM_CAPABILITIES_MAX
+ 1] = {
761 [LLDP_SYSTEM_CAPABILITIES_OTHER
] = "O",
762 [LLDP_SYSTEM_CAPABILITIES_REPEATER
] = "P",
763 [LLDP_SYSTEM_CAPABILITIES_BRIDGE
] = "B",
764 [LLDP_SYSTEM_CAPABILITIES_WLAN_AP
] = "W",
765 [LLDP_SYSTEM_CAPABILITIES_ROUTER
] = "R",
766 [LLDP_SYSTEM_CAPABILITIES_PHONE
] = "T",
767 [LLDP_SYSTEM_CAPABILITIES_DOCSIS
] = "D",
768 [LLDP_SYSTEM_CAPABILITIES_STATION
] = "A",
769 [LLDP_SYSTEM_CAPABILITIES_CVLAN
] = "C",
770 [LLDP_SYSTEM_CAPABILITIES_SVLAN
] = "S",
771 [LLDP_SYSTEM_CAPABILITIES_TPMR
] = "M",
772 [_LLDP_SYSTEM_CAPABILITIES_MAX
] = "N/A",
775 DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability
, LLDPSystemCapabilities
);
777 static char *lldp_system_caps(uint16_t cap
) {
778 _cleanup_free_
char *s
= NULL
, *t
= NULL
;
785 if (cap
& LLDP_SYSTEM_CAPABILITIES_OTHER
) {
786 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER
), " ", NULL
);
794 if (cap
& LLDP_SYSTEM_CAPABILITIES_REPEATER
) {
795 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER
), " ", NULL
);
803 if (cap
& LLDP_SYSTEM_CAPABILITIES_BRIDGE
) {
804 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE
), " ", NULL
);
812 if (cap
& LLDP_SYSTEM_CAPABILITIES_WLAN_AP
) {
813 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP
), " ", NULL
);
821 if (cap
& LLDP_SYSTEM_CAPABILITIES_ROUTER
) {
822 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER
), " ", NULL
);
830 if (cap
& LLDP_SYSTEM_CAPABILITIES_PHONE
) {
831 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE
), " ", NULL
);
839 if (cap
& LLDP_SYSTEM_CAPABILITIES_DOCSIS
) {
840 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS
), " ", NULL
);
848 if (cap
& LLDP_SYSTEM_CAPABILITIES_STATION
) {
849 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION
), " ", NULL
);
857 if (cap
& LLDP_SYSTEM_CAPABILITIES_CVLAN
) {
858 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN
), " ", NULL
);
866 if (cap
& LLDP_SYSTEM_CAPABILITIES_SVLAN
) {
867 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN
), " ", NULL
);
875 if (cap
& LLDP_SYSTEM_CAPABILITIES_TPMR
) {
876 s
= strappend(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR
));
884 s
= strappend(t
, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX
));
891 t
= strappend(s
, "]");
904 static int link_lldp_status(int argc
, char *argv
[], void *userdata
) {
905 _cleanup_netlink_message_unref_ sd_netlink_message
*req
= NULL
, *reply
= NULL
;
906 _cleanup_netlink_unref_ sd_netlink
*rtnl
= NULL
;
907 _cleanup_free_ LinkInfo
*links
= NULL
;
908 const char *state
, *word
;
916 pager_open_if_enabled();
918 r
= sd_netlink_open(&rtnl
);
920 return log_error_errno(r
, "Failed to connect to netlink: %m");
922 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
924 return rtnl_log_create_error(r
);
926 r
= sd_netlink_message_request_dump(req
, true);
928 return rtnl_log_create_error(r
);
930 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
932 return log_error_errno(r
, "Failed to enumerate links: %m");
934 c
= decode_and_sort_links(reply
, &links
);
936 return rtnl_log_parse_error(c
);
939 printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
941 for (i
= j
= 0; i
< c
; i
++) {
942 _cleanup_free_
char *chassis
= NULL
, *port
= NULL
, *cap
= NULL
, *lldp
= NULL
;
943 _cleanup_strv_free_
char **l
= NULL
;
945 r
= sd_network_link_get_lldp(links
[i
].ifindex
, &lldp
);
949 l
= strv_split_newlines(lldp
);
954 FOREACH_WORD_QUOTED(word
, ll
, *s
, state
) {
955 _cleanup_free_
char *t
= NULL
, *a
= NULL
, *b
= NULL
;
957 t
= strndup(word
, ll
);
961 r
= split_pair(t
, "=", &a
, &b
);
965 if (streq(a
, "_Chassis")) {
966 r
= free_and_strdup(&chassis
, b
);
970 } else if (streq(a
, "_Port")) {
971 r
= free_and_strdup(&port
, b
);
975 } else if (streq(a
, "_TTL")) {
976 long long unsigned x
= 0;
979 r
= safe_atollu(b
, &x
);
980 if (r
< 0 || (usec_t
) x
!= x
)
981 return log_warning_errno(r
< 0 ? r
: ERANGE
,
982 "Failed to parse TTL \"%s\": %m", b
);
984 time
= now(clock_boottime_or_monotonic());
988 ttl
= (double) (x
- time
) / USEC_PER_SEC
;
990 } else if (streq(a
, "_CAP")) {
991 sscanf(b
, "%x", &capability
);
993 cap
= lldp_system_caps(capability
);
999 printf("%10s %24s %16s %16f %16s\n",
1001 strna(chassis
), strna(port
),
1009 printf("\nCapability Codes:\n"
1010 "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
1011 "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
1012 "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
1014 printf("Total entries displayed: %d\n", j
);
1020 static void help(void) {
1021 printf("%s [OPTIONS...]\n\n"
1022 "Query and control the networking subsystem.\n\n"
1023 " -h --help Show this help\n"
1024 " --version Show package version\n"
1025 " --no-pager Do not pipe output into a pager\n"
1026 " --no-legend Do not show the headers and footers\n"
1027 " -a --all Show status for all links\n\n"
1029 " list List links\n"
1030 " status [LINK...] Show link status\n"
1031 " lldp Show lldp information\n"
1032 , program_invocation_short_name
);
1035 static int parse_argv(int argc
, char *argv
[]) {
1038 ARG_VERSION
= 0x100,
1043 static const struct option options
[] = {
1044 { "help", no_argument
, NULL
, 'h' },
1045 { "version", no_argument
, NULL
, ARG_VERSION
},
1046 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1047 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1048 { "all", no_argument
, NULL
, 'a' },
1057 while ((c
= getopt_long(argc
, argv
, "ha", options
, NULL
)) >= 0) {
1066 puts(PACKAGE_STRING
);
1067 puts(SYSTEMD_FEATURES
);
1071 arg_no_pager
= true;
1086 assert_not_reached("Unhandled option");
1093 static int networkctl_main(int argc
, char *argv
[]) {
1094 const Verb verbs
[] = {
1095 { "list", VERB_ANY
, 1, VERB_DEFAULT
, list_links
},
1096 { "status", 1, VERB_ANY
, 0, link_status
},
1097 { "lldp", VERB_ANY
, 1, VERB_DEFAULT
, link_lldp_status
},
1101 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1104 int main(int argc
, char* argv
[]) {
1107 log_parse_environment();
1110 r
= parse_argv(argc
, argv
);
1114 r
= networkctl_main(argc
, argv
);
1119 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;