summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Down <chris@chrisdown.name>2020-03-06 17:13:13 +0100
committerGitHub <noreply@github.com>2020-03-06 17:13:13 +0100
commit5bb67b107f1d618453308c05958d6e987f995ee9 (patch)
treecff35695a46af837bb1e16551f398c59303eb6e3
parentMerge pull request #15010 from cgzones/selinux_reload_cache_enforce (diff)
parenttest-network: add a test case for [IPv6Prefix] Assign=yes (diff)
downloadsystemd-5bb67b107f1d618453308c05958d6e987f995ee9.tar.xz
systemd-5bb67b107f1d618453308c05958d6e987f995ee9.zip
Merge pull request #14956 from ssahani/delegated-prefix-14474
nettwork: introduce delegated prefix assign
-rw-r--r--man/systemd.network.xml5
-rw-r--r--src/libsystemd-network/sd-radv.c12
-rw-r--r--src/network/networkd-address.c18
-rw-r--r--src/network/networkd-address.h2
-rw-r--r--src/network/networkd-link.c30
-rw-r--r--src/network/networkd-ndisc.c14
-rw-r--r--src/network/networkd-network-gperf.gperf1
-rw-r--r--src/network/networkd-radv.c40
-rw-r--r--src/network/networkd-radv.h3
-rw-r--r--src/systemd/sd-radv.h2
-rw-r--r--test/fuzz/fuzz-network-parser/directives.network1
-rw-r--r--test/test-network/conf/ipv6ra-prefix.network7
-rwxr-xr-xtest/test-network/systemd-networkd-tests.py7
13 files changed, 129 insertions, 13 deletions
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index bd19b766c3..b73cff8ffe 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -2038,6 +2038,11 @@
to 2592000 seconds (30 days).</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>Assign=</varname></term>
+ <listitem><para>Takes a boolean. When true, adds an address from the prefix. Default to false.
+ </para></listitem>
+ </varlistentry>
</variablelist>
</refsect1>
diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c
index 873a2f40f8..e7ffe879a8 100644
--- a/src/libsystemd-network/sd-radv.c
+++ b/src/libsystemd-network/sd-radv.c
@@ -829,6 +829,18 @@ _public_ int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr
return 0;
}
+_public_ int sd_radv_prefix_get_prefix(sd_radv_prefix *p, struct in6_addr *ret_in6_addr,
+ unsigned char *ret_prefixlen) {
+ assert_return(p, -EINVAL);
+ assert_return(ret_in6_addr, -EINVAL);
+ assert_return(ret_prefixlen, -EINVAL);
+
+ *ret_in6_addr = p->opt.in6_addr;
+ *ret_prefixlen = p->opt.prefixlen;
+
+ return 0;
+}
+
_public_ int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink) {
assert_return(p, -EINVAL);
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 6244f75201..1567bd7ee9 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -20,6 +20,24 @@
#define ADDRESSES_PER_LINK_MAX 2048U
#define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
+int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret) {
+ assert(link);
+ assert(ret);
+
+ /* see RFC4291 section 2.5.1 */
+ ret->s6_addr[8] = link->mac.ether_addr_octet[0];
+ ret->s6_addr[8] ^= 1 << 1;
+ ret->s6_addr[9] = link->mac.ether_addr_octet[1];
+ ret->s6_addr[10] = link->mac.ether_addr_octet[2];
+ ret->s6_addr[11] = 0xff;
+ ret->s6_addr[12] = 0xfe;
+ ret->s6_addr[13] = link->mac.ether_addr_octet[3];
+ ret->s6_addr[14] = link->mac.ether_addr_octet[4];
+ ret->s6_addr[15] = link->mac.ether_addr_octet[5];
+
+ return 0;
+}
+
int address_new(Address **ret) {
_cleanup_(address_freep) Address *address = NULL;
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index ad2412c75a..bd0485e0ab 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -66,6 +66,8 @@ bool address_is_ready(const Address *a);
int address_section_verify(Address *a);
int configure_ipv4_duplicate_address_detection(Link *link, Address *address);
+int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
+
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
extern const struct hash_ops address_hash_ops;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 99d4b29c31..b46c875548 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -1222,6 +1222,7 @@ static int link_set_bridge_fdb(Link *link) {
static int link_request_set_addresses(Link *link) {
AddressLabel *label;
Address *ad;
+ Prefix *p;
int r;
assert(link);
@@ -1257,6 +1258,35 @@ static int link_request_set_addresses(Link *link) {
link->address_messages++;
}
+ if (IN_SET(link->network->router_prefix_delegation,
+ RADV_PREFIX_DELEGATION_STATIC,
+ RADV_PREFIX_DELEGATION_BOTH))
+ LIST_FOREACH(prefixes, p, link->network->static_prefixes) {
+ _cleanup_(address_freep) Address *address = NULL;
+
+ if (!p->assign)
+ continue;
+
+ r = address_new(&address);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Could not allocate address: %m");
+
+ r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
+ if (r < 0)
+ return r;
+
+ r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
+ if (r < 0)
+ return r;
+
+ address->family = AF_INET6;
+ r = address_configure(address, link, address_handler, true);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not set addresses: %m");
+ if (r > 0)
+ link->address_messages++;
+ }
+
LIST_FOREACH(labels, label, link->network->address_labels) {
r = address_label_configure(label, link, NULL, false);
if (r < 0)
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index c45fec5430..90cd0c81ab 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -324,16 +324,10 @@ static int ndisc_router_generate_addresses(Link *link, unsigned prefixlen, uint3
*new_address = *address;
- /* see RFC4291 section 2.5.1 */
- new_address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0];
- new_address->in_addr.in6.s6_addr[8] ^= 1 << 1;
- new_address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1];
- new_address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
- new_address->in_addr.in6.s6_addr[11] = 0xff;
- new_address->in_addr.in6.s6_addr[12] = 0xfe;
- new_address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
- new_address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
- new_address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
+ r = generate_ipv6_eui_64_address(link, &new_address->in_addr.in6);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to generate EUI64 address: %m");
+
new_address->prefixlen = prefixlen;
new_address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
new_address->cinfo.ifa_prefered = lifetime_preferred;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index fb726c8634..8d7c657a1a 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -245,6 +245,7 @@ IPv6Prefix.OnLink, config_parse_prefix_flags,
IPv6Prefix.AddressAutoconfiguration, config_parse_prefix_flags, 0, 0
IPv6Prefix.ValidLifetimeSec, config_parse_prefix_lifetime, 0, 0
IPv6Prefix.PreferredLifetimeSec, config_parse_prefix_lifetime, 0, 0
+IPv6Prefix.Assign, config_parse_prefix_assign, 0, 0
IPv6RoutePrefix.Route, config_parse_route_prefix, 0, 0
IPv6RoutePrefix.LifetimeSec, config_parse_route_prefix_lifetime, 0, 0
CAN.BitRate, config_parse_si_uint64, 0, offsetof(Network, can_bitrate)
diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c
index 620939e251..d9267dd805 100644
--- a/src/network/networkd-radv.c
+++ b/src/network/networkd-radv.c
@@ -319,6 +319,46 @@ int config_parse_prefix_lifetime(const char *unit,
return 0;
}
+int config_parse_prefix_assign(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Network *network = userdata;
+ _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = prefix_new_static(network, filename, section_line, &p);
+ if (r < 0)
+ return r;
+
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse %s=, ignoring assignment: %s",
+ lvalue, rvalue);
+ return 0;
+ }
+
+ p->assign = r;
+ p = NULL;
+
+ return 0;
+}
+
int config_parse_route_prefix(const char *unit,
const char *filename,
unsigned line,
diff --git a/src/network/networkd-radv.h b/src/network/networkd-radv.h
index 21b323e83e..8bf697aff0 100644
--- a/src/network/networkd-radv.h
+++ b/src/network/networkd-radv.h
@@ -28,6 +28,8 @@ struct Prefix {
sd_radv_prefix *radv_prefix;
+ bool assign;
+
LIST_FIELDS(Prefix, prefixes);
};
@@ -59,6 +61,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_router_preference);
CONFIG_PARSER_PROTOTYPE(config_parse_prefix);
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_flags);
CONFIG_PARSER_PROTOTYPE(config_parse_prefix_lifetime);
+CONFIG_PARSER_PROTOTYPE(config_parse_prefix_assign);
CONFIG_PARSER_PROTOTYPE(config_parse_radv_dns);
CONFIG_PARSER_PROTOTYPE(config_parse_radv_search_domains);
CONFIG_PARSER_PROTOTYPE(config_parse_route_prefix);
diff --git a/src/systemd/sd-radv.h b/src/systemd/sd-radv.h
index f085231934..011e40d8a5 100644
--- a/src/systemd/sd-radv.h
+++ b/src/systemd/sd-radv.h
@@ -74,6 +74,8 @@ sd_radv_prefix *sd_radv_prefix_unref(sd_radv_prefix *ra);
int sd_radv_prefix_set_prefix(sd_radv_prefix *p, const struct in6_addr *in6_addr,
unsigned char prefixlen);
+int sd_radv_prefix_get_prefix(sd_radv_prefix *p, struct in6_addr *ret_in6_addr,
+ unsigned char *ret_prefixlen);
int sd_radv_prefix_set_onlink(sd_radv_prefix *p, int onlink);
int sd_radv_prefix_set_address_autoconfiguration(sd_radv_prefix *p,
int address_autoconfiguration);
diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network
index 2b41239b74..ea872cd7e2 100644
--- a/test/fuzz/fuzz-network-parser/directives.network
+++ b/test/fuzz/fuzz-network-parser/directives.network
@@ -186,6 +186,7 @@ OnLink=
PreferredLifetimeSec=
AddressAutoconfiguration=
ValidLifetimeSec=
+Assign=
[IPv6RoutePrefix]
Route=
LifetimeSec=
diff --git a/test/test-network/conf/ipv6ra-prefix.network b/test/test-network/conf/ipv6ra-prefix.network
index 7bb6661362..9dc32cb4da 100644
--- a/test/test-network/conf/ipv6ra-prefix.network
+++ b/test/test-network/conf/ipv6ra-prefix.network
@@ -4,10 +4,13 @@ Name=veth99
[Network]
DHCP=no
IPv6PrefixDelegation=yes
-Address=2001:db8:0:1::1/64
[IPv6Prefix]
-Prefix=2001:db8:0:1::4/64
+Prefix=2001:db8:0:1::/64
+
+[IPv6Prefix]
+Prefix=2001:db8:0:2::/64
+Assign=yes
[IPv6RoutePrefix]
Route=2001:db0:fff::/64
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index 97488243ff..0824108e7e 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -3591,10 +3591,15 @@ class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities):
start_networkd()
self.wait_online(['veth99:routable', 'veth-peer:routable'])
- output = check_output('ip', '-6', 'route', 'show', 'dev', 'veth-peer')
+ output = check_output('ip -6 route show dev veth-peer')
print(output)
self.assertRegex(output, '2001:db8:0:1::/64 proto ra')
+ output = check_output('ip addr show dev veth99')
+ print(output)
+ self.assertNotRegex(output, '2001:db8:0:1')
+ self.assertRegex(output, '2001:db8:0:2')
+
class NetworkdMTUTests(unittest.TestCase, Utilities):
links = ['dummy98']