[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