chiark / gitweb /
networkd: add support for IPv6 tokens
authorTom Gundersen <teg@jklm.no>
Sun, 8 Feb 2015 22:20:56 +0000 (23:20 +0100)
committerTom Gundersen <teg@jklm.no>
Mon, 9 Feb 2015 11:20:10 +0000 (12:20 +0100)
This allows the admin to set the host-specific part of IPv6 addresses, but still
receive the prefix via SLAAC.

.network file snippet:

[Network]
IPv6Token=::12

gives:

$ ip token
token ::12 dev eth0

This closes https://bugs.freedesktop.org/show_bug.cgi?id=81177.

src/network/networkd-link.c
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd.h

index 3b9881d..1f96c63 100644 (file)
@@ -1097,36 +1097,44 @@ static int link_up(Link *link) {
                 }
         }
 
-        if (!link_ipv6ll_enabled(link)) {
-                r = sd_rtnl_message_open_container(req, IFLA_AF_SPEC);
-                if (r < 0) {
-                        log_link_error(link, "Could not open IFLA_AF_SPEC container: %s", strerror(-r));
-                        return r;
-                }
+        r = sd_rtnl_message_open_container(req, IFLA_AF_SPEC);
+        if (r < 0) {
+                log_link_error(link, "Could not open IFLA_AF_SPEC container: %s", strerror(-r));
+                return r;
+        }
 
-                r = sd_rtnl_message_open_container(req, AF_INET6);
-                if (r < 0) {
-                        log_link_error(link, "Could not open AF_INET6 container: %s", strerror(-r));
-                        return r;
-                }
+        r = sd_rtnl_message_open_container(req, AF_INET6);
+        if (r < 0) {
+                log_link_error(link, "Could not open AF_INET6 container: %s", strerror(-r));
+                return r;
+        }
 
+        if (!link_ipv6ll_enabled(link)) {
                 r = sd_rtnl_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, IN6_ADDR_GEN_MODE_NONE);
                 if (r < 0) {
                         log_link_error(link, "Could not append IFLA_INET6_ADDR_GEN_MODE: %s", strerror(-r));
                         return r;
                 }
+        }
 
-                r = sd_rtnl_message_close_container(req);
+        if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) {
+                r = sd_rtnl_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6);
                 if (r < 0) {
-                        log_link_error(link, "Could not close AF_INET6 contaire: %s", strerror(-r));
+                        log_link_error(link, "Could not append IFLA_INET6_TOKEN: %s", strerror(-r));
                         return r;
                 }
+        }
 
-                r = sd_rtnl_message_close_container(req);
-                if (r < 0) {
-                        log_link_error(link, "Could not close IFLA_AF_SPEC contaire: %s", strerror(-r));
-                        return r;
-                }
+        r = sd_rtnl_message_close_container(req);
+        if (r < 0) {
+                log_link_error(link, "Could not close AF_INET6 container: %s", strerror(-r));
+                return r;
+        }
+
+        r = sd_rtnl_message_close_container(req);
+        if (r < 0) {
+                log_link_error(link, "Could not close IFLA_AF_SPEC contaire: %s", strerror(-r));
+                return r;
         }
 
         r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link,
index 525f2ba..6f29548 100644 (file)
@@ -38,6 +38,7 @@ Network.DHCP,                config_parse_dhcp,                  0,
 Network.DHCPServer,          config_parse_bool,                  0,                             offsetof(Network, dhcp_server)
 Network.LinkLocal,           config_parse_address_family_boolean,0,                             offsetof(Network, link_local)
 Network.IPv4LLRoute,         config_parse_bool,                  0,                             offsetof(Network, ipv4ll_route)
+Network.IPv6Token,           config_parse_token,                 0,                             offsetof(Network, ipv6_token)
 Network.LLDP,                config_parse_bool,                  0,                             offsetof(Network, lldp)
 Network.Address,             config_parse_address,               0,                             0
 Network.Gateway,             config_parse_gateway,               0,                             0
index c39ba6d..9ebc2d1 100644 (file)
@@ -626,7 +626,7 @@ int config_parse_llmnr(
         assert(filename);
         assert(lvalue);
         assert(rvalue);
-        assert(data);
+        assert(llmnr);
 
         /* Our enum shall be a superset of booleans, hence first try
          * to parse as boolean, and then as enum */
@@ -650,3 +650,46 @@ int config_parse_llmnr(
 
         return 0;
 }
+
+int config_parse_token(
+                const char* unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        union in_addr_union buffer;
+        struct in6_addr *token = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(token);
+
+        r = in_addr_from_string(AF_INET6, rvalue, &buffer);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        r = in_addr_is_null(AF_INET6, &buffer);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, -r, "IPv6 token canno t be the ANY address, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token canno t be longer than 64 bits, ignoring: %s", rvalue);
+                return 0;
+        }
+
+        *token = buffer.in6;
+
+        return 0;
+}
index 4f3bcf3..6fb920b 100644 (file)
@@ -128,6 +128,7 @@ struct Network {
         unsigned dhcp_route_metric;
         AddressFamilyBoolean link_local;
         bool ipv4ll_route;
+        union in_addr_union ipv6_token;
 
         bool dhcp_server;
 
@@ -405,6 +406,11 @@ int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line,
                         const char *section, unsigned section_line, const char *lvalue,
                         int ltype, const char *rvalue, void *data, void *userdata);
 
+/* IPv6 support */
+int config_parse_token(const char *unit, const char *filename, unsigned line,
+                       const char *section, unsigned section_line, const char *lvalue,
+                       int ltype, const char *rvalue, void *data, void *userdata);
+
 /* LLMNR support */
 
 const char* llmnr_support_to_string(LLMNRSupport i) _const_;