1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "networkd-address.h"
5 #include "networkd-address-pool.h"
6 #include "networkd-link.h"
7 #include "networkd-manager.h"
8 #include "networkd-queue.h"
9 #include "ordered-set.h"
12 #define RANDOM_PREFIX_TRIAL_MAX 1024
14 static int address_pool_new(
17 const union in_addr_union
*u
,
20 _cleanup_free_ AddressPool
*p
= NULL
;
26 p
= new(AddressPool
, 1);
33 .prefixlen
= prefixlen
,
37 r
= ordered_set_ensure_put(&m
->address_pools
, &trivial_hash_ops_free
, p
);
45 static int address_pool_new_from_string(
51 union in_addr_union u
;
57 r
= in_addr_from_string(family
, p
, &u
);
61 return address_pool_new(m
, family
, &u
, prefixlen
);
64 int address_pool_setup_default(Manager
*m
) {
69 /* Add in the well-known private address ranges. */
70 r
= address_pool_new_from_string(m
, AF_INET6
, "fd00::", 8);
74 r
= address_pool_new_from_string(m
, AF_INET
, "192.168.0.0", 16);
78 r
= address_pool_new_from_string(m
, AF_INET
, "172.16.0.0", 12);
82 r
= address_pool_new_from_string(m
, AF_INET
, "10.0.0.0", 8);
89 static bool address_intersect(
92 const union in_addr_union
*u
,
98 if (a
->family
!= family
)
101 return in_addr_prefix_intersect(family
, u
, prefixlen
, &a
->in_addr
, a
->prefixlen
);
104 static bool address_pool_prefix_is_taken(
106 const union in_addr_union
*u
,
107 unsigned prefixlen
) {
117 /* Don't clash with assigned addresses. */
118 HASHMAP_FOREACH(l
, p
->manager
->links_by_index
)
119 SET_FOREACH(a
, l
->addresses
)
120 if (address_intersect(a
, p
->family
, u
, prefixlen
))
123 /* And don't clash with configured but un-assigned addresses either. */
124 ORDERED_HASHMAP_FOREACH(n
, p
->manager
->networks
)
125 ORDERED_HASHMAP_FOREACH(a
, n
->addresses_by_section
)
126 if (address_intersect(a
, p
->family
, u
, prefixlen
))
129 /* Also check queued addresses. */
130 ORDERED_SET_FOREACH(req
, p
->manager
->request_queue
) {
131 if (req
->type
!= REQUEST_TYPE_ADDRESS
)
134 if (address_intersect(req
->userdata
, p
->family
, u
, prefixlen
))
141 static int address_pool_acquire_one(AddressPool
*p
, int family
, unsigned prefixlen
, union in_addr_union
*found
) {
142 union in_addr_union u
;
146 assert(prefixlen
> 0);
149 if (p
->family
!= family
)
152 if (p
->prefixlen
>= prefixlen
)
157 for (unsigned i
= 0; i
< RANDOM_PREFIX_TRIAL_MAX
; i
++) {
158 r
= in_addr_random_prefix(p
->family
, &u
, p
->prefixlen
, prefixlen
);
162 if (!address_pool_prefix_is_taken(p
, &u
, prefixlen
)) {
163 log_debug("Found range %s", IN_ADDR_PREFIX_TO_STRING(p
->family
, &u
, prefixlen
));
173 int address_pool_acquire(Manager
*m
, int family
, unsigned prefixlen
, union in_addr_union
*found
) {
178 assert(IN_SET(family
, AF_INET
, AF_INET6
));
179 assert(prefixlen
> 0);
182 ORDERED_SET_FOREACH(p
, m
->address_pools
) {
183 r
= address_pool_acquire_one(p
, family
, prefixlen
, found
);