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
;
521 if (safe_atoi(name
, &ifindex
) >= 0 && ifindex
> 0)
522 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, ifindex
);
524 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
526 return rtnl_log_create_error(r
);
528 r
= sd_rtnl_message_append_string(req
, IFLA_IFNAME
, name
);
532 return rtnl_log_create_error(r
);
534 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
536 return log_error_errno(r
, "Failed to query link: %m");
538 r
= sd_rtnl_message_link_get_ifindex(reply
, &ifindex
);
540 return rtnl_log_parse_error(r
);
542 r
= sd_rtnl_message_read_string(reply
, IFLA_IFNAME
, &name
);
544 return rtnl_log_parse_error(r
);
546 r
= sd_rtnl_message_link_get_type(reply
, &iftype
);
548 return rtnl_log_parse_error(r
);
550 have_mac
= sd_rtnl_message_read_ether_addr(reply
, IFLA_ADDRESS
, &e
) >= 0;
554 bool all_zeroes
= true;
556 for (p
= (uint8_t*) &e
; p
< (uint8_t*) &e
+ sizeof(e
); p
++)
566 sd_rtnl_message_read_u32(reply
, IFLA_MTU
, &mtu
);
568 sd_network_link_get_operational_state(ifindex
, &operational_state
);
569 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
571 sd_network_link_get_setup_state(ifindex
, &setup_state
);
572 setup_state_to_color(setup_state
, &on_color_setup
, &off_color_setup
);
574 sd_network_link_get_dns(ifindex
, &dns
);
575 sd_network_link_get_ntp(ifindex
, &ntp
);
576 sd_network_link_get_domains(ifindex
, &domains
);
577 r
= sd_network_link_get_wildcard_domain(ifindex
);
581 wildcard
= strdup("*");
585 if (strv_consume(&domains
, wildcard
) < 0)
589 sprintf(devid
, "n%i", ifindex
);
590 d
= udev_device_new_from_device_id(udev
, devid
);
592 link
= udev_device_get_property_value(d
, "ID_NET_LINK_FILE");
593 driver
= udev_device_get_property_value(d
, "ID_NET_DRIVER");
594 path
= udev_device_get_property_value(d
, "ID_PATH");
596 vendor
= udev_device_get_property_value(d
, "ID_VENDOR_FROM_DATABASE");
598 vendor
= udev_device_get_property_value(d
, "ID_VENDOR");
600 model
= udev_device_get_property_value(d
, "ID_MODEL_FROM_DATABASE");
602 model
= udev_device_get_property_value(d
, "ID_MODEL");
605 link_get_type_string(iftype
, d
, &t
);
607 sd_network_link_get_network_file(ifindex
, &network
);
609 printf("%s%s%s %i: %s\n", on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
, ifindex
, name
);
611 printf(" Link File: %s\n"
614 " State: %s%s%s (%s%s%s)\n",
618 on_color_operational
, strna(operational_state
), off_color_operational
,
619 on_color_setup
, strna(setup_state
), off_color_setup
);
622 printf(" Path: %s\n", path
);
624 printf(" Driver: %s\n", driver
);
626 printf(" Vendor: %s\n", vendor
);
628 printf(" Model: %s\n", model
);
631 _cleanup_free_
char *description
= NULL
;
632 char ea
[ETHER_ADDR_TO_STRING_MAX
];
634 ieee_oui(hwdb
, &e
, &description
);
637 printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e
, ea
), description
);
639 printf(" HW Address: %s\n", ether_addr_to_string(&e
, ea
));
643 printf(" MTU: %u\n", mtu
);
645 dump_addresses(rtnl
, " Address: ", ifindex
);
646 dump_gateways(rtnl
, hwdb
, " Gateway: ", ifindex
);
648 if (!strv_isempty(dns
))
649 dump_list(" DNS: ", dns
);
650 if (!strv_isempty(domains
))
651 dump_list(" Domain: ", domains
);
652 if (!strv_isempty(ntp
))
653 dump_list(" NTP: ", ntp
);
658 static int link_status(int argc
, char *argv
[], void *userdata
) {
659 _cleanup_hwdb_unref_ sd_hwdb
*hwdb
= NULL
;
660 _cleanup_udev_unref_
struct udev
*udev
= NULL
;
661 _cleanup_rtnl_unref_ sd_rtnl
*rtnl
= NULL
;
665 r
= sd_rtnl_open(&rtnl
, 0);
667 return log_error_errno(r
, "Failed to connect to netlink: %m");
671 return log_error_errno(errno
, "Failed to connect to udev: %m");
673 r
= sd_hwdb_new(&hwdb
);
675 log_debug_errno(r
, "Failed to open hardware database: %m");
677 if (argc
<= 1 && !arg_all
) {
678 _cleanup_free_
char *operational_state
= NULL
;
679 _cleanup_strv_free_
char **dns
= NULL
, **ntp
= NULL
, **domains
= NULL
;
680 const char *on_color_operational
, *off_color_operational
;
682 sd_network_get_operational_state(&operational_state
);
683 operational_state_to_color(operational_state
, &on_color_operational
, &off_color_operational
);
685 printf("%s%s%s State: %s%s%s\n",
686 on_color_operational
, draw_special_char(DRAW_BLACK_CIRCLE
), off_color_operational
,
687 on_color_operational
, strna(operational_state
), off_color_operational
);
689 dump_addresses(rtnl
, " Address: ", 0);
690 dump_gateways(rtnl
, hwdb
, " Gateway: ", 0);
692 sd_network_get_dns(&dns
);
693 if (!strv_isempty(dns
))
694 dump_list(" DNS: ", dns
);
696 sd_network_get_domains(&domains
);
697 if (!strv_isempty(domains
))
698 dump_list(" Domain: ", domains
);
700 sd_network_get_ntp(&ntp
);
701 if (!strv_isempty(ntp
))
702 dump_list(" NTP: ", ntp
);
707 pager_open_if_enabled();
710 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
711 _cleanup_free_ LinkInfo
*links
= NULL
;
714 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
716 return rtnl_log_create_error(r
);
718 r
= sd_rtnl_message_request_dump(req
, true);
720 return rtnl_log_create_error(r
);
722 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
724 return log_error_errno(r
, "Failed to enumerate links: %m");
726 c
= decode_and_sort_links(reply
, &links
);
728 return rtnl_log_parse_error(c
);
730 for (i
= 0; i
< c
; i
++) {
734 link_status_one(rtnl
, udev
, hwdb
, links
[i
].name
);
737 STRV_FOREACH(name
, argv
+ 1) {
738 if (name
!= argv
+ 1)
741 link_status_one(rtnl
, udev
, hwdb
, *name
);
748 const char *lldp_system_capability_to_string(LLDPSystemCapabilities d
) _const_
;
749 LLDPSystemCapabilities
lldp_system_capability_from_string(const char *d
) _pure_
;
751 static const char* const lldp_system_capability_table
[_LLDP_SYSTEM_CAPABILITIES_MAX
+ 1] = {
752 [LLDP_SYSTEM_CAPABILITIES_OTHER
] = "O",
753 [LLDP_SYSTEM_CAPABILITIES_REPEATER
] = "P",
754 [LLDP_SYSTEM_CAPABILITIES_BRIDGE
] = "B",
755 [LLDP_SYSTEM_CAPABILITIES_WLAN_AP
] = "W",
756 [LLDP_SYSTEM_CAPABILITIES_ROUTER
] = "R",
757 [LLDP_SYSTEM_CAPABILITIES_PHONE
] = "T",
758 [LLDP_SYSTEM_CAPABILITIES_DOCSIS
] = "D",
759 [LLDP_SYSTEM_CAPABILITIES_STATION
] = "A",
760 [LLDP_SYSTEM_CAPABILITIES_CVLAN
] = "C",
761 [LLDP_SYSTEM_CAPABILITIES_SVLAN
] = "S",
762 [LLDP_SYSTEM_CAPABILITIES_TPMR
] = "M",
763 [_LLDP_SYSTEM_CAPABILITIES_MAX
] = "N/A",
766 DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability
, LLDPSystemCapabilities
);
768 static char *lldp_system_caps(uint16_t cap
) {
769 _cleanup_free_
char *s
= NULL
, *t
= NULL
;
776 if (cap
& LLDP_SYSTEM_CAPABILITIES_OTHER
) {
777 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER
), " ", NULL
);
785 if (cap
& LLDP_SYSTEM_CAPABILITIES_REPEATER
) {
786 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER
), " ", NULL
);
794 if (cap
& LLDP_SYSTEM_CAPABILITIES_BRIDGE
) {
795 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE
), " ", NULL
);
803 if (cap
& LLDP_SYSTEM_CAPABILITIES_WLAN_AP
) {
804 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP
), " ", NULL
);
812 if (cap
& LLDP_SYSTEM_CAPABILITIES_ROUTER
) {
813 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER
), " ", NULL
);
821 if (cap
& LLDP_SYSTEM_CAPABILITIES_PHONE
) {
822 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE
), " ", NULL
);
830 if (cap
& LLDP_SYSTEM_CAPABILITIES_DOCSIS
) {
831 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS
), " ", NULL
);
839 if (cap
& LLDP_SYSTEM_CAPABILITIES_STATION
) {
840 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION
), " ", NULL
);
848 if (cap
& LLDP_SYSTEM_CAPABILITIES_CVLAN
) {
849 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN
), " ", NULL
);
857 if (cap
& LLDP_SYSTEM_CAPABILITIES_SVLAN
) {
858 s
= strjoin(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN
), " ", NULL
);
866 if (cap
& LLDP_SYSTEM_CAPABILITIES_TPMR
) {
867 s
= strappend(t
, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR
));
875 s
= strappend(t
, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX
));
882 t
= strappend(s
, "]");
895 static int link_lldp_status(int argc
, char *argv
[], void *userdata
) {
896 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
, *reply
= NULL
;
897 _cleanup_rtnl_unref_ sd_rtnl
*rtnl
= NULL
;
898 _cleanup_free_ LinkInfo
*links
= NULL
;
899 const char *state
, *word
;
907 pager_open_if_enabled();
909 r
= sd_rtnl_open(&rtnl
, 0);
911 return log_error_errno(r
, "Failed to connect to netlink: %m");
913 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
915 return rtnl_log_create_error(r
);
917 r
= sd_rtnl_message_request_dump(req
, true);
919 return rtnl_log_create_error(r
);
921 r
= sd_rtnl_call(rtnl
, req
, 0, &reply
);
923 return log_error_errno(r
, "Failed to enumerate links: %m");
925 c
= decode_and_sort_links(reply
, &links
);
927 return rtnl_log_parse_error(c
);
930 printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
932 for (i
= j
= 0; i
< c
; i
++) {
933 _cleanup_free_
char *chassis
= NULL
, *port
= NULL
, *cap
= NULL
, *lldp
= NULL
;
934 _cleanup_strv_free_
char **l
= NULL
;
936 r
= sd_network_link_get_lldp(links
[i
].ifindex
, &lldp
);
940 l
= strv_split_newlines(lldp
);
945 FOREACH_WORD_QUOTED(word
, ll
, *s
, state
) {
946 _cleanup_free_
char *t
= NULL
, *a
= NULL
, *b
= NULL
;
948 t
= strndup(word
, ll
);
952 r
= split_pair(t
, "=", &a
, &b
);
956 if (streq(a
, "_Chassis")) {
961 } else if (streq(a
, "_Port")) {
966 } else if (streq(a
, "_TTL")) {
967 long long unsigned x
;
970 r
= safe_atollu(b
, &x
);
971 if (r
< 0 || (usec_t
) x
!= x
)
972 return log_warning_errno(r
< 0 ? r
: ERANGE
,
973 "Failed to parse TTL \"%s\": %m", b
);
975 time
= now(CLOCK_BOOTTIME
);
979 ttl
= (double) (x
- time
) / USEC_PER_SEC
;
981 } else if (streq(a
, "_CAP")) {
982 sscanf(b
, "%x", &capability
);
984 cap
= lldp_system_caps(capability
);
990 printf("%10s %24s %16s %16f %16s\n",
992 strna(chassis
), strna(port
),
1000 printf("\nCapability Codes:\n"
1001 "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
1002 "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
1003 "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
1005 printf("Total entries displayed: %d\n", j
);
1011 static void help(void) {
1012 printf("%s [OPTIONS...]\n\n"
1013 "Query and control the networking subsystem.\n\n"
1014 " -h --help Show this help\n"
1015 " --version Show package version\n"
1016 " --no-pager Do not pipe output into a pager\n"
1017 " --no-legend Do not show the headers and footers\n"
1018 " -a --all Show status for all links\n\n"
1020 " list List links\n"
1021 " status [LINK...] Show link status\n"
1022 " lldp Show lldp information\n"
1023 , program_invocation_short_name
);
1026 static int parse_argv(int argc
, char *argv
[]) {
1029 ARG_VERSION
= 0x100,
1034 static const struct option options
[] = {
1035 { "help", no_argument
, NULL
, 'h' },
1036 { "version", no_argument
, NULL
, ARG_VERSION
},
1037 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
1038 { "no-legend", no_argument
, NULL
, ARG_NO_LEGEND
},
1039 { "all", no_argument
, NULL
, 'a' },
1048 while ((c
= getopt_long(argc
, argv
, "ha", options
, NULL
)) >= 0) {
1057 puts(PACKAGE_STRING
);
1058 puts(SYSTEMD_FEATURES
);
1062 arg_no_pager
= true;
1077 assert_not_reached("Unhandled option");
1084 static int networkctl_main(int argc
, char *argv
[]) {
1085 const Verb verbs
[] = {
1086 { "list", VERB_ANY
, 1, VERB_DEFAULT
, list_links
},
1087 { "status", 1, VERB_ANY
, 0, link_status
},
1088 { "lldp", VERB_ANY
, 1, VERB_DEFAULT
, link_lldp_status
},
1092 return dispatch_verb(argc
, argv
, verbs
, NULL
);
1095 int main(int argc
, char* argv
[]) {
1098 log_parse_environment();
1101 r
= parse_argv(argc
, argv
);
1105 r
= networkctl_main(argc
, argv
);
1110 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;