[systemd-devel] [PATCH 10/11] networkd-dhcp6: Assign DHCPv6 addresses and prefix lengths

Zbigniew Jędrzejewski-Szmek zbyszek at in.waw.pl
Tue Jan 13 16:41:10 PST 2015


On Tue, Jan 13, 2015 at 02:02:20PM +0200, Patrik Flykt wrote:
> Once IPv6 addresses have been acquired, assign these to the interface
> with the prefix lengths taken from the ICMPv6 Router Advertisement
> handling code. The preferred and valid IPv6 address lifetimes are
> handed to the kernel which will clean up them if not renewed in time.
> 
> When a prefix announced via Router Advertisements expires, find all
> addresses that match that prefix and update the address to have a
> prefix lenght of 128 causing the prefix to be off-link.
> ---
>  src/network/networkd-dhcp6.c | 179 +++++++++++++++++++++++++++++++++++++++++--
>  src/network/networkd-link.h  |  10 +++
>  src/network/networkd.c       |   1 +
>  3 files changed, 184 insertions(+), 6 deletions(-)
> 
> diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
> index c31bd4e..5f78f93 100644
> --- a/src/network/networkd-dhcp6.c
> +++ b/src/network/networkd-dhcp6.c
> @@ -28,7 +28,151 @@
>  #include "sd-icmp6-nd.h"
>  #include "sd-dhcp6-client.h"
>  
> +static int dhcp6_lease_information_acquired(sd_dhcp6_client *client,
> +                                        Link *link) {
> +        int r;
> +        uint32_t mtu;
> +
> +        r = sd_icmp6_ra_get_mtu(link->icmp6_router_discovery, &mtu);
> +        if (r >= 0) {
> +                r = link_set_mtu(link, mtu);
> +                if (r < 0)
> +                        log_link_error(link, "Failed to set IPv6 MTU to %" PRIu16, mtu);
> +        }
> +
> +        return 0;
> +}
> +
> +static int dhcp6_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
> +                                 void *userdata) {
> +        _cleanup_link_unref_ Link *link = userdata;
> +        int r;
> +
> +        assert(link);
> +
> +        r = sd_rtnl_message_get_errno(m);
> +        if (r < 0 && r != -EEXIST) {
> +                log_link_error(link, "Could not set DHCPv6 address: %s",
> +                               strerror(-r));
> +
> +                link_enter_failed(link);
> +
> +        } else if (r >= 0)
> +                link_rtnl_process_address(rtnl, m, link->manager);
> +
> +        return 1;
> +}
> +
> +static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
> +                                uint8_t prefixlen, uint32_t lifetime_preferred,
> +                                uint32_t lifetime_valid) {
> +        int r;
> +        _cleanup_address_free_ Address *addr = NULL;
> +
> +        r = address_new_dynamic(&addr);
> +        if (r < 0)
> +                return r;
> +
> +        addr->family = AF_INET6;
> +        memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
> +        addr->prefixlen = prefixlen;
> +
> +        addr->cinfo.ifa_prefered = lifetime_preferred;
> +        addr->cinfo.ifa_valid = lifetime_valid;
> +
> +        log_link_struct(link, LOG_INFO, "MESSAGE=%-*s: DHCPv6 address %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x/%d timeout preferred %d valid %d",
> +                        IFNAMSIZ,
> +                        link->ifname, ADDRESS6_FMT_VAL(addr->in_addr.in6),
> +                        addr->prefixlen, lifetime_preferred, lifetime_valid,
> +                        NULL);
> +
> +        r = address_update(addr, link, dhcp6_address_handler);
> +        if (r < 0)
> +                log_link_warning(link, "Could not assign DHCPv6 address: %s",
> +                                strerror(-r));
> +
> +        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;
> +
> +        r = sd_dhcp6_lease_reset_address_iter(lease);
> +        if (r < 0 && r != -ENOMSG)
> +                return r;
I was thinking about this when looking at the patch adding sd_dhcp6_lease_reset_address_iter(),
but since I wasn't sure how it will be used, I didn't write anythign.
So this comment is really for that patch.

Maybe sd_dhcp6_lease_reset_address_iter() should always succeed,
an not return -ENOMSG. It would make it more like other "reset" functions
in systemd (e.g. sd_journal_restart_unique).

> +        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) {
> +                        r = dhcp6_address_update(link, &ip6_addr, 128,
> +                                                lifetime_preferred,
> +                                                lifetime_valid);
> +
> +                        return r;
> +                }
> +        }
> +
> +        return 0;
> +}
> +
> +static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
> +        int r;
> +        sd_dhcp6_lease *lease;
> +        struct in6_addr ip6_addr;
> +        uint32_t lifetime_preferred, lifetime_valid;
> +        uint8_t prefixlen;
> +
> +        r = sd_dhcp6_client_get_lease(client, &lease);
> +        if (r < 0)
> +                return r;
> +
> +        r = sd_dhcp6_lease_reset_address_iter(lease);
> +        if (r < 0 && r != -ENOMSG)
> +                return r;
> +
> +        while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
> +                                                &lifetime_preferred,
> +                                                &lifetime_valid) >= 0) {
> +
> +                r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery,
> +                                        &ip6_addr, &prefixlen);
> +                if (r < 0 && r != -EADDRNOTAVAIL) {
> +                        log_link_warning(link, "Could not get prefix information: %s",
> +                                        strerror(-r));
It seems like it's time to add log_link_warning_errno.

> +                        return r;
> +                }
> +
> +                if (r == -EADDRNOTAVAIL)
> +                        prefixlen = 128;
> +
> +                r = dhcp6_address_update(link, &ip6_addr, prefixlen,
> +                                        lifetime_preferred, lifetime_valid);
> +                if (r < 0)
> +                        return r;
> +        }
> +
> +        return 0;
> +}
> +
>  static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
> +        int r;
>          Link *link = userdata;
>  
>          assert(link);
> @@ -42,9 +186,23 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) {
>          case DHCP6_EVENT_STOP:
>          case DHCP6_EVENT_RESEND_EXPIRE:
>          case DHCP6_EVENT_RETRANS_MAX:
> +                log_link_debug(link, "DHCPv6 event %d", event);
> +                break;
> +
>          case DHCP6_EVENT_IP_ACQUIRE:
> +                r = dhcp6_lease_address_acquired(client, link);
> +                if (r < 0) {
> +                        link_enter_failed(link);
> +                        return;
> +                }
> +
> +                /* fall through */
>          case DHCP6_EVENT_INFORMATION_REQUEST:
> -                log_link_debug(link, "DHCPv6 event %d", event);
> +                r = dhcp6_lease_information_acquired(client, link);
> +                if (r < 0) {
> +                        link_enter_failed(link);
> +                        return;
> +                }
>  
>                  break;
>  
> @@ -72,7 +230,8 @@ static int dhcp6_configure(Link *link, int event) {
>                  r = sd_dhcp6_client_get_information_request(link->dhcp6_client,
>                                                          &information_request);
>                  if (r < 0) {
> -                        log_link_warning(link, "Could not get DHCPv6 Information request setting");
> +                        log_link_warning(link, "Could not get DHCPv6 Information request setting: %s",
> +                                        strerror(-r));
>                          link->dhcp6_client =
>                                  sd_dhcp6_client_unref(link->dhcp6_client);
>                          return r;
> @@ -84,7 +243,8 @@ static int dhcp6_configure(Link *link, int event) {
>                  r = sd_dhcp6_client_set_information_request(link->dhcp6_client,
>                                                          false);
>                  if (r < 0) {
> -                        log_link_warning(link, "Could not unset DHCPv6 Information request");
> +                        log_link_warning(link, "Could not unset DHCPv6 Information request: %s",
> +                                        strerror(-r));
>                          link->dhcp6_client =
>                                  sd_dhcp6_client_unref(link->dhcp6_client);
>                          return r;
> @@ -92,7 +252,8 @@ static int dhcp6_configure(Link *link, int event) {
>  
>                  r = sd_dhcp6_client_start(link->dhcp6_client);
>                  if (r < 0) {
> -                        log_link_warning(link, "Could not restart DHCPv6 after enabling Information request");
> +                        log_link_warning(link, "Could not restart DHCPv6 after enabling Information request: %s",
> +                                        strerror(-r));
>                          link->dhcp6_client =
>                                  sd_dhcp6_client_unref(link->dhcp6_client);
>                          return r;
> @@ -166,6 +327,13 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
>          case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT:
>          case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER:
>          case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED:
> +                dhcp6_configure(link, event);
> +
> +                break;
> +
> +        case ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED:
> +                dhcp6_prefix_expired(link);
> +
>                  break;
>  
>          default:
> @@ -176,10 +344,9 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) {
>                          log_link_warning(link, "ICMPv6 unknown event: %d",
>                                           event);
>  
> -                return;
> +                break;
>          }
>  
> -        dhcp6_configure(link, event);
>  }
>  
>  int icmp6_configure(Link *link) {
> diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
> index 0e2f558..be5d0be 100644
> --- a/src/network/networkd-link.h
> +++ b/src/network/networkd-link.h
> @@ -157,3 +157,13 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
>          ((address).s_addr >> 8) & 0xFF,     \
>          ((address).s_addr >> 16) & 0xFF,    \
>          (address).s_addr >> 24
> +
> +#define ADDRESS6_FMT_VAL(address)               \
> +        be16toh((address).s6_addr16[0]),        \
> +        be16toh((address).s6_addr16[1]),        \
> +        be16toh((address).s6_addr16[2]),        \
> +        be16toh((address).s6_addr16[3]),        \
> +        be16toh((address).s6_addr16[4]),        \
> +        be16toh((address).s6_addr16[5]),        \
> +        be16toh((address).s6_addr16[6]),        \
> +        be16toh((address).s6_addr16[7])
> diff --git a/src/network/networkd.c b/src/network/networkd.c
> index ced319d..ce96286 100644
> --- a/src/network/networkd.c
> +++ b/src/network/networkd.c
> @@ -33,6 +33,7 @@ int main(int argc, char *argv[]) {
>          int r;
>  
>          log_set_target(LOG_TARGET_AUTO);
> +        log_set_max_level(LOG_DEBUG);
>          log_parse_environment();
>          log_open();
>  

Zbyszek


More information about the systemd-devel mailing list