summaryrefslogtreecommitdiff
path: root/src/network/networkd-dhcp6.c
diff options
context:
space:
mode:
authorPatrik Flykt <patrik.flykt@linux.intel.com>2015-04-10 14:03:18 +0300
committerPatrik Flykt <patrik.flykt@linux.intel.com>2015-05-04 09:42:37 +0300
commitbe3a09b7ffe62b52658e77ae4d6638d1b0dae654 (patch)
treeba98350ead4b1b638cc2dba86640db2ffc7d70da /src/network/networkd-dhcp6.c
parent336b5c615e9c101476784b32df1b86aaeac96431 (diff)
network: Implement fallback DHCPv6 prefix handling for older kernels
When setting IPv6 addresses acquired by DHCPv6, systemd-networkd sets the IFA_F_NOPREFIXROUTE flag in the IFA_FLAGS netlink attribute. As the flag and the attribute are present starting with Linux 3.14, older kernels will need systemd-network to manage prefix route expiry. By default, DHCPv6 addresses are first assigned setting the IFA_F_NOPREFIXROUTE flag in the IFA_FLAGS netlink attribute. Should the address assignment fail, the same assignment is tried without the IFA_FLAGS attribute. Should also the second attempt fail, an error is printed and address assignment ends with failure. As successful use of the IFA_FLAGS netlink attribute is recorded in the Link structure, the DHCPv6 code will know if the kernel or systemd-network fallback code handles expiring prefixes. The prefix expiration and IPv6 address updating fallback code is resurrected from the parts deleted with commit 47d45d3cde45d6545367570264e4e3636bc9e345. This patch can be removed once the minimum kernel requirements are greater than or equal to 3.14.
Diffstat (limited to 'src/network/networkd-dhcp6.c')
-rw-r--r--src/network/networkd-dhcp6.c66
1 files changed, 64 insertions, 2 deletions
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index e863f4b347..5668fdf16c 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -28,6 +28,8 @@
#include "sd-icmp6-nd.h"
#include "sd-dhcp6-client.h"
+static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
+
static int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
Link *link) {
return 0;
@@ -42,6 +44,15 @@ static int dhcp6_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
+ if (link->rtnl_extended_attrs) {
+ log_link_warning(link, "Could not set extended netlink attributes, reverting to fallback mechanism");
+
+ link->rtnl_extended_attrs = false;
+ dhcp6_lease_address_acquired(link->dhcp6_client, link);
+
+ return 1;
+ }
+
log_link_error(link, "Could not set DHCPv6 address: %s",
strerror(-r));
@@ -67,7 +78,7 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
addr->flags = IFA_F_NOPREFIXROUTE;
- addr->prefixlen = 64;
+ addr->prefixlen = prefixlen;
addr->cinfo.ifa_prefered = lifetime_preferred;
addr->cinfo.ifa_valid = lifetime_valid;
@@ -262,6 +273,52 @@ static int dhcp6_configure(Link *link, int event) {
return r;
}
+static int dhcp6_prefix_expired(Link *link) {
+ int r;
+ sd_dhcp6_lease *lease;
+ struct in6_addr *expired_prefix, ip6_addr;
+ uint8_t expired_prefixlen;
+ uint32_t lifetime_preferred, lifetime_valid;
+
+ r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery,
+ &expired_prefix, &expired_prefixlen);
+ if (r < 0)
+ return r;
+
+ r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease);
+ if (r < 0)
+ return r;
+
+ log_link_struct(link, LOG_INFO,
+ "MESSAGE=%-*s: IPv6 prefix "SD_ICMP6_ADDRESS_FORMAT_STR"/%d expired",
+ IFNAMSIZ, link->ifname,
+ SD_ICMP6_ADDRESS_FORMAT_VAL(*expired_prefix),
+ expired_prefixlen, NULL);
+
+ sd_dhcp6_lease_reset_address_iter(lease);
+
+ while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
+ &lifetime_preferred,
+ &lifetime_valid) >= 0) {
+
+ r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen,
+ &ip6_addr);
+ if (r < 0)
+ continue;
+
+ log_link_struct(link, LOG_INFO,
+ "MESSAGE=%-*s: IPv6 prefix length updated "SD_ICMP6_ADDRESS_FORMAT_STR"/%d",
+ IFNAMSIZ, link->ifname,
+ SD_ICMP6_ADDRESS_FORMAT_VAL(ip6_addr), 128,
+ NULL);
+
+ dhcp6_address_update(link, &ip6_addr, 128, lifetime_preferred,
+ lifetime_valid);
+ }
+
+ return 0;
+}
+
static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
Link *link = userdata;
@@ -274,7 +331,6 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
switch(event) {
case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE:
- case ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
return;
case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
@@ -284,6 +340,12 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
break;
+ case ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
+ if (!link->rtnl_extended_attrs)
+ dhcp6_prefix_expired(link);
+
+ break;
+
default:
if (event < 0)
log_link_warning(link, "ICMPv6 error: %s",