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/>.
25 #include "networkd-link.h"
29 #include "conf-parser.h"
30 #include "network-internal.h"
32 static void address_init(Address *address) {
35 address->family = AF_UNSPEC;
36 address->scope = RT_SCOPE_UNIVERSE;
37 address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
38 address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME;
41 int address_new_static(Network *network, unsigned section, Address **ret) {
42 _cleanup_address_free_ Address *address = NULL;
45 address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section));
54 address = new0(Address, 1);
58 address_init(address);
60 address->network = network;
62 LIST_PREPEND(addresses, network->static_addresses, address);
65 address->section = section;
66 hashmap_put(network->addresses_by_section,
67 UINT_TO_PTR(address->section), address);
76 int address_new_dynamic(Address **ret) {
77 _cleanup_address_free_ Address *address = NULL;
79 address = new0(Address, 1);
83 address_init(address);
91 void address_free(Address *address) {
95 if (address->network) {
96 LIST_REMOVE(addresses, address->network->static_addresses, address);
99 hashmap_remove(address->network->addresses_by_section,
100 UINT_TO_PTR(address->section));
106 int address_drop(Address *address, Link *link,
107 sd_rtnl_message_handler_t callback) {
108 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
112 assert(address->family == AF_INET || address->family == AF_INET6);
114 assert(link->ifindex > 0);
115 assert(link->manager);
116 assert(link->manager->rtnl);
118 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
119 link->ifindex, address->family);
121 log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
125 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
127 log_error_errno(r, "Could not set prefixlen: %m");
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_errno(r, "Could not append IFA_LOCAL attribute: %m");
140 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
142 log_error_errno(r, "Could not send rtnetlink message: %m");
151 int address_update(Address *address, Link *link,
152 sd_rtnl_message_handler_t callback) {
153 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
157 assert(address->family == AF_INET || address->family == AF_INET6);
158 assert(link->ifindex > 0);
159 assert(link->manager);
160 assert(link->manager->rtnl);
162 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
163 link->ifindex, address->family);
165 log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
169 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
171 log_error_errno(r, "Could not set prefixlen: %m");
175 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
177 log_error_errno(r, "Could not set flags: %m");
181 r = sd_rtnl_message_addr_set_scope(req, address->scope);
183 log_error_errno(r, "Could not set scope: %m");
187 if (address->family == AF_INET)
188 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
189 else if (address->family == AF_INET6)
190 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
192 log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
196 if (address->family == AF_INET) {
197 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
199 log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
204 if (address->label) {
205 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
207 log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
212 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
214 log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
218 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
220 log_error_errno(r, "Could not send rtnetlink message: %m");
229 static int address_acquire(Link *link, Address *original, Address **ret) {
230 union in_addr_union in_addr = {};
231 struct in_addr broadcast = {};
232 _cleanup_address_free_ Address *na = NULL;
239 /* Something useful was configured? just use it */
240 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
243 /* The address is configured to be 0.0.0.0 or [::] by the user?
244 * Then let's acquire something more useful from the pool. */
245 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
247 log_link_error(link, "Failed to acquire address from pool: %s", strerror(-r));
251 log_link_error(link, "Couldn't find free address for interface, all taken.");
255 if (original->family == AF_INET) {
256 /* Pick first address in range for ourselves ...*/
257 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
259 /* .. and use last as broadcast address */
260 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
261 } else if (original->family == AF_INET6)
262 in_addr.in6.s6_addr[15] |= 1;
264 r = address_new_dynamic(&na);
268 na->family = original->family;
269 na->prefixlen = original->prefixlen;
270 na->scope = original->scope;
271 na->cinfo = original->cinfo;
273 if (original->label) {
274 na->label = strdup(original->label);
279 na->broadcast = broadcast;
280 na->in_addr = in_addr;
282 LIST_PREPEND(addresses, link->pool_addresses, na);
290 int address_configure(Address *address, Link *link,
291 sd_rtnl_message_handler_t callback) {
292 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
296 assert(address->family == AF_INET || address->family == AF_INET6);
298 assert(link->ifindex > 0);
299 assert(link->manager);
300 assert(link->manager->rtnl);
302 r = address_acquire(link, address, &address);
306 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
307 link->ifindex, address->family);
309 log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
313 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
315 log_error_errno(r, "Could not set prefixlen: %m");
319 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
321 log_error_errno(r, "Could not set flags: %m");
325 r = sd_rtnl_message_addr_set_scope(req, address->scope);
327 log_error_errno(r, "Could not set scope: %m");
331 if (address->family == AF_INET)
332 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
333 else if (address->family == AF_INET6)
334 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
336 log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
340 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
341 if (address->family == AF_INET)
342 r = sd_rtnl_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
343 else if (address->family == AF_INET6)
344 r = sd_rtnl_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
346 log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
350 if (address->family == AF_INET) {
351 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
353 log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
359 if (address->label) {
360 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
362 log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
367 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
370 log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
374 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
376 log_error_errno(r, "Could not send rtnetlink message: %m");
385 int config_parse_broadcast(
387 const char *filename,
390 unsigned section_line,
397 Network *network = userdata;
398 _cleanup_address_free_ Address *n = NULL;
407 r = address_new_static(network, section_line, &n);
411 if (n->family == AF_INET6) {
412 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
413 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
417 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
419 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
420 "Broadcast is invalid, ignoring assignment: %s", rvalue);
430 int config_parse_address(const char *unit,
431 const char *filename,
434 unsigned section_line,
441 Network *network = userdata;
442 _cleanup_address_free_ Address *n = NULL;
443 const char *address, *e;
444 union in_addr_union buffer;
453 if (streq(section, "Network")) {
454 /* we are not in an Address section, so treat
455 * this as the special '0' section */
459 r = address_new_static(network, section_line, &n);
463 /* Address=address/prefixlen */
466 e = strchr(rvalue, '/');
469 r = safe_atou(e + 1, &i);
471 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
472 "Prefix length is invalid, ignoring assignment: %s", e + 1);
476 n->prefixlen = (unsigned char) i;
478 address = strndupa(rvalue, e - rvalue);
482 r = in_addr_from_string_auto(address, &f, &buffer);
484 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
485 "Address is invalid, ignoring assignment: %s", address);
489 if (!e && f == AF_INET) {
490 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
492 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
493 "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
498 if (n->family != AF_UNSPEC && f != n->family) {
499 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
500 "Address is incompatible, ignoring assignment: %s", address);
506 if (streq(lvalue, "Address"))
509 n->in_addr_peer = buffer;
511 if (n->family == AF_INET && n->broadcast.s_addr == 0)
512 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
519 int config_parse_label(const char *unit,
520 const char *filename,
523 unsigned section_line,
529 Network *network = userdata;
530 _cleanup_address_free_ Address *n = NULL;
540 r = address_new_static(network, section_line, &n);
544 label = strdup(rvalue);
548 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
549 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
550 "Interface label is not ASCII clean or is too"
551 " long, ignoring assignment: %s", rvalue);
569 bool address_equal(Address *a1, Address *a2) {
574 /* one, but not both, is NULL */
578 if (a1->family != a2->family)
581 switch (a1->family) {
582 /* use the same notion of equality as the kernel does */
587 if (a1->prefixlen != a2->prefixlen)
592 b1 = be32toh(a1->in_addr.in.s_addr);
593 b2 = be32toh(a2->in_addr.in.s_addr);
595 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
602 b1 = (uint64_t*)&a1->in_addr.in6;
603 b2 = (uint64_t*)&a2->in_addr.in6;
605 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
608 assert_not_reached("Invalid address family");