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("Could not allocate RTM_DELADDR message: %s",
126 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
128 log_error_errno(-r
, "Could not set prefixlen: %m");
132 if (address
->family
== AF_INET
)
133 r
= sd_rtnl_message_append_in_addr(req
, IFA_LOCAL
, &address
->in_addr
.in
);
134 else if (address
->family
== AF_INET6
)
135 r
= sd_rtnl_message_append_in6_addr(req
, IFA_LOCAL
, &address
->in_addr
.in6
);
137 log_error("Could not append IFA_LOCAL attribute: %s",
142 r
= sd_rtnl_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
144 log_error_errno(-r
, "Could not send rtnetlink message: %m");
153 int address_update(Address
*address
, Link
*link
,
154 sd_rtnl_message_handler_t callback
) {
155 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
;
159 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
160 assert(link
->ifindex
> 0);
161 assert(link
->manager
);
162 assert(link
->manager
->rtnl
);
164 r
= sd_rtnl_message_new_addr_update(link
->manager
->rtnl
, &req
,
165 link
->ifindex
, address
->family
);
167 log_error("Could not allocate RTM_NEWADDR message: %s",
172 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
174 log_error_errno(-r
, "Could not set prefixlen: %m");
178 r
= sd_rtnl_message_addr_set_flags(req
, IFA_F_PERMANENT
);
180 log_error_errno(-r
, "Could not set flags: %m");
184 r
= sd_rtnl_message_addr_set_scope(req
, address
->scope
);
186 log_error_errno(-r
, "Could not set scope: %m");
190 if (address
->family
== AF_INET
)
191 r
= sd_rtnl_message_append_in_addr(req
, IFA_LOCAL
, &address
->in_addr
.in
);
192 else if (address
->family
== AF_INET6
)
193 r
= sd_rtnl_message_append_in6_addr(req
, IFA_LOCAL
, &address
->in_addr
.in6
);
195 log_error("Could not append IFA_LOCAL attribute: %s",
200 if (address
->family
== AF_INET
) {
201 r
= sd_rtnl_message_append_in_addr(req
, IFA_BROADCAST
, &address
->broadcast
);
203 log_error("Could not append IFA_BROADCAST attribute: %s",
209 if (address
->label
) {
210 r
= sd_rtnl_message_append_string(req
, IFA_LABEL
, address
->label
);
212 log_error("Could not append IFA_LABEL attribute: %s",
218 r
= sd_rtnl_message_append_cache_info(req
, IFA_CACHEINFO
, &address
->cinfo
);
220 log_error("Could not append IFA_CACHEINFO attribute: %s",
225 r
= sd_rtnl_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
227 log_error_errno(-r
, "Could not send rtnetlink message: %m");
236 static int address_acquire(Link
*link
, Address
*original
, Address
**ret
) {
237 union in_addr_union in_addr
= {};
238 struct in_addr broadcast
= {};
239 _cleanup_address_free_ Address
*na
= NULL
;
246 /* Something useful was configured? just use it */
247 if (in_addr_is_null(original
->family
, &original
->in_addr
) <= 0)
250 /* The address is configured to be 0.0.0.0 or [::] by the user?
251 * Then let's acquire something more useful from the pool. */
252 r
= manager_address_pool_acquire(link
->manager
, original
->family
, original
->prefixlen
, &in_addr
);
254 log_link_error(link
, "Failed to acquire address from pool: %s", strerror(-r
));
258 log_link_error(link
, "Couldn't find free address for interface, all taken.");
262 if (original
->family
== AF_INET
) {
263 /* Pick first address in range for ourselves ...*/
264 in_addr
.in
.s_addr
= in_addr
.in
.s_addr
| htobe32(1);
266 /* .. and use last as broadcast address */
267 broadcast
.s_addr
= in_addr
.in
.s_addr
| htobe32(0xFFFFFFFFUL
>> original
->prefixlen
);
268 } else if (original
->family
== AF_INET6
)
269 in_addr
.in6
.s6_addr
[15] |= 1;
271 r
= address_new_dynamic(&na
);
275 na
->family
= original
->family
;
276 na
->prefixlen
= original
->prefixlen
;
277 na
->scope
= original
->scope
;
278 na
->cinfo
= original
->cinfo
;
280 if (original
->label
) {
281 na
->label
= strdup(original
->label
);
286 na
->broadcast
= broadcast
;
287 na
->in_addr
= in_addr
;
289 LIST_PREPEND(addresses
, link
->pool_addresses
, na
);
297 int address_configure(Address
*address
, Link
*link
,
298 sd_rtnl_message_handler_t callback
) {
299 _cleanup_rtnl_message_unref_ sd_rtnl_message
*req
= NULL
;
303 assert(address
->family
== AF_INET
|| address
->family
== AF_INET6
);
305 assert(link
->ifindex
> 0);
306 assert(link
->manager
);
307 assert(link
->manager
->rtnl
);
309 r
= address_acquire(link
, address
, &address
);
313 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_NEWADDR
,
314 link
->ifindex
, address
->family
);
316 log_error("Could not allocate RTM_NEWADDR message: %s",
321 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
323 log_error_errno(-r
, "Could not set prefixlen: %m");
327 r
= sd_rtnl_message_addr_set_flags(req
, IFA_F_PERMANENT
);
329 log_error_errno(-r
, "Could not set flags: %m");
333 r
= sd_rtnl_message_addr_set_scope(req
, address
->scope
);
335 log_error_errno(-r
, "Could not set scope: %m");
339 if (address
->family
== AF_INET
)
340 r
= sd_rtnl_message_append_in_addr(req
, IFA_LOCAL
, &address
->in_addr
.in
);
341 else if (address
->family
== AF_INET6
)
342 r
= sd_rtnl_message_append_in6_addr(req
, IFA_LOCAL
, &address
->in_addr
.in6
);
344 log_error("Could not append IFA_LOCAL attribute: %s",
349 if (!in_addr_is_null(address
->family
, &address
->in_addr_peer
)) {
350 if (address
->family
== AF_INET
)
351 r
= sd_rtnl_message_append_in_addr(req
, IFA_ADDRESS
, &address
->in_addr_peer
.in
);
352 else if (address
->family
== AF_INET6
)
353 r
= sd_rtnl_message_append_in6_addr(req
, IFA_ADDRESS
, &address
->in_addr_peer
.in6
);
355 log_error("Could not append IFA_ADDRESS attribute: %s",
360 if (address
->family
== AF_INET
) {
361 r
= sd_rtnl_message_append_in_addr(req
, IFA_BROADCAST
, &address
->broadcast
);
363 log_error("Could not append IFA_BROADCAST attribute: %s",
370 if (address
->label
) {
371 r
= sd_rtnl_message_append_string(req
, IFA_LABEL
, address
->label
);
373 log_error("Could not append IFA_LABEL attribute: %s",
379 r
= sd_rtnl_message_append_cache_info(req
, IFA_CACHEINFO
,
382 log_error("Could not append IFA_CACHEINFO attribute: %s",
387 r
= sd_rtnl_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
389 log_error_errno(-r
, "Could not send rtnetlink message: %m");
398 int config_parse_broadcast(
400 const char *filename
,
403 unsigned section_line
,
410 Network
*network
= userdata
;
411 _cleanup_address_free_ Address
*n
= NULL
;
420 r
= address_new_static(network
, section_line
, &n
);
424 if (n
->family
== AF_INET6
) {
425 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
426 "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue
);
430 r
= in_addr_from_string(AF_INET
, rvalue
, (union in_addr_union
*) &n
->broadcast
);
432 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
433 "Broadcast is invalid, ignoring assignment: %s", rvalue
);
443 int config_parse_address(const char *unit
,
444 const char *filename
,
447 unsigned section_line
,
454 Network
*network
= userdata
;
455 _cleanup_address_free_ Address
*n
= NULL
;
456 const char *address
, *e
;
457 union in_addr_union buffer
;
466 if (streq(section
, "Network")) {
467 /* we are not in an Address section, so treat
468 * this as the special '0' section */
472 r
= address_new_static(network
, section_line
, &n
);
476 /* Address=address/prefixlen */
479 e
= strchr(rvalue
, '/');
482 r
= safe_atou(e
+ 1, &i
);
484 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
485 "Prefix length is invalid, ignoring assignment: %s", e
+ 1);
489 n
->prefixlen
= (unsigned char) i
;
491 address
= strndupa(rvalue
, e
- rvalue
);
495 r
= in_addr_from_string_auto(address
, &f
, &buffer
);
497 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
498 "Address is invalid, ignoring assignment: %s", address
);
502 if (!e
&& f
== AF_INET
) {
503 r
= in_addr_default_prefixlen(&buffer
.in
, &n
->prefixlen
);
505 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
506 "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address
);
511 if (n
->family
!= AF_UNSPEC
&& f
!= n
->family
) {
512 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
513 "Address is incompatible, ignoring assignment: %s", address
);
519 if (streq(lvalue
, "Address"))
522 n
->in_addr_peer
= buffer
;
524 if (n
->family
== AF_INET
&& n
->broadcast
.s_addr
== 0)
525 n
->broadcast
.s_addr
= n
->in_addr
.in
.s_addr
| htonl(0xfffffffflu
>> n
->prefixlen
);
532 int config_parse_label(const char *unit
,
533 const char *filename
,
536 unsigned section_line
,
542 Network
*network
= userdata
;
543 _cleanup_address_free_ Address
*n
= NULL
;
553 r
= address_new_static(network
, section_line
, &n
);
557 label
= strdup(rvalue
);
561 if (!ascii_is_valid(label
) || strlen(label
) >= IFNAMSIZ
) {
562 log_syntax(unit
, LOG_ERR
, filename
, line
, EINVAL
,
563 "Interface label is not ASCII clean or is too"
564 " long, ignoring assignment: %s", rvalue
);
582 bool address_equal(Address
*a1
, Address
*a2
) {
587 /* one, but not both, is NULL */
591 if (a1
->family
!= a2
->family
)
594 switch (a1
->family
) {
595 /* use the same notion of equality as the kernel does */
600 if (a1
->prefixlen
!= a2
->prefixlen
)
605 b1
= be32toh(a1
->in_addr
.in
.s_addr
);
606 b2
= be32toh(a2
->in_addr
.in
.s_addr
);
608 return (b1
>> (32 - a1
->prefixlen
)) == (b2
>> (32 - a1
->prefixlen
));
615 b1
= (uint64_t*)&a1
->in_addr
.in6
;
616 b2
= (uint64_t*)&a2
->in_addr
.in6
;
618 return (((b1
[0] ^ b2
[0]) | (b1
[1] ^ b2
[1])) == 0UL);
621 assert_not_reached("Invalid address family");