[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