1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "networkd-address-pool.h"
5 #include "networkd-address.h"
6 #include "networkd-manager.h"
7 #include "networkd-queue.h"
8 #include "string-util.h"
10 #define RANDOM_PREFIX_TRIAL_MAX 1024
12 static int address_pool_new(
15 const union in_addr_union
*u
,
18 _cleanup_free_ AddressPool
*p
= NULL
;
24 p
= new(AddressPool
, 1);
31 .prefixlen
= prefixlen
,
35 r
= ordered_set_ensure_put(&m
->address_pools
, NULL
, p
);
43 static int address_pool_new_from_string(
49 union in_addr_union u
;
55 r
= in_addr_from_string(family
, p
, &u
);
59 return address_pool_new(m
, family
, &u
, prefixlen
);
62 int address_pool_setup_default(Manager
*m
) {
67 /* Add in the well-known private address ranges. */
68 r
= address_pool_new_from_string(m
, AF_INET6
, "fd00::", 8);
72 r
= address_pool_new_from_string(m
, AF_INET
, "192.168.0.0", 16);
76 r
= address_pool_new_from_string(m
, AF_INET
, "172.16.0.0", 12);
80 r
= address_pool_new_from_string(m
, AF_INET
, "10.0.0.0", 8);
87 static bool address_intersect(
90 const union in_addr_union
*u
,
96 if (a
->family
!= family
)
99 return in_addr_prefix_intersect(family
, u
, prefixlen
, &a
->in_addr
, a
->prefixlen
);
102 static bool address_pool_prefix_is_taken(
104 const union in_addr_union
*u
,
105 unsigned prefixlen
) {
115 /* Don't clash with assigned addresses. */
116 HASHMAP_FOREACH(l
, p
->manager
->links_by_index
)
117 SET_FOREACH(a
, l
->addresses
)
118 if (address_intersect(a
, p
->family
, u
, prefixlen
))
121 /* And don't clash with configured but un-assigned addresses either. */
122 ORDERED_HASHMAP_FOREACH(n
, p
->manager
->networks
)
123 ORDERED_HASHMAP_FOREACH(a
, n
->addresses_by_section
)
124 if (address_intersect(a
, p
->family
, u
, prefixlen
))
127 /* Also check queued addresses. */
128 ORDERED_SET_FOREACH(req
, p
->manager
->request_queue
) {
129 if (req
->type
!= REQUEST_TYPE_ADDRESS
)
132 if (address_intersect(req
->userdata
, p
->family
, u
, prefixlen
))
139 static int address_pool_acquire_one(AddressPool
*p
, int family
, unsigned prefixlen
, union in_addr_union
*found
) {
140 union in_addr_union u
;
144 assert(prefixlen
> 0);
147 if (p
->family
!= family
)
150 if (p
->prefixlen
>= prefixlen
)
155 for (unsigned i
= 0; i
< RANDOM_PREFIX_TRIAL_MAX
; i
++) {
156 r
= in_addr_random_prefix(p
->family
, &u
, p
->prefixlen
, prefixlen
);
160 if (!address_pool_prefix_is_taken(p
, &u
, prefixlen
)) {
161 log_debug("Found range %s", IN_ADDR_PREFIX_TO_STRING(p
->family
, &u
, prefixlen
));
171 int address_pool_acquire(Manager
*m
, int family
, unsigned prefixlen
, union in_addr_union
*found
) {
176 assert(IN_SET(family
, AF_INET
, AF_INET6
));
177 assert(prefixlen
> 0);
180 ORDERED_SET_FOREACH(p
, m
->address_pools
) {
181 r
= address_pool_acquire_one(p
, family
, prefixlen
, found
);