chiark / gitweb /
systemd-networkd: Use IFA_F_NOPREFIXROUTE with IPv6 addresses
authorPatrik Flykt <patrik.flykt@linux.intel.com>
Mon, 2 Feb 2015 11:13:17 +0000 (13:13 +0200)
committerPatrik Flykt <patrik.flykt@linux.intel.com>
Fri, 27 Mar 2015 11:57:13 +0000 (13:57 +0200)
The IFA_F_NOPREFIXROUTE flag prevents the kernel from creating new onlink
prefixes when a DHCPv6 IPv6 address with a prefix length is set from user
space. IPv6 routing will follow the onlink status from Router Advertisment
Prefix Information options or any manually set route, which is the correct
thing to do.

As this flag has a larger value than what fits into an unsigned char, update
the flag attribute to an uint32_t and set it with an IFA_FLAGS attribute
when writing netlink messages to the kernel.

src/network/networkd-address.c
src/network/networkd-dhcp6.c
src/network/networkd-link.c
src/network/networkd.h

index 255ff7702247ee81d5b1c8646c57e286d1f2e8e0..85acc499459c7410e42720cd5814e5dfad32c826 100644 (file)
@@ -209,10 +209,18 @@ int address_update(Address *address, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not set prefixlen: %m");
 
-        r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
+        address->flags |= IFA_F_PERMANENT;
+
+        r = sd_rtnl_message_addr_set_flags(req, address->flags & 0xff);
         if (r < 0)
                 return log_error_errno(r, "Could not set flags: %m");
 
+        if (address->flags & ~0xff) {
+                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");
+        }
+
         r = sd_rtnl_message_addr_set_scope(req, address->scope);
         if (r < 0)
                 return log_error_errno(r, "Could not set scope: %m");
@@ -335,10 +343,18 @@ int address_configure(Address *address, Link *link,
         if (r < 0)
                 return log_error_errno(r, "Could not set prefixlen: %m");
 
-        r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
+        address->flags |= IFA_F_PERMANENT;
+
+        r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
         if (r < 0)
                 return log_error_errno(r, "Could not set flags: %m");
 
+        if (address->flags & ~0xff) {
+                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");
+        }
+
         r = sd_rtnl_message_addr_set_scope(req, address->scope);
         if (r < 0)
                 return log_error_errno(r, "Could not set scope: %m");
index bcfad4c03f9a930a76613166d9e1a35a9cbe24e7..283a7d69926735983600877005a02a2be8d497c1 100644 (file)
@@ -65,7 +65,9 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr,
 
         addr->family = AF_INET6;
         memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr));
-        addr->prefixlen = prefixlen;
+
+        addr->flags = IFA_F_NOPREFIXROUTE;
+        addr->prefixlen = 64;
 
         addr->cinfo.ifa_prefered = lifetime_preferred;
         addr->cinfo.ifa_valid = lifetime_valid;
index 842ca1ce6ed4c6ddc848efc7db15db9750409f54..437c59843ed9aaa4c971dfb28635c59427516fd0 100644 (file)
@@ -1831,6 +1831,7 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
         Link *link = NULL;
         uint16_t type;
         _cleanup_address_free_ Address *address = NULL;
+        unsigned char flags;
         Address *existing;
         char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX];
         const char *valid_str = NULL;
@@ -1894,11 +1895,12 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use
                 return 0;
         }
 
-        r = sd_rtnl_message_addr_get_flags(message, &address->flags);
+        r = sd_rtnl_message_addr_get_flags(message, &flags);
         if (r < 0) {
                 log_link_warning(link, "rtnl: received address with invalid flags, ignoring");
                 return 0;
         }
+        address->flags = flags;
 
         switch (address->family) {
         case AF_INET:
index 8bdc2bed82b24191a1581790b687efa3cd632143..c26d64e38331bf3a70d8a72a1917ae6c3dcbdb54 100644 (file)
@@ -173,7 +173,7 @@ struct Address {
         int family;
         unsigned char prefixlen;
         unsigned char scope;
-        unsigned char flags;
+        uint32_t flags;
         char *label;
 
         struct in_addr broadcast;