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 broadcast
.s_addr
= in_addr
.in
.s_addr
| htobe32(0xFFFFFFFFUL
>> original
->prefixlen
);
518 } else if (original
->family
== AF_INET6
)
519 in_addr
.in6
.s6_addr
[15] |= 1;
521 r
= address_new(&na
);
525 na
->family
= original
->family
;
526 na
->prefixlen
= original
->prefixlen
;
527 na
->scope
= original
->scope
;
528 na
->cinfo
= original
->cinfo
;
530 if (original
->label
) {
531 na
->label
= strdup(original
->label
);
536 na
->broadcast
= broadcast
;
537 na
->in_addr
= in_addr
;
539 LIST_PREPEND(addresses
, link
->pool_addresses
, na
);
547 int address_configure(
550 sd_netlink_message_handler_t callback
,
553 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
557 assert(IN_SET(address
->family
, AF_INET
, AF_INET6
));
559 assert(link
->ifindex
> 0);
560 assert(link
->manager
);
561 assert(link
->manager
->rtnl
);
563 /* If this is a new address, then refuse adding more than the limit */
564 if (address_get(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, NULL
) <= 0 &&
565 set_size(link
->addresses
) >= ADDRESSES_PER_LINK_MAX
)
568 r
= address_acquire(link
, address
, &address
);
573 r
= sd_rtnl_message_new_addr_update(link
->manager
->rtnl
, &req
,
574 link
->ifindex
, address
->family
);
576 r
= sd_rtnl_message_new_addr(link
->manager
->rtnl
, &req
, RTM_NEWADDR
,
577 link
->ifindex
, address
->family
);
579 return log_error_errno(r
, "Could not allocate RTM_NEWADDR message: %m");
581 r
= sd_rtnl_message_addr_set_prefixlen(req
, address
->prefixlen
);
583 return log_error_errno(r
, "Could not set prefixlen: %m");
585 address
->flags
|= IFA_F_PERMANENT
;
587 if (address
->home_address
)
588 address
->flags
|= IFA_F_HOMEADDRESS
;
590 if (address
->duplicate_address_detection
)
591 address
->flags
|= IFA_F_NODAD
;
593 if (address
->manage_temporary_address
)
594 address
->flags
|= IFA_F_MANAGETEMPADDR
;
596 if (address
->prefix_route
)
597 address
->flags
|= IFA_F_NOPREFIXROUTE
;
599 if (address
->autojoin
)
600 address
->flags
|= IFA_F_MCAUTOJOIN
;
602 r
= sd_rtnl_message_addr_set_flags(req
, (address
->flags
& 0xff));
604 return log_error_errno(r
, "Could not set flags: %m");
606 if (address
->flags
& ~0xff) {
607 r
= sd_netlink_message_append_u32(req
, IFA_FLAGS
, address
->flags
);
609 return log_error_errno(r
, "Could not set extended flags: %m");
612 r
= sd_rtnl_message_addr_set_scope(req
, address
->scope
);
614 return log_error_errno(r
, "Could not set scope: %m");
616 if (address
->family
== AF_INET
)
617 r
= sd_netlink_message_append_in_addr(req
, IFA_LOCAL
, &address
->in_addr
.in
);
618 else if (address
->family
== AF_INET6
)
619 r
= sd_netlink_message_append_in6_addr(req
, IFA_LOCAL
, &address
->in_addr
.in6
);
621 return log_error_errno(r
, "Could not append IFA_LOCAL attribute: %m");
623 if (!in_addr_is_null(address
->family
, &address
->in_addr_peer
)) {
624 if (address
->family
== AF_INET
)
625 r
= sd_netlink_message_append_in_addr(req
, IFA_ADDRESS
, &address
->in_addr_peer
.in
);
626 else if (address
->family
== AF_INET6
)
627 r
= sd_netlink_message_append_in6_addr(req
, IFA_ADDRESS
, &address
->in_addr_peer
.in6
);
629 return log_error_errno(r
, "Could not append IFA_ADDRESS attribute: %m");
631 if (address
->family
== AF_INET
) {
632 r
= sd_netlink_message_append_in_addr(req
, IFA_BROADCAST
, &address
->broadcast
);
634 return log_error_errno(r
, "Could not append IFA_BROADCAST attribute: %m");
638 if (address
->label
) {
639 r
= sd_netlink_message_append_string(req
, IFA_LABEL
, address
->label
);
641 return log_error_errno(r
, "Could not append IFA_LABEL attribute: %m");
644 r
= sd_netlink_message_append_cache_info(req
, IFA_CACHEINFO
,
647 return log_error_errno(r
, "Could not append IFA_CACHEINFO attribute: %m");
649 r
= address_establish(address
, link
);
653 r
= sd_netlink_call_async(link
->manager
->rtnl
, req
, callback
, link
, 0, NULL
);
655 address_release(address
);
656 return log_error_errno(r
, "Could not send rtnetlink message: %m");
661 r
= address_add(link
, address
->family
, &address
->in_addr
, address
->prefixlen
, NULL
);
663 address_release(address
);
664 return log_error_errno(r
, "Could not add address: %m");
670 int config_parse_broadcast(
672 const char *filename
,
675 unsigned section_line
,
682 Network
*network
= userdata
;
683 _cleanup_address_free_ Address
*n
= NULL
;
692 r
= address_new_static(network
, filename
, section_line
, &n
);
696 if (n
->family
== AF_INET6
) {
697 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue
);
701 r
= in_addr_from_string(AF_INET
, rvalue
, (union in_addr_union
*) &n
->broadcast
);
703 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Broadcast is invalid, ignoring assignment: %s", rvalue
);
713 int config_parse_address(const char *unit
,
714 const char *filename
,
717 unsigned section_line
,
724 Network
*network
= userdata
;
725 _cleanup_address_free_ Address
*n
= NULL
;
726 const char *address
, *e
;
727 union in_addr_union buffer
;
736 if (streq(section
, "Network")) {
737 /* we are not in an Address section, so treat
738 * this as the special '0' section */
739 r
= address_new_static(network
, NULL
, 0, &n
);
741 r
= address_new_static(network
, filename
, section_line
, &n
);
746 /* Address=address/prefixlen */
749 e
= strchr(rvalue
, '/');
753 r
= safe_atou(e
+ 1, &i
);
755 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix length is invalid, ignoring assignment: %s", e
+ 1);
759 n
->prefixlen
= (unsigned char) i
;
761 address
= strndupa(rvalue
, e
- rvalue
);
765 r
= in_addr_from_string_auto(address
, &f
, &buffer
);
767 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Address is invalid, ignoring assignment: %s", address
);
771 if (!e
&& f
== AF_INET
) {
772 r
= in4_addr_default_prefixlen(&buffer
.in
, &n
->prefixlen
);
774 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
);
779 if (n
->family
!= AF_UNSPEC
&& f
!= n
->family
) {
780 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Address is incompatible, ignoring assignment: %s", address
);
786 if (streq(lvalue
, "Address"))
789 n
->in_addr_peer
= buffer
;
791 if (n
->family
== AF_INET
&& n
->broadcast
.s_addr
== 0)
792 n
->broadcast
.s_addr
= n
->in_addr
.in
.s_addr
| htonl(0xfffffffflu
>> n
->prefixlen
);
799 int config_parse_label(
801 const char *filename
,
804 unsigned section_line
,
811 _cleanup_address_free_ Address
*n
= NULL
;
812 Network
*network
= userdata
;
821 r
= address_new_static(network
, filename
, section_line
, &n
);
825 if (!address_label_valid(rvalue
)) {
826 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Interface label is too long or invalid, ignoring assignment: %s", rvalue
);
830 r
= free_and_strdup(&n
->label
, rvalue
);
839 int config_parse_lifetime(const char *unit
,
840 const char *filename
,
843 unsigned section_line
,
849 Network
*network
= userdata
;
850 _cleanup_address_free_ Address
*n
= NULL
;
860 r
= address_new_static(network
, filename
, section_line
, &n
);
864 if (STR_IN_SET(rvalue
, "forever", "infinity")) {
865 n
->cinfo
.ifa_prefered
= CACHE_INFO_INFINITY_LIFE_TIME
;
871 r
= safe_atou(rvalue
, &k
);
873 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse PreferredLifetime, ignoring: %s", rvalue
);
878 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid PreferredLifetime value, ignoring: %d", k
);
880 n
->cinfo
.ifa_prefered
= k
;
887 int config_parse_address_flags(const char *unit
,
888 const char *filename
,
891 unsigned section_line
,
897 Network
*network
= userdata
;
898 _cleanup_address_free_ Address
*n
= NULL
;
907 r
= address_new_static(network
, filename
, section_line
, &n
);
911 r
= parse_boolean(rvalue
);
913 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address flag, ignoring: %s", rvalue
);
917 if (streq(lvalue
, "HomeAddress"))
919 else if (streq(lvalue
, "DuplicateAddressDetection"))
920 n
->duplicate_address_detection
= r
;
921 else if (streq(lvalue
, "ManageTemporaryAddress"))
922 n
->manage_temporary_address
= r
;
923 else if (streq(lvalue
, "PrefixRoute"))
925 else if (streq(lvalue
, "AutoJoin"))
931 int config_parse_address_scope(const char *unit
,
932 const char *filename
,
935 unsigned section_line
,
941 Network
*network
= userdata
;
942 _cleanup_address_free_ Address
*n
= NULL
;
951 r
= address_new_static(network
, filename
, section_line
, &n
);
955 if (streq(rvalue
, "host"))
956 n
->scope
= RT_SCOPE_HOST
;
957 else if (streq(rvalue
, "link"))
958 n
->scope
= RT_SCOPE_LINK
;
959 else if (streq(rvalue
, "global"))
960 n
->scope
= RT_SCOPE_UNIVERSE
;
962 r
= safe_atou8(rvalue
, &n
->scope
);
964 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue
);
974 bool address_is_ready(const Address
*a
) {
977 return !(a
->flags
& (IFA_F_TENTATIVE
| IFA_F_DEPRECATED
));
980 int config_parse_router_preference(const char *unit
,
981 const char *filename
,
984 unsigned section_line
,
990 Network
*network
= userdata
;
998 if (streq(rvalue
, "high"))
999 network
->router_preference
= SD_NDISC_PREFERENCE_HIGH
;
1000 else if (STR_IN_SET(rvalue
, "medium", "normal", "default"))
1001 network
->router_preference
= SD_NDISC_PREFERENCE_MEDIUM
;
1002 else if (streq(rvalue
, "low"))
1003 network
->router_preference
= SD_NDISC_PREFERENCE_LOW
;
1005 log_syntax(unit
, LOG_ERR
, filename
, line
, -EINVAL
, "Router preference '%s' is invalid, ignoring assignment: %m", rvalue
);
1010 void prefix_free(Prefix
*prefix
) {
1014 if (prefix
->network
) {
1015 LIST_REMOVE(prefixes
, prefix
->network
->static_prefixes
, prefix
);
1016 assert(prefix
->network
->n_static_prefixes
> 0);
1017 prefix
->network
->n_static_prefixes
--;
1019 if (prefix
->section
)
1020 hashmap_remove(prefix
->network
->prefixes_by_section
,
1024 prefix
->radv_prefix
= sd_radv_prefix_unref(prefix
->radv_prefix
);
1029 int prefix_new(Prefix
**ret
) {
1030 Prefix
*prefix
= NULL
;
1032 prefix
= new0(Prefix
, 1);
1036 if (sd_radv_prefix_new(&prefix
->radv_prefix
) < 0)
1045 int prefix_new_static(Network
*network
, const char *filename
,
1046 unsigned section_line
, Prefix
**ret
) {
1047 _cleanup_network_config_section_free_ NetworkConfigSection
*n
= NULL
;
1048 _cleanup_prefix_free_ Prefix
*prefix
= NULL
;
1053 assert(!!filename
== (section_line
> 0));
1056 r
= network_config_section_new(filename
, section_line
, &n
);
1061 prefix
= hashmap_get(network
->prefixes_by_section
, n
);
1071 r
= prefix_new(&prefix
);
1076 prefix
->section
= n
;
1079 r
= hashmap_put(network
->prefixes_by_section
, prefix
->section
,
1085 prefix
->network
= network
;
1086 LIST_APPEND(prefixes
, network
->static_prefixes
, prefix
);
1087 network
->n_static_prefixes
++;
1095 int config_parse_prefix(const char *unit
,
1096 const char *filename
,
1098 const char *section
,
1099 unsigned section_line
,
1106 Network
*network
= userdata
;
1107 _cleanup_prefix_free_ Prefix
*p
= NULL
;
1108 uint8_t prefixlen
= 64;
1109 union in_addr_union in6addr
;
1118 r
= prefix_new_static(network
, filename
, section_line
, &p
);
1122 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &in6addr
, &prefixlen
);
1124 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Prefix is invalid, ignoring assignment: %s", rvalue
);
1128 if (sd_radv_prefix_set_prefix(p
->radv_prefix
, &in6addr
.in6
, prefixlen
) < 0)
1129 return -EADDRNOTAVAIL
;
1131 log_syntax(unit
, LOG_INFO
, filename
, line
, r
, "Found prefix %s", rvalue
);
1138 int config_parse_prefix_flags(const char *unit
,
1139 const char *filename
,
1141 const char *section
,
1142 unsigned section_line
,
1148 Network
*network
= userdata
;
1149 _cleanup_prefix_free_ Prefix
*p
= NULL
;
1158 r
= prefix_new_static(network
, filename
, section_line
, &p
);
1162 r
= parse_boolean(rvalue
);
1164 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse address flag, ignoring: %s", rvalue
);
1170 if (streq(lvalue
, "OnLink"))
1171 r
= sd_radv_prefix_set_onlink(p
->radv_prefix
, val
);
1172 else if (streq(lvalue
, "AddressAutoconfiguration"))
1173 r
= sd_radv_prefix_set_address_autoconfiguration(p
->radv_prefix
, val
);
1182 int config_parse_prefix_lifetime(const char *unit
,
1183 const char *filename
,
1185 const char *section
,
1186 unsigned section_line
,
1192 Network
*network
= userdata
;
1193 _cleanup_prefix_free_ Prefix
*p
= NULL
;
1203 r
= prefix_new_static(network
, filename
, section_line
, &p
);
1207 r
= parse_sec(rvalue
, &usec
);
1209 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Lifetime is invalid, ignoring assignment: %s", rvalue
);
1213 /* a value of 0xffffffff represents infinity */
1214 if (streq(lvalue
, "PreferredLifetimeSec"))
1215 r
= sd_radv_prefix_set_preferred_lifetime(p
->radv_prefix
,
1216 DIV_ROUND_UP(usec
, USEC_PER_SEC
));
1217 else if (streq(lvalue
, "ValidLifetimeSec"))
1218 r
= sd_radv_prefix_set_valid_lifetime(p
->radv_prefix
,
1219 DIV_ROUND_UP(usec
, USEC_PER_SEC
));