diff --git a/man/networkctl.xml b/man/networkctl.xml
index 809eb7ec6a..d4fa5e9029 100644
--- a/man/networkctl.xml
+++ b/man/networkctl.xml
@@ -172,14 +172,40 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
1 neighbors listed.
+
+
+
+ label
+
+
+ Show numerical address labels that can be used for address selection.
+ This is the same information that
+ ip-addrlabel8
+ shows. See RFC 3484
+ for a discussion of address labels.
+
+ Produces output similar to:
+ Prefix/Prefixlen Label
+ ::/0 1
+ fc00::/7 5
+ fec0::/10 11
+ 2002::/16 2
+ 3ffe::/16 12
+ 2001:10::/28 7
+ 2001::/32 6
+::ffff:0.0.0.0/96 4
+ ::/96 3
+ ::1/128 0
+
+
+
Exit status
- On success, 0 is returned, a non-zero failure
- code otherwise.
+ On success, 0 is returned, a non-zero failure code otherwise.
@@ -187,7 +213,8 @@ s - Service VLAN, m - Two-port MAC Relay (TPMR)
systemd-networkd.service8,
systemd.network5,
- systemd.netdev5
+ systemd.netdev5,
+ ip8
diff --git a/shell-completion/bash/networkctl b/shell-completion/bash/networkctl
index 942c7e1c00..68e3338471 100644
--- a/shell-completion/bash/networkctl
+++ b/shell-completion/bash/networkctl
@@ -36,7 +36,7 @@ _networkctl() {
)
local -A VERBS=(
- [STANDALONE]='list lldp'
+ [STANDALONE]='list lldp label'
[LINKS]='status'
)
diff --git a/shell-completion/zsh/_networkctl b/shell-completion/zsh/_networkctl
index 61f173b78e..acf7463edb 100644
--- a/shell-completion/zsh/_networkctl
+++ b/shell-completion/zsh/_networkctl
@@ -6,6 +6,7 @@ _networkctl_command(){
'list:List existing links'
'status:Show information about the specified links'
'lldp:Show Link Layer Discovery Protocol status'
+ 'label:Show address labels'
)
if (( CURRENT == 1 )); then
_describe -t commands 'networkctl command' _networkctl_cmds
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 654a22fe3b..e8c8abac2a 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -104,7 +104,8 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
m->hdr->nlmsg_type == RTM_GETADDR ||
m->hdr->nlmsg_type == RTM_GETROUTE ||
- m->hdr->nlmsg_type == RTM_GETNEIGH,
+ m->hdr->nlmsg_type == RTM_GETNEIGH ||
+ m->hdr->nlmsg_type == RTM_GETADDRLABEL ,
-EINVAL);
SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c
index d5f8b7d15e..12c51ffe2e 100644
--- a/src/libsystemd/sd-netlink/rtnl-message.c
+++ b/src/libsystemd/sd-netlink/rtnl-message.c
@@ -740,3 +740,17 @@ int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char
return 0;
}
+
+int sd_rtnl_message_addrlabel_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen) {
+ struct ifaddrlblmsg *addrlabel;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_addrlabel(m->hdr->nlmsg_type), -EINVAL);
+
+ addrlabel = NLMSG_DATA(m->hdr);
+
+ *prefixlen = addrlabel->ifal_prefixlen;
+
+ return 0;
+}
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 6f7f41bf7d..54d54c8fd5 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -18,6 +18,7 @@
***/
#include
+#include
#include
#include
@@ -35,6 +36,7 @@
#include "hwdb-util.h"
#include "local-addresses.h"
#include "locale-util.h"
+#include "macro.h"
#include "netlink-util.h"
#include "pager.h"
#include "parse-util.h"
@@ -569,6 +571,76 @@ static int dump_addresses(
return 0;
}
+static int dump_address_labels(sd_netlink *rtnl) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+ sd_netlink_message *m;
+ int r;
+
+ assert(rtnl);
+
+ r = sd_rtnl_message_new_addrlabel(rtnl, &req, RTM_GETADDRLABEL, 0, AF_INET6);
+ if (r < 0)
+ return log_error_errno(r, "Could not allocate RTM_GETADDRLABEL message: %m");
+
+ r = sd_netlink_message_request_dump(req, true);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(rtnl, req, 0, &reply);
+ if (r < 0)
+ return r;
+
+ printf("%10s/%s %30s\n", "Prefix", "Prefixlen", "Label");
+
+ for (m = reply; m; m = sd_netlink_message_next(m)) {
+ _cleanup_free_ char *pretty = NULL;
+ union in_addr_union prefix = {};
+ uint8_t prefixlen;
+ uint32_t label;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0) {
+ log_error_errno(r, "got error: %m");
+ continue;
+ }
+
+ r = sd_netlink_message_read_u32(m, IFAL_LABEL, &label);
+ if (r < 0 && r != -ENODATA) {
+ log_error_errno(r, "Could not read IFAL_LABEL, ignoring: %m");
+ continue;
+ }
+
+ r = sd_netlink_message_read_in6_addr(m, IFAL_ADDRESS, &prefix.in6);
+ if (r < 0)
+ continue;
+
+ r = in_addr_to_string(AF_INET6, &prefix, &pretty);
+ if (r < 0)
+ continue;
+
+ r = sd_rtnl_message_addrlabel_get_prefixlen(m, &prefixlen);
+ if (r < 0)
+ continue;
+
+ printf("%10s/%-5u %30u\n", pretty, prefixlen, label);
+ }
+
+ return 0;
+}
+
+static int list_address_labels(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ int r;
+
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
+
+ dump_address_labels(rtnl);
+
+ return 0;
+}
+
static int open_lldp_neighbors(int ifindex, FILE **ret) {
_cleanup_free_ char *p = NULL;
FILE *f;
@@ -1043,6 +1115,7 @@ static void help(void) {
" list [LINK...] List links\n"
" status [LINK...] Show link status\n"
" lldp [LINK...] Show LLDP neighbors\n"
+ " label Show current address label entries in the kernel\n"
, program_invocation_short_name);
}
@@ -1107,6 +1180,7 @@ static int networkctl_main(int argc, char *argv[]) {
{ "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links },
{ "status", VERB_ANY, VERB_ANY, 0, link_status },
{ "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status },
+ { "label", VERB_ANY, VERB_ANY, 0, list_address_labels},
{}
};
diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h
index aa39e0a0db..3f5a6673cf 100644
--- a/src/systemd/sd-netlink.h
+++ b/src/systemd/sd-netlink.h
@@ -157,6 +157,7 @@ int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags);
int sd_rtnl_message_new_addrlabel(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifindex, int ifal_family);
int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
+int sd_rtnl_message_addrlabel_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_message, sd_netlink_message_unref);