1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "conf-parser.h"
29 #include "network-internal.h"
31 static void address_init(Address *address) {
34 address->family = AF_UNSPEC;
35 address->scope = RT_SCOPE_UNIVERSE;
36 address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
37 address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
40 int address_new_static(Network *network, unsigned section, Address **ret) {
41 _cleanup_address_free_ Address *address = NULL;
44 address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
53 address = new0(Address, 1);
57 address_init(address);
59 address->network = network;
61 LIST_PREPEND(addresses, network->static_addresses, address);
64 address->section = section;
65 hashmap_put(network->addresses_by_section,
66 UINT_TO_PTR(address->section), address);
75 int address_new_dynamic(Address **ret) {
76 _cleanup_address_free_ Address *address = NULL;
78 address = new0(Address, 1);
82 address_init(address);
90 void address_free(Address *address) {
94 if (address->network) {
95 LIST_REMOVE(addresses, address->network->static_addresses, address);
98 hashmap_remove(address->network->addresses_by_section,
99 UINT_TO_PTR(address->section));
105 int address_drop(Address *address, Link *link,
106 sd_rtnl_message_handler_t callback) {
107 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
111 assert(address->family == AF_INET || address->family == AF_INET6);
113 assert(link->ifindex > 0);
114 assert(link->manager);
115 assert(link->manager->rtnl);
117 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
118 link->ifindex, address->family);
120 log_error("Could not allocate RTM_DELADDR message: %s",
125 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
127 log_error("Could not set prefixlen: %s", strerror(-r));
131 if (address->family == AF_INET)
132 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
133 else if (address->family == AF_INET6)
134 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
136 log_error("Could not append IFA_LOCAL attribute: %s",
141 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
143 log_error("Could not send rtnetlink message: %s", strerror(-r));
152 int address_update(Address *address, Link *link,
153 sd_rtnl_message_handler_t callback) {
154 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
158 assert(address->family == AF_INET || address->family == AF_INET6);
159 assert(link->ifindex > 0);
160 assert(link->manager);
161 assert(link->manager->rtnl);
163 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
164 link->ifindex, address->family);
166 log_error("Could not allocate RTM_NEWADDR message: %s",
171 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
173 log_error("Could not set prefixlen: %s", strerror(-r));
177 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
179 log_error("Could not set flags: %s", strerror(-r));
183 r = sd_rtnl_message_addr_set_scope(req, address->scope);
185 log_error("Could not set scope: %s", strerror(-r));
189 if (address->family == AF_INET)
190 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
191 else if (address->family == AF_INET6)
192 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
194 log_error("Could not append IFA_LOCAL attribute: %s",
199 if (address->family == AF_INET) {
200 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
202 log_error("Could not append IFA_BROADCAST attribute: %s",
208 if (address->label) {
209 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
211 log_error("Could not append IFA_LABEL attribute: %s",
217 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
219 log_error("Could not append IFA_CACHEINFO attribute: %s",
224 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
226 log_error("Could not send rtnetlink message: %s", strerror(-r));
235 static int address_acquire(Link *link, Address *original, Address **ret) {
236 union in_addr_union in_addr = {};
237 struct in_addr broadcast = {};
238 _cleanup_address_free_ Address *na = NULL;
245 /* Something useful was configured? just use it */
246 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
249 /* The address is configured to be 0.0.0.0 or [::] by the user?
250 * Then let's acquire something more useful from the pool. */
251 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
253 log_error_link(link, "Failed to acquire address from pool: %s", strerror(-r));
257 log_error_link(link, "Couldn't find free address for interface, all taken.");
261 if (original->family == AF_INET) {
262 /* Pick first address in range for ourselves ...*/
263 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
265 /* .. and use last as broadcast address */
266 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
267 } else if (original->family == AF_INET6)
268 in_addr.in6.s6_addr[15] |= 1;
270 r = address_new_dynamic(&na);
274 na->family = original->family;
275 na->prefixlen = original->prefixlen;
276 na->scope = original->scope;
277 na->cinfo = original->cinfo;
279 if (original->label) {
280 na->label = strdup(original->label);
285 na->broadcast = broadcast;
286 na->in_addr = in_addr;
288 LIST_PREPEND(addresses, link->pool_addresses, na);
296 int address_configure(Address *address, Link *link,
297 sd_rtnl_message_handler_t callback) {
298 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
302 assert(address->family == AF_INET || address->family == AF_INET6);
304 assert(link->ifindex > 0);
305 assert(link->manager);
306 assert(link->manager->rtnl);
308 r = address_acquire(link, address, &address);
312 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
313 link->ifindex, address->family);
315 log_error("Could not allocate RTM_NEWADDR message: %s",
320 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
322 log_error("Could not set prefixlen: %s", strerror(-r));
326 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
328 log_error("Could not set flags: %s", strerror(-r));
332 r = sd_rtnl_message_addr_set_scope(req, address->scope);
334 log_error("Could not set scope: %s", strerror(-r));
338 if (address->family == AF_INET)
339 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
340 else if (address->family == AF_INET6)
341 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
343 log_error("Could not append IFA_LOCAL attribute: %s",
348 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
349 if (address->family == AF_INET)
350 r = sd_rtnl_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
351 else if (address->family == AF_INET6)
352 r = sd_rtnl_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
354 log_error("Could not append IFA_ADDRESS attribute: %s",
359 if (address->family == AF_INET) {
360 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
362 log_error("Could not append IFA_BROADCAST attribute: %s",
369 if (address->label) {
370 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
372 log_error("Could not append IFA_LABEL attribute: %s",
378 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
381 log_error("Could not append IFA_CACHEINFO attribute: %s",
386 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
388 log_error("Could not send rtnetlink message: %s", strerror(-r));
397 int config_parse_broadcast(
399 const char *filename,
402 unsigned section_line,
409 Network *network = userdata;
410 _cleanup_address_free_ Address *n = NULL;
419 r = address_new_static(network, section_line, &n);
423 if (n->family == AF_INET6) {
424 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
425 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
429 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
431 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
432 "Broadcast is invalid, ignoring assignment: %s", rvalue);
442 int config_parse_address(const char *unit,
443 const char *filename,
446 unsigned section_line,
453 Network *network = userdata;
454 _cleanup_address_free_ Address *n = NULL;
455 const char *address, *e;
456 union in_addr_union buffer;
465 if (streq(section, "Network")) {
466 /* we are not in an Address section, so treat
467 * this as the special '0' section */
471 r = address_new_static(network, section_line, &n);
475 /* Address=address/prefixlen */
478 e = strchr(rvalue, '/');
481 r = safe_atou(e + 1, &i);
483 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
484 "Interface prefix length is invalid, ignoring assignment: %s", e + 1);
488 n->prefixlen = (unsigned char) i;
490 address = strndupa(rvalue, e - rvalue);
494 r = in_addr_from_string_auto(address, &f, &buffer);
496 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
497 "Address is invalid, ignoring assignment: %s", address);
501 if (n->family != AF_UNSPEC && f != n->family) {
502 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
503 "Address is incompatible, ignoring assignment: %s", address);
509 if (streq(lvalue, "Address"))
512 n->in_addr_peer = buffer;
514 if (n->family == AF_INET && n->broadcast.s_addr == 0)
515 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
522 int config_parse_label(const char *unit,
523 const char *filename,
526 unsigned section_line,
532 Network *network = userdata;
533 _cleanup_address_free_ Address *n = NULL;
543 r = address_new_static(network, section_line, &n);
547 label = strdup(rvalue);
551 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
552 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
553 "Interface label is not ASCII clean or is too"
554 " long, ignoring assignment: %s", rvalue);
572 bool address_equal(Address *a1, Address *a2) {
577 /* one, but not both, is NULL */
581 if (a1->family != a2->family)
584 switch (a1->family) {
585 /* use the same notion of equality as the kernel does */
590 if (a1->prefixlen != a2->prefixlen)
595 b1 = be32toh(a1->in_addr.in.s_addr);
596 b2 = be32toh(a2->in_addr.in.s_addr);
598 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
605 b1 = (uint64_t*)&a1->in_addr.in6;
606 b2 = (uint64_t*)&a2->in_addr.in6;
608 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
611 assert_not_reached("Invalid address family");