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 return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
123 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
125 return log_error_errno(r, "Could not set prefixlen: %m");
127 if (address->family == AF_INET)
128 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
129 else if (address->family == AF_INET6)
130 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
132 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
134 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
136 return log_error_errno(r, "Could not send rtnetlink message: %m");
143 int address_update(Address *address, Link *link,
144 sd_rtnl_message_handler_t callback) {
145 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
149 assert(address->family == AF_INET || address->family == AF_INET6);
150 assert(link->ifindex > 0);
151 assert(link->manager);
152 assert(link->manager->rtnl);
154 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
155 link->ifindex, address->family);
157 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
159 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
161 return log_error_errno(r, "Could not set prefixlen: %m");
163 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
165 return log_error_errno(r, "Could not set flags: %m");
167 r = sd_rtnl_message_addr_set_scope(req, address->scope);
169 return log_error_errno(r, "Could not set scope: %m");
171 if (address->family == AF_INET)
172 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
173 else if (address->family == AF_INET6)
174 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
176 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
178 if (address->family == AF_INET) {
179 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
181 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
184 if (address->label) {
185 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
187 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
190 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
192 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
194 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
196 return log_error_errno(r, "Could not send rtnetlink message: %m");
203 static int address_acquire(Link *link, Address *original, Address **ret) {
204 union in_addr_union in_addr = {};
205 struct in_addr broadcast = {};
206 _cleanup_address_free_ Address *na = NULL;
213 /* Something useful was configured? just use it */
214 if (in_addr_is_null(original->family, &original->in_addr) <= 0)
217 /* The address is configured to be 0.0.0.0 or [::] by the user?
218 * Then let's acquire something more useful from the pool. */
219 r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
221 log_link_error(link, "Failed to acquire address from pool: %s", strerror(-r));
225 log_link_error(link, "Couldn't find free address for interface, all taken.");
229 if (original->family == AF_INET) {
230 /* Pick first address in range for ourselves ...*/
231 in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1);
233 /* .. and use last as broadcast address */
234 broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen);
235 } else if (original->family == AF_INET6)
236 in_addr.in6.s6_addr[15] |= 1;
238 r = address_new_dynamic(&na);
242 na->family = original->family;
243 na->prefixlen = original->prefixlen;
244 na->scope = original->scope;
245 na->cinfo = original->cinfo;
247 if (original->label) {
248 na->label = strdup(original->label);
253 na->broadcast = broadcast;
254 na->in_addr = in_addr;
256 LIST_PREPEND(addresses, link->pool_addresses, na);
264 int address_configure(Address *address, Link *link,
265 sd_rtnl_message_handler_t callback) {
266 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
270 assert(address->family == AF_INET || address->family == AF_INET6);
272 assert(link->ifindex > 0);
273 assert(link->manager);
274 assert(link->manager->rtnl);
276 r = address_acquire(link, address, &address);
280 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
281 link->ifindex, address->family);
283 return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
285 r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
287 return log_error_errno(r, "Could not set prefixlen: %m");
289 r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
291 return log_error_errno(r, "Could not set flags: %m");
293 r = sd_rtnl_message_addr_set_scope(req, address->scope);
295 return log_error_errno(r, "Could not set scope: %m");
297 if (address->family == AF_INET)
298 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
299 else if (address->family == AF_INET6)
300 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
302 return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
304 if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
305 if (address->family == AF_INET)
306 r = sd_rtnl_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
307 else if (address->family == AF_INET6)
308 r = sd_rtnl_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
310 return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
312 if (address->family == AF_INET) {
313 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
315 return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
319 if (address->label) {
320 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
322 return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
325 r = sd_rtnl_message_append_cache_info(req, IFA_CACHEINFO,
328 return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
330 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
332 return log_error_errno(r, "Could not send rtnetlink message: %m");
339 int config_parse_broadcast(
341 const char *filename,
344 unsigned section_line,
351 Network *network = userdata;
352 _cleanup_address_free_ Address *n = NULL;
361 r = address_new_static(network, section_line, &n);
365 if (n->family == AF_INET6) {
366 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
367 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
371 r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
373 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
374 "Broadcast is invalid, ignoring assignment: %s", rvalue);
384 int config_parse_address(const char *unit,
385 const char *filename,
388 unsigned section_line,
395 Network *network = userdata;
396 _cleanup_address_free_ Address *n = NULL;
397 const char *address, *e;
398 union in_addr_union buffer;
407 if (streq(section, "Network")) {
408 /* we are not in an Address section, so treat
409 * this as the special '0' section */
413 r = address_new_static(network, section_line, &n);
417 /* Address=address/prefixlen */
420 e = strchr(rvalue, '/');
423 r = safe_atou(e + 1, &i);
425 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
426 "Prefix length is invalid, ignoring assignment: %s", e + 1);
430 n->prefixlen = (unsigned char) i;
432 address = strndupa(rvalue, e - rvalue);
436 r = in_addr_from_string_auto(address, &f, &buffer);
438 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
439 "Address is invalid, ignoring assignment: %s", address);
443 if (!e && f == AF_INET) {
444 r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen);
446 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
447 "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address);
452 if (n->family != AF_UNSPEC && f != n->family) {
453 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
454 "Address is incompatible, ignoring assignment: %s", address);
460 if (streq(lvalue, "Address"))
463 n->in_addr_peer = buffer;
465 if (n->family == AF_INET && n->broadcast.s_addr == 0)
466 n->broadcast.s_addr = n->in_addr.in.s_addr | htonl(0xfffffffflu >> n->prefixlen);
473 int config_parse_label(const char *unit,
474 const char *filename,
477 unsigned section_line,
483 Network *network = userdata;
484 _cleanup_address_free_ Address *n = NULL;
494 r = address_new_static(network, section_line, &n);
498 label = strdup(rvalue);
502 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
503 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
504 "Interface label is not ASCII clean or is too"
505 " long, ignoring assignment: %s", rvalue);
523 bool address_equal(Address *a1, Address *a2) {
528 /* one, but not both, is NULL */
532 if (a1->family != a2->family)
535 switch (a1->family) {
536 /* use the same notion of equality as the kernel does */
541 if (a1->prefixlen != a2->prefixlen)
546 b1 = be32toh(a1->in_addr.in.s_addr);
547 b2 = be32toh(a2->in_addr.in.s_addr);
549 return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen));
556 b1 = (uint64_t*)&a1->in_addr.in6;
557 b2 = (uint64_t*)&a2->in_addr.in6;
559 return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL);
562 assert_not_reached("Invalid address family");