[systemd-devel] [PATCH v2] network: Implement fallback DHCPv6 prefix handling for older kernels
Alexander Sverdlin
alexander.sverdlin at gmail.com
Fri Apr 10 14:20:07 PDT 2015
Hello Patrik!
On 10/04/15 13:03, Patrik Flykt wrote:
> 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.
> ---
>
> Hi,
>
> Version 2 attempts to resolve IPv6 address assignment issues at run time,
> first by adding IFA_FLAGS, then without.
>
> Please test with kernels < 3.14 and >= 3.14.
While the patch itself looks good to me, I cannot test it right now, as
I actually never used networkd before.
> src/network/networkd-address.c | 2 +-
> src/network/networkd-dhcp6.c | 66 ++++++++++++++++++++++++++++++++++++++++--
> src/network/networkd-link.c | 1 +
> src/network/networkd-link.h | 1 +
> 4 files changed, 67 insertions(+), 3 deletions(-)
>
> diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
> index 85acc49..df836d3 100644
> --- a/src/network/networkd-address.c
> +++ b/src/network/networkd-address.c
> @@ -215,7 +215,7 @@ int address_update(Address *address, Link *link,
> if (r < 0)
> return log_error_errno(r, "Could not set flags: %m");
>
> - if (address->flags & ~0xff) {
> + if (address->flags & ~0xff && link->rtnl_extended_attrs) {
> r = sd_rtnl_message_append_u32(req, IFA_FLAGS, address->flags);
> if (r < 0)
> return log_error_errno(r, "Could not set extended flags: %m");
> diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
> index e863f4b..5668fdf 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",
> diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
> index 3bd37d8..d00a828 100644
> --- a/src/network/networkd-link.c
> +++ b/src/network/networkd-link.c
> @@ -227,6 +227,7 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
> link->n_ref = 1;
> link->manager = manager;
> link->state = LINK_STATE_PENDING;
> + link->rtnl_extended_attrs = true;
> link->ifindex = ifindex;
> link->ifname = strdup(ifname);
> if (!link->ifname)
> diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
> index 479098c..c3bc1b9 100644
> --- a/src/network/networkd-link.h
> +++ b/src/network/networkd-link.h
> @@ -82,6 +82,7 @@ struct Link {
>
> sd_icmp6_nd *icmp6_router_discovery;
> sd_dhcp6_client *dhcp6_client;
> + bool rtnl_extended_attrs;
>
> sd_lldp *lldp;
> char *lldp_file;
Best regards,
Alexander.
More information about the systemd-devel
mailing list