1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Tom Gundersen <teg@jklm.no>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "alloc-util.h"
24 #include "conf-parser.h"
25 #include "firewall-util.h"
26 #include "netlink-util.h"
27 #include "networkd-address.h"
28 #include "networkd-manager.h"
29 #include "parse-util.h"
31 #include "socket-util.h"
32 #include "string-util.h"
36 #define ADDRESSES_PER_LINK_MAX 2048U
37 #define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
39 int address_new(Address
**ret
) {
40 _cleanup_address_free_ Address
*address
= NULL
;
42 address
= new0(Address
, 1);
46 address
->family
= AF_UNSPEC
;
47 address
->scope
= RT_SCOPE_UNIVERSE
;
48 address
->cinfo
.ifa_prefered
= CACHE_INFO_INFINITY_LIFE_TIME
;
49 address
->cinfo
.ifa_valid
= CACHE_INFO_INFINITY_LIFE_TIME
;
57 int address_new_static(Network
*network
, const char *filename
, unsigned section_line
, Address
**ret
) {
58 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
59 _cleanup_address_free_ Address
*address
= NULL
;
64 assert(!!filename
== (section_line
> 0));
67 r
= network_config_section_new(filename
, section_line
, &n
);
71 address
= hashmap_get(network
->addresses_by_section
, n
);
80 if (network
->n_static_addresses
>= STATIC_ADDRESSES_PER_NETWORK_MAX
)
83 r
= address_new(&address
);
91 r
= hashmap_put(network
->addresses_by_section
, address
->section
, address
);
96 address
->network
= network
;
97 LIST_APPEND(addresses
, network
->static_addresses
, address
);
98 network
->n_static_addresses
++;
106 void address_free(Address
*address
) {
110 if (address
->network
) {
111 LIST_REMOVE(addresses
, address
->network
->static_addresses
, address
);
112 assert(address
->network
->n_static_addresses
> 0);
113 address
->network
->n_static_addresses
--;
115 if (address
->section
) {
116 hashmap_remove(address
->network
->addresses_by_section
, address
->section
);
117 network_config_section_free(address
->section
);
122 set_remove(address
->link
->addresses
, address
);
123 set_remove(address
->link
->addresses_foreign
, address
);
125 if (in_addr_equal(AF_INET6
, &address
->in_addr
, (const union in_addr_union
*) &address
->link
->ipv6ll_address
))
126 memzero(&address
->link
->ipv6ll_address
, sizeof(struct in6_addr
));
132 static void address_hash_func(const void *b
, struct siphash
*state
) {
133 const Address
*a
= b
;
137 siphash24_compress(&a
->family
, sizeof(a
->family
), state
);
141 siphash24_compress(&a
->prefixlen
, sizeof(a
->prefixlen
), state
);
144 if (a
->prefixlen
!= 0) {
147 if (a
->in_addr_peer
.in
.s_addr
!= 0)
148 prefix
= be32toh(a
->in_addr_peer
.in
.s_addr
) >> (32 - a
->prefixlen
);
150 prefix
= be32toh(a
->in_addr
.in
.s_addr
) >> (32 - a
->prefixlen
);
152 siphash24_compress(&prefix
, sizeof(prefix
), state
);
158 siphash24_compress(&a
->in_addr
, FAMILY_ADDRESS_SIZE(a
->family
), state
);
162 /* treat any other address family as AF_UNSPEC */
167 static int address_compare_func(const void *c1
, const void *c2
) {
168 const Address
*a1
= c1
, *a2
= c2
;
170 if (a1
->family
< a2
->family
)
172 if (a1
->family
> a2
->family
)
175 switch (a1
->family
) {
176 /* use the same notion of equality as the kernel does */
178 if (a1
->prefixlen
< a2
->prefixlen
)
180 if (a1
->prefixlen
> a2
->prefixlen
)
183 /* compare the peer prefixes */
184 if (a1
->prefixlen
!= 0) {
185 /* make sure we don't try to shift by 32.
186 * See ISO/IEC 9899:TC3 § 6.5.7.3. */
189 if (a1
->in_addr_peer
.in
.s_addr
!= 0)
190 b1
= be32toh(a1
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
192 b1
= be32toh(a1
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
194 if (a2
->in_addr_peer
.in
.s_addr
!= 0)
195 b2
= be32toh(a2
->in_addr_peer
.in
.s_addr
) >> (32 - a1
->prefixlen
);
197 b2
= be32toh(a2
->in_addr
.in
.s_addr
) >> (32 - a1
->prefixlen
);
207 return memcmp(&a1
->in_addr
, &a2
->in_addr
, FAMILY_ADDRESS_SIZE(a1
->family
));
209 /* treat any other address family as AF_UNSPEC */
214 static const struct hash_ops address_hash_ops
= {
215 .hash
= address_hash_func
,
216 .compare
= address_compare_func
219 bool address_equal(Address
*a1
, Address
*a2
) {
226 return address_compare_func(a1
, a2
) == 0;
229 static int address_establish(Address
*address
, Link
*link
) {
236 masq
= link
->network
&&
237 link
->network
->ip_masquerade
&&
238 address
->family
== AF_INET
&&
239 address
->scope
< RT_SCOPE_LINK
;
241 /* Add firewall entry if this is requested */
242 if (address
->ip_masquerade_done
!= masq
) {
243 union in_addr_union masked
= address
->in_addr
;
244 in_addr_mask(address
->family
, &masked
, address
->prefixlen
);
246 r
= fw_add_masquerade(masq
, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
248 log_link_warning_errno(link
, r
, "Could not enable IP masquerading: %m");
250 address
->ip_masquerade_done
= masq
;
256 static int address_add_internal(Link
*link
, Set
**addresses
,
258 const union in_addr_union
*in_addr
,
259 unsigned char prefixlen
,
261 _cleanup_address_free_ Address
*address
= NULL
;
268 r
= address_new(&address
);
272 address
->family
= family
;
273 address
->in_addr
= *in_addr
;
274 address
->prefixlen
= prefixlen
;
275 /* Consider address tentative until we get the real flags from the kernel */
276 address
->flags
= IFA_F_TENTATIVE
;
278 r
= set_ensure_allocated(addresses
, &address_hash_ops
);
282 r
= set_put(*addresses
, address
);
286 address
->link
= link
;
296 int address_add_foreign(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
297 return address_add_internal(link
, &link
->addresses_foreign
, family
, in_addr
, prefixlen
, ret
);
300 int address_add(Link
*link
, int family
, const union in_addr_union
*in_addr
, unsigned char prefixlen
, Address
**ret
) {
304 r
= address_get(link
, family
, in_addr
, prefixlen
, &address
);
306 /* Address does not exist, create a new one */
307 r
= address_add_internal(link
, &link
->addresses
, family
, in_addr
, prefixlen
, &address
);
311 /* Take over a foreign address */
312 r
= set_ensure_allocated(&link
->addresses
, &address_hash_ops
);
316 r
= set_put(link
->addresses
, address
);
320 set_remove(link
->addresses_foreign
, address
);
322 /* Already exists, do nothing */
333 static int address_release(Address
*address
) {
337 assert(address
->link
);
339 /* Remove masquerading firewall entry if it was added */
340 if (address
->ip_masquerade_done
) {
341 union in_addr_union masked
= address
->in_addr
;
342 in_addr_mask(address
->family
, &masked
, address
->prefixlen
);
344 r
= fw_add_masquerade(false, AF_INET
, 0, &masked
, address
->prefixlen
, NULL
, NULL
, 0);
346 log_link_warning_errno(address
->link
, r
, "Failed to disable IP masquerading: %m");
348 address
->ip_masquerade_done
= false;
358 const struct ifa_cacheinfo
*cinfo
) {
365 assert_return(address
->link
, 1);
367 if (IN_SET(address
->link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
370 ready
= address_is_ready(address
);
372 address
->flags
= flags
;
373 address
->scope
= scope
;
374 address
->cinfo
= *cinfo
;
376 link_update_operstate(address
->link
);
378 if (!ready
&& address_is_ready(address
)) {
379 link_check_ready(address
->link
);
381 if (address
->family
== AF_INET6
&&
382 in_addr_is_link_local(AF_INET6
, &address
->in_addr
) > 0 &&
383 in_addr_is_null(AF_INET6
, (const union in_addr_union
*) &address
->link
->ipv6ll_address
) > 0) {
385 r
= link_ipv6ll_gained(address
->link
, &address
->in_addr
.in6
);
394 int address_drop(Address
*address
) {
400 ready
= address_is_ready(address
);
401 link
= address
->link
;
403 address_release(address
);
404 address_free(address
);
406 link_update_operstate(link
);
409 link_check_ready(link
);
414 int address_get(Link
*link
,
416 const union in_addr_union
*in_addr
,
417 unsigned char prefixlen
,
420 Address address
, *existing
;
425 address
= (Address
) {
428 .prefixlen
= prefixlen
,
431 existing
= set_get(link
->addresses
, &address
);
438 existing
= set_get(link
->addresses_foreign
, &address
);
451 sd_netlink_message_handler_t callback
) {
453 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
457 assert(IN_SET(address
->family
, AF_INET
, AF_INET6
));
459 assert(link
->ifindex
> 0);
460 assert(link
->manager
);
461 assert(link
->manager
->rtnl
);
463 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_DELADDR
,
464 link
->ifindex
, address
->family
);
466 return log_error_errno(r
, "Could not allocate RTM_DELADDR message: %m");
468 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
470 return log_error_errno(r
, "Could not set prefixlen: %m");
472 if (address
->family
== AF_INET
)
473 r
= sd_netlink_message_append_in_addr(req
, IFA_LOCAL
, &address
->in_addr
.in
);
474 else if (address
->family
== AF_INET6
)
475 r
= sd_netlink_message_append_in6_addr(req
, IFA_LOCAL
, &address
->in_addr
.in6
);
477 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
479 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
481 return log_error_errno(r
, "Could not send rtnetlink message: %m");
488 static int address_acquire(Link
*link
, Address
*original
, Address
**ret
) {
489 union in_addr_union in_addr
= {};
490 struct in_addr broadcast
= {};
491 _cleanup_address_free_ Address
*na
= NULL
;
498 /* Something useful was configured? just use it */
499 if (in_addr_is_null(original
->family
, &original
->in_addr
) <= 0)
502 /* The address is configured to be 0.0.0.0 or [::] by the user?
503 * Then let's acquire something more useful from the pool. */
504 r
= manager_address_pool_acquire(link
->manager
, original
->family
, original
->prefixlen
, &in_addr
);
506 return log_link_error_errno(link
, r
, "Failed to acquire address from pool: %m");
508 log_link_error(link
, "Couldn't find free address for interface, all taken.");
512 if (original
->family
== AF_INET
) {
513 /* Pick first address in range for ourselves ... */
514 in_addr
.in
.s_addr
= in_addr
.in
.s_addr
| htobe32(1);
516 /* .. and use last as broadcast address */
517 if (original
->prefixlen
> 30)
518 broadcast
.s_addr
= 0;
520 broadcast
.s_addr
= in_addr
.in
.s_addr
| htobe32(0xFFFFFFFFUL
>> original
->prefixlen
);
521 } else if (original
->family
== AF_INET6
)
522 in_addr
.in6
.s6_addr
[15] |= 1;
524 r
= address_new(&na
);
528 na
->family
= original
->family
;
529 na
->prefixlen
= original
->prefixlen
;
530 na
->scope
= original
->scope
;
531 na
->cinfo
= original
->cinfo
;
533 if (original
->label
) {
534 na
->label
= strdup(original
->label
);
539 na
->broadcast
= broadcast
;
540 na
->in_addr
= in_addr
;
542 LIST_PREPEND(addresses
, link
->pool_addresses
, na
);
550 int address_configure(
553 sd_netlink_message_handler_t callback
,
556 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
560 assert(IN_SET(address
->family
, AF_INET
, AF_INET6
));
562 assert(link
->ifindex
> 0);
563 assert(link
->manager
);
564 assert(link
->manager
->rtnl
);
566 /* If this is a new address, then refuse adding more than the limit */
567 if (address_get(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, NULL
) <= 0 &&
568 set_size(link
->addresses
) >= ADDRESSES_PER_LINK_MAX
)
571 r
= address_acquire(link
, address
, &address
);
576 r
= sd_rtnl_message_new_addr_update(link
->manager
->rtnl
, &req
,
577 link
->ifindex
, address
->family
);
579 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_NEWADDR
,
580 link
->ifindex
, address
->family
);
582 return log_error_errno(r
, "Could not allocate RTM_NEWADDR message: %m");
584 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
586 return log_error_errno(r
, "Could not set prefixlen: %m");
588 address
->flags
|= IFA_F_PERMANENT
;
590 if (address
->home_address
)
591 address
->flags
|= IFA_F_HOMEADDRESS
;
593 if (address
->duplicate_address_detection
)
594 address
->flags
|= IFA_F_NODAD
;
596 if (address
->manage_temporary_address
)
597 address
->flags
|= IFA_F_MANAGETEMPADDR
;
599 if (address
->prefix_route
)
600 address
->flags
|= IFA_F_NOPREFIXROUTE
;
602 if (address
->autojoin
)
603 address
->flags
|= IFA_F_MCAUTOJOIN
;
605 r
= sd_rtnl_message_addr_set_flags(req
, (address
->flags
& 0xff));
607 return log_error_errno(r
, "Could not set flags: %m");
609 if (address
->flags
& ~0xff) {
610 r
= sd_netlink_message_append_u32(req
, IFA_FLAGS
, address
->flags
);
612 return log_error_errno(r
, "Could not set extended flags: %m");
615 r
= sd_rtnl_message_addr_set_scope(req
, address
->scope
);
617 return log_error_errno(r
, "Could not set scope: %m");
619 if (address
->family
== AF_INET
)
620 r
= sd_netlink_message_append_in_addr(req
, IFA_LOCAL
, &address
->in_addr
.in
);
621 else if (address
->family
== AF_INET6
)
622 r
= sd_netlink_message_append_in6_addr(req
, IFA_LOCAL
, &address
->in_addr
.in6
);
624 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
626 if (!in_addr_is_null(address
->family
, &address
->in_addr_peer
)) {
627 if (address
->family
== AF_INET
)
628 r
= sd_netlink_message_append_in_addr(req
, IFA_ADDRESS
, &address
->in_addr_peer
.in
);
629 else if (address
->family
== AF_INET6
)
630 r
= sd_netlink_message_append_in6_addr(req
, IFA_ADDRESS
, &address
->in_addr_peer
.in6
);
632 return log_error_errno(r
, "Could not append IFA_ADDRESS attribute: %m");
634 if (address
->family
== AF_INET
) {
635 if (address
->prefixlen
<= 30) {
636 r
= sd_netlink_message_append_in_addr(req
, IFA_BROADCAST
, &address
->broadcast
);
638 return log_error_errno(r
, "Could not append IFA_BROADCAST attribute: %m");
643 if (address
->label
) {
644 r
= sd_netlink_message_append_string(req
, IFA_LABEL
, address
->label
);
646 return log_error_errno(r
, "Could not append IFA_LABEL attribute: %m");
649 r
= sd_netlink_message_append_cache_info(req
, IFA_CACHEINFO
,
652 return log_error_errno(r
, "Could not append IFA_CACHEINFO attribute: %m");
654 r
= address_establish(address
, link
);
658 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
660 address_release(address
);
661 return log_error_errno(r
, "Could not send rtnetlink message: %m");
666 r
= address_add(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, NULL
);
668 address_release(address
);
669 return log_error_errno(r
, "Could not add address: %m");
675 int config_parse_broadcast(
677 const char *filename
,
680 unsigned section_line
,
687 Network
*network
= userdata
;
688 _cleanup_address_free_ Address
*n
= NULL
;
697 r
= address_new_static(network
, filename
, section_line
, &n
);
701 if (n
->family
== AF_INET6
) {
702 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue
);
706 r
= in_addr_from_string(AF_INET
, rvalue
, (union in_addr_union
*) &n
->broadcast
);
708 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Broadcast is invalid, ignoring assignment: %s", rvalue
);
718 int config_parse_address(const char *unit
,
719 const char *filename
,
722 unsigned section_line
,
729 Network
*network
= userdata
;
730 _cleanup_address_free_ Address
*n
= NULL
;
731 const char *address
, *e
;
732 union in_addr_union buffer
;
741 if (streq(section
, "Network")) {
742 /* we are not in an Address section, so treat
743 * this as the special '0' section */
744 r
= address_new_static(network
, NULL
, 0, &n
);
746 r
= address_new_static(network
, filename
, section_line
, &n
);
751 /* Address=address/prefixlen */
754 e
= strchr(rvalue
, '/');
758 r
= safe_atou(e
+ 1, &i
);
760 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix length is invalid, ignoring assignment: %s", e
+ 1);
764 n
->prefixlen
= (unsigned char) i
;
766 address
= strndupa(rvalue
, e
- rvalue
);
770 r
= in_addr_from_string_auto(address
, &f
, &buffer
);
772 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Address is invalid, ignoring assignment: %s", address
);
776 if (!e
&& f
== AF_INET
) {
777 r
= in4_addr_default_prefixlen(&buffer
.in
, &n
->prefixlen
);
779 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address
);
784 if (n
->family
!= AF_UNSPEC
&& f
!= n
->family
) {
785 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address is incompatible, ignoring assignment: %s", address
);
791 if (streq(lvalue
, "Address"))
794 n
->in_addr_peer
= buffer
;
796 if (n
->family
== AF_INET
&& n
->broadcast
.s_addr
== 0)
797 n
->broadcast
.s_addr
= n
->in_addr
.in
.s_addr
| htonl(0xfffffffflu
>> n
->prefixlen
);
804 int config_parse_label(
806 const char *filename
,
809 unsigned section_line
,
816 _cleanup_address_free_ Address
*n
= NULL
;
817 Network
*network
= userdata
;
826 r
= address_new_static(network
, filename
, section_line
, &n
);
830 if (!address_label_valid(rvalue
)) {
831 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface label is too long or invalid, ignoring assignment: %s", rvalue
);
835 r
= free_and_strdup(&n
->label
, rvalue
);
844 int config_parse_lifetime(const char *unit
,
845 const char *filename
,
848 unsigned section_line
,
854 Network
*network
= userdata
;
855 _cleanup_address_free_ Address
*n
= NULL
;
865 r
= address_new_static(network
, filename
, section_line
, &n
);
869 if (STR_IN_SET(rvalue
, "forever", "infinity")) {
870 n
->cinfo
.ifa_prefered
= CACHE_INFO_INFINITY_LIFE_TIME
;
876 r
= safe_atou(rvalue
, &k
);
878 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse PreferredLifetime, ignoring: %s", rvalue
);
883 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid PreferredLifetime value, ignoring: %d", k
);
885 n
->cinfo
.ifa_prefered
= k
;
892 int config_parse_address_flags(const char *unit
,
893 const char *filename
,
896 unsigned section_line
,
902 Network
*network
= userdata
;
903 _cleanup_address_free_ Address
*n
= NULL
;
912 r
= address_new_static(network
, filename
, section_line
, &n
);
916 r
= parse_boolean(rvalue
);
918 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address flag, ignoring: %s", rvalue
);
922 if (streq(lvalue
, "HomeAddress"))
924 else if (streq(lvalue
, "DuplicateAddressDetection"))
925 n
->duplicate_address_detection
= r
;
926 else if (streq(lvalue
, "ManageTemporaryAddress"))
927 n
->manage_temporary_address
= r
;
928 else if (streq(lvalue
, "PrefixRoute"))
930 else if (streq(lvalue
, "AutoJoin"))
936 int config_parse_address_scope(const char *unit
,
937 const char *filename
,
940 unsigned section_line
,
946 Network
*network
= userdata
;
947 _cleanup_address_free_ Address
*n
= NULL
;
956 r
= address_new_static(network
, filename
, section_line
, &n
);
960 if (streq(rvalue
, "host"))
961 n
->scope
= RT_SCOPE_HOST
;
962 else if (streq(rvalue
, "link"))
963 n
->scope
= RT_SCOPE_LINK
;
964 else if (streq(rvalue
, "global"))
965 n
->scope
= RT_SCOPE_UNIVERSE
;
967 r
= safe_atou8(rvalue
, &n
->scope
);
969 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue
);
979 bool address_is_ready(const Address
*a
) {
982 if (a
->family
== AF_INET6
)
983 return !(a
->flags
& IFA_F_TENTATIVE
);
985 return !(a
->flags
& (IFA_F_TENTATIVE
| IFA_F_DEPRECATED
));
988 int config_parse_router_preference(const char *unit
,
989 const char *filename
,
992 unsigned section_line
,
998 Network
*network
= userdata
;
1006 if (streq(rvalue
, "high"))
1007 network
->router_preference
= SD_NDISC_PREFERENCE_HIGH
;
1008 else if (STR_IN_SET(rvalue
, "medium", "normal", "default"))
1009 network
->router_preference
= SD_NDISC_PREFERENCE_MEDIUM
;
1010 else if (streq(rvalue
, "low"))
1011 network
->router_preference
= SD_NDISC_PREFERENCE_LOW
;
1013 log_syntax(unit
, LOG_ERR
, filename
, line
, -EINVAL
, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue
);
1018 void prefix_free(Prefix
*prefix
) {
1022 if (prefix
->network
) {
1023 LIST_REMOVE(prefixes
, prefix
->network
->static_prefixes
, prefix
);
1024 assert(prefix
->network
->n_static_prefixes
> 0);
1025 prefix
->network
->n_static_prefixes
--;
1027 if (prefix
->section
)
1028 hashmap_remove(prefix
->network
->prefixes_by_section
,
1032 prefix
->radv_prefix
= sd_radv_prefix_unref(prefix
->radv_prefix
);
1037 int prefix_new(Prefix
**ret
) {
1038 Prefix
*prefix
= NULL
;
1040 prefix
= new0(Prefix
, 1);
1044 if (sd_radv_prefix_new(&prefix
->radv_prefix
) < 0)
1053 int prefix_new_static(Network
*network
, const char *filename
,
1054 unsigned section_line
, Prefix
**ret
) {
1055 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
1056 _cleanup_prefix_free_ Prefix
*prefix
= NULL
;
1061 assert(!!filename
== (section_line
> 0));
1064 r
= network_config_section_new(filename
, section_line
, &n
);
1069 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
1079 r
= prefix_new(&prefix
);
1084 prefix
->section
= n
;
1087 r
= hashmap_put(network
->prefixes_by_section
, prefix
->section
,
1093 prefix
->network
= network
;
1094 LIST_APPEND(prefixes
, network
->static_prefixes
, prefix
);
1095 network
->n_static_prefixes
++;
1103 int config_parse_prefix(const char *unit
,
1104 const char *filename
,
1106 const char *section
,
1107 unsigned section_line
,
1114 Network
*network
= userdata
;
1115 _cleanup_prefix_free_ Prefix
*p
= NULL
;
1116 uint8_t prefixlen
= 64;
1117 union in_addr_union in6addr
;
1126 r
= prefix_new_static(network
, filename
, section_line
, &p
);
1130 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
1132 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
1136 if (sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
) < 0)
1137 return -EADDRNOTAVAIL
;
1139 log_syntax(unit
, LOG_INFO
, filename
, line
, r
, "Found prefix %s", rvalue
);
1146 int config_parse_prefix_flags(const char *unit
,
1147 const char *filename
,
1149 const char *section
,
1150 unsigned section_line
,
1156 Network
*network
= userdata
;
1157 _cleanup_prefix_free_ Prefix
*p
= NULL
;
1166 r
= prefix_new_static(network
, filename
, section_line
, &p
);
1170 r
= parse_boolean(rvalue
);
1172 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address flag, ignoring: %s", rvalue
);
1178 if (streq(lvalue
, "OnLink"))
1179 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, val
);
1180 else if (streq(lvalue
, "AddressAutoconfiguration"))
1181 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, val
);
1190 int config_parse_prefix_lifetime(const char *unit
,
1191 const char *filename
,
1193 const char *section
,
1194 unsigned section_line
,
1200 Network
*network
= userdata
;
1201 _cleanup_prefix_free_ Prefix
*p
= NULL
;
1211 r
= prefix_new_static(network
, filename
, section_line
, &p
);
1215 r
= parse_sec(rvalue
, &usec
);
1217 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
1221 /* a value of 0xffffffff represents infinity */
1222 if (streq(lvalue
, "PreferredLifetimeSec"))
1223 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
1224 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
1225 else if (streq(lvalue
, "ValidLifetimeSec"))
1226 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
1227 DIV_ROUND_UP(usec
, USEC_PER_SEC
));