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

2015-01-13 Thread Zbigniew Jędrzejewski-Szmek
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);
 +
 +   

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

2015-01-13 Thread Patrik Flykt
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;
+
+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