From 7f77697a1744f8df2089848b9d718faf7ba6c665 Mon Sep 17 00:00:00 2001 From: Tom Gundersen Date: Sun, 8 Feb 2015 23:20:56 +0100 Subject: [PATCH] networkd: add support for IPv6 tokens 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 | 46 ++++++++++++++---------- src/network/networkd-network-gperf.gperf | 1 + src/network/networkd-network.c | 45 ++++++++++++++++++++++- src/network/networkd.h | 6 ++++ 4 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 3b9881d71e5..1f96c634efc 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1097,36 +1097,44 @@ static int link_up(Link *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, 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_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_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, diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 525f2ba799a..6f295488bdd 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -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 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index c39ba6dfa25..9ebc2d15aae 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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; +} diff --git a/src/network/networkd.h b/src/network/networkd.h index 4f3bcf36f9d..6fb920b1587 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -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_;