diff options
author | Lennart Poettering <lennart@poettering.net> | 2016-02-19 18:57:11 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2016-02-21 20:40:57 +0100 |
commit | e997c4b09d519ec2dcc58a7bb34166eacca8e599 (patch) | |
tree | e3ce02c5d32fe4ac50a056fed8fe9b7b3de706cd | |
parent | 7d367b45f6f7151f092e982a4d0685231d31b824 (diff) |
networkctl: extend "networkctl list" and "networctl lldp" to optionally take interface names
This way, the output may be reduced to only show data about the specified
interfaces.
-rw-r--r-- | man/networkctl.xml | 33 | ||||
-rw-r--r-- | src/network/networkctl.c | 151 |
2 files changed, 135 insertions, 49 deletions
diff --git a/man/networkctl.xml b/man/networkctl.xml index c688714b30..24e1de6986 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -102,12 +102,14 @@ <varlistentry> <term> <command>list</command> + <optional><replaceable>LINK...</replaceable></optional> </term> <listitem> - <para>Show a list of existing links and their - status. Produces output similar to <programlisting> -IDX LINK TYPE OPERATIONAL SETUP + <para>Show a list of existing links and their status. If no further arguments are specified shows all links, + otherwise just the specified links. Produces output similar to: + + <programlisting>IDX LINK TYPE OPERATIONAL SETUP 1 lo loopback carrier unmanaged 2 eth0 ether routable configured 3 virbr0 ether no-carrier unmanaged @@ -128,10 +130,10 @@ IDX LINK TYPE OPERATIONAL SETUP state, kernel module driver, hardware and IP address, configured DNS servers, etc.</para> - <para>When no links are specified, routable links are - shown. Also see the option <option>--all</option>.</para> + <para>When no links are specified, an overall network status is shown. Also see the option + <option>--all</option>.</para> - <para>Produces output similar to + <para>Produces output similar to: <programlisting> ● State: routable Address: 10.193.76.5 on eth0 @@ -148,11 +150,26 @@ IDX LINK TYPE OPERATIONAL SETUP <varlistentry> <term> <command>lldp</command> + <optional><replaceable>LINK...</replaceable></optional> </term> <listitem> - <para>Show LLDP (Link Layer Discovery Protocol) - status.</para> + <para>Show discovered LLDP (Link Layer Discovery Protocol) neighbors. If one or more link names are specified + only neighbors on those interfaces are shown. Otherwise shows discovered neighbors on all interfaces. Note + that for this feature to work, <varname>LLDP=</varname> must be turned on on the specific interface, see + <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> for + details.</para> + + <para>Produces output similar to: + <programlisting>LINK CHASSIS ID SYSTEM NAME CAPS PORT ID PORT DESCRIPTION +enp0s25 00:e0:4c:00:00:00 GS1900 ..b........ 2 Port #2 + +Capability Flags: +o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router; +t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN; +s - Service VLAN, m - Two-port MAC Relay (TPMR) + +1 neighbors listed.</programlisting></para> </listitem> </varlistentry> </variablelist> diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 9838e7a5a6..d19bf131cd 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -73,7 +73,7 @@ static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) * to show a more useful type string for * them */ - (void)sd_device_get_devtype(d, &devtype); + (void) sd_device_get_devtype(d, &devtype); if (streq_ptr(devtype, "wlan")) id = "wlan"; @@ -107,7 +107,7 @@ static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) } typedef struct LinkInfo { - const char *name; + char name[IFNAMSIZ+1]; int ifindex; unsigned short iftype; } LinkInfo; @@ -118,44 +118,56 @@ static int link_info_compare(const void *a, const void *b) { return x->ifindex - y->ifindex; } -static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { - _cleanup_free_ LinkInfo *links = NULL; - size_t size = 0, c = 0; - sd_netlink_message *i; - int r; +static int decode_link_one(sd_netlink_message *m, LinkInfo *info) { + const char *name; + unsigned short iftype; + uint16_t type; + int ifindex, r; - for (i = m; i; i = sd_netlink_message_next(i)) { - const char *name; - unsigned short iftype; - uint16_t type; - int ifindex; + assert(m); + assert(info); - r = sd_netlink_message_get_type(i, &type); - if (r < 0) - return r; + r = sd_netlink_message_get_type(m, &type); + if (r < 0) + return r; - if (type != RTM_NEWLINK) - continue; + if (type != RTM_NEWLINK) + return 0; - r = sd_rtnl_message_link_get_ifindex(i, &ifindex); - if (r < 0) - return r; + r = sd_rtnl_message_link_get_ifindex(m, &ifindex); + if (r < 0) + return r; - r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name); - if (r < 0) - return r; + r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name); + if (r < 0) + return r; - r = sd_rtnl_message_link_get_type(i, &iftype); - if (r < 0) - return r; + r = sd_rtnl_message_link_get_type(m, &iftype); + if (r < 0) + return r; - if (!GREEDY_REALLOC(links, size, c+1)) + strncpy(info->name, name, sizeof(info->name)); + info->ifindex = ifindex; + info->iftype = iftype; + + return 1; +} + +static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { + _cleanup_free_ LinkInfo *links = NULL; + size_t allocated = 0, c = 0; + sd_netlink_message *i; + int r; + + for (i = m; i; i = sd_netlink_message_next(i)) { + if (!GREEDY_REALLOC(links, allocated, c+1)) return -ENOMEM; - links[c].name = name; - links[c].ifindex = ifindex; - links[c].iftype = iftype; - c++; + r = decode_link_one(i, links + c); + if (r < 0) + return r; + if (r > 0) + c++; } qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); @@ -197,7 +209,59 @@ static void setup_state_to_color(const char *state, const char **on, const char *on = *off = ""; } -static int acquire_link_info(LinkInfo **ret) { +static int acquire_link_info_strv(char **l, LinkInfo **ret) { + _cleanup_free_ LinkInfo *links = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + char **i; + size_t c = 0; + int r; + + assert(ret); + + links = new(LinkInfo, strv_length(l)); + if (!links) + return log_oom(); + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + STRV_FOREACH(i, l) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + int ifindex; + + if (parse_ifindex(*i, &ifindex) >= 0) + r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex); + else { + r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); + if (r < 0) + return rtnl_log_create_error(r); + + r = sd_netlink_message_append_string(req, IFLA_IFNAME, *i); + } + if (r < 0) + return rtnl_log_create_error(r); + + r = sd_netlink_call(rtnl, req, 0, &reply); + if (r < 0) + return log_error_errno(r, "Failed to request link: %m"); + + r = decode_link_one(reply, links + c); + if (r < 0) + return r; + if (r > 0) + c++; + } + + qsort_safe(links, c, sizeof(LinkInfo), link_info_compare); + + *ret = links; + links = NULL; + + return (int) c; +} + +static int acquire_link_info_all(LinkInfo **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; @@ -232,7 +296,10 @@ static int list_links(int argc, char *argv[], void *userdata) { _cleanup_free_ LinkInfo *links = NULL; int c, i; - c = acquire_link_info(&links); + if (argc > 1) + c = acquire_link_info_strv(argv + 1, &links); + else + c = acquire_link_info_all(&links); if (c < 0) return c; @@ -553,7 +620,6 @@ static int link_status_one( r = sd_netlink_message_append_string(req, IFLA_IFNAME, name); } - if (r < 0) return rtnl_log_create_error(r); @@ -793,7 +859,10 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { _cleanup_free_ LinkInfo *links = NULL; int i, r, c, j; - c = acquire_link_info(&links); + if (argc > 1) + c = acquire_link_info_strv(argv + 1, &links); + else + c = acquire_link_info_all(&links); if (c < 0) return c; @@ -874,11 +943,11 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { } if (arg_legend) - printf("\nCapabilities:\n" + printf("\nCapability Flags:\n" "o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router;\n" "t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN;\n" "s - Service VLAN, m - Two-port MAC Relay (TPMR)\n\n" - "Total entries displayed: %i\n", j); + "%i neighbors listed.\n", j); return 0; } @@ -892,9 +961,9 @@ static void help(void) { " --no-legend Do not show the headers and footers\n" " -a --all Show status for all links\n\n" "Commands:\n" - " list List links\n" + " list [LINK...] List links\n" " status [LINK...] Show link status\n" - " lldp Show lldp neighbors\n" + " lldp [LINK...] Show lldp neighbors\n" , program_invocation_short_name); } @@ -956,9 +1025,9 @@ static int parse_argv(int argc, char *argv[]) { static int networkctl_main(int argc, char *argv[]) { const Verb verbs[] = { - { "list", VERB_ANY, 1, VERB_DEFAULT, list_links }, + { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links }, { "status", VERB_ANY, VERB_ANY, 0, link_status }, - { "lldp", VERB_ANY, 1, 0, link_lldp_status }, + { "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status }, {} }; |