summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/networkctl.xml33
-rw-r--r--src/network/networkctl.c151
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 },
{}
};