]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address-pool.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / network / networkd-address-pool.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
11bf3cce 2
b5efdb8a 3#include "alloc-util.h"
093e3533 4#include "networkd-address.h"
1cf40697 5#include "networkd-address-pool.h"
0ee78fc9 6#include "networkd-link.h"
23f53b99 7#include "networkd-manager.h"
826a46fc 8#include "networkd-queue.h"
baa3fadf
DDM
9#include "ordered-set.h"
10#include "set.h"
11bf3cce 11
304e7e9d
YW
12#define RANDOM_PREFIX_TRIAL_MAX 1024
13
198afaab 14static int address_pool_new(
11bf3cce 15 Manager *m,
0dd25fb9 16 int family,
11bf3cce
LP
17 const union in_addr_union *u,
18 unsigned prefixlen) {
19
bfbf150e
YW
20 _cleanup_free_ AddressPool *p = NULL;
21 int r;
11bf3cce
LP
22
23 assert(m);
11bf3cce
LP
24 assert(u);
25
17f9c355 26 p = new(AddressPool, 1);
11bf3cce
LP
27 if (!p)
28 return -ENOMEM;
29
17f9c355
YW
30 *p = (AddressPool) {
31 .manager = m,
32 .family = family,
33 .prefixlen = prefixlen,
34 .in_addr = *u,
35 };
11bf3cce 36
04b7949e 37 r = ordered_set_ensure_put(&m->address_pools, &trivial_hash_ops_free, p);
bfbf150e
YW
38 if (r < 0)
39 return r;
11bf3cce 40
bfbf150e 41 TAKE_PTR(p);
11bf3cce
LP
42 return 0;
43}
44
ed76f585 45static int address_pool_new_from_string(
11bf3cce 46 Manager *m,
0dd25fb9 47 int family,
11bf3cce
LP
48 const char *p,
49 unsigned prefixlen) {
50
51 union in_addr_union u;
52 int r;
53
54 assert(m);
11bf3cce
LP
55 assert(p);
56
57 r = in_addr_from_string(family, p, &u);
58 if (r < 0)
59 return r;
60
3fe721c6 61 return address_pool_new(m, family, &u, prefixlen);
11bf3cce
LP
62}
63
ed76f585 64int address_pool_setup_default(Manager *m) {
ed76f585
YW
65 int r;
66
67 assert(m);
68
69 /* Add in the well-known private address ranges. */
3fe721c6 70 r = address_pool_new_from_string(m, AF_INET6, "fd00::", 8);
ed76f585
YW
71 if (r < 0)
72 return r;
73
bfbf150e 74 r = address_pool_new_from_string(m, AF_INET, "192.168.0.0", 16);
ed76f585
YW
75 if (r < 0)
76 return r;
77
3fe721c6 78 r = address_pool_new_from_string(m, AF_INET, "172.16.0.0", 12);
ed76f585
YW
79 if (r < 0)
80 return r;
81
bfbf150e 82 r = address_pool_new_from_string(m, AF_INET, "10.0.0.0", 8);
ed76f585
YW
83 if (r < 0)
84 return r;
85
86 return 0;
87}
88
4212d6a1
YW
89static bool address_intersect(
90 const Address *a,
91 int family,
92 const union in_addr_union *u,
93 unsigned prefixlen) {
94
95 assert(a);
96 assert(u);
97
98 if (a->family != family)
99 return false;
100
101 return in_addr_prefix_intersect(family, u, prefixlen, &a->in_addr, a->prefixlen);
102}
103
11bf3cce
LP
104static bool address_pool_prefix_is_taken(
105 AddressPool *p,
106 const union in_addr_union *u,
107 unsigned prefixlen) {
108
4212d6a1 109 Address *a;
11bf3cce
LP
110 Link *l;
111 Network *n;
826a46fc 112 Request *req;
11bf3cce
LP
113
114 assert(p);
115 assert(u);
116
4212d6a1
YW
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))
11bf3cce 121 return true;
11bf3cce 122
4212d6a1
YW
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))
11bf3cce 127 return true;
11bf3cce 128
826a46fc
YW
129 /* Also check queued addresses. */
130 ORDERED_SET_FOREACH(req, p->manager->request_queue) {
131 if (req->type != REQUEST_TYPE_ADDRESS)
132 continue;
133
134 if (address_intersect(req->userdata, p->family, u, prefixlen))
135 return true;
136 }
137
11bf3cce
LP
138 return false;
139}
140
ed76f585 141static int address_pool_acquire_one(AddressPool *p, int family, unsigned prefixlen, union in_addr_union *found) {
11bf3cce 142 union in_addr_union u;
304e7e9d 143 int r;
11bf3cce
LP
144
145 assert(p);
146 assert(prefixlen > 0);
147 assert(found);
148
ed76f585
YW
149 if (p->family != family)
150 return 0;
151
304e7e9d 152 if (p->prefixlen >= prefixlen)
11bf3cce
LP
153 return 0;
154
155 u = p->in_addr;
0229100b 156
cda7fc8d 157 for (unsigned i = 0; i < RANDOM_PREFIX_TRIAL_MAX; i++) {
304e7e9d
YW
158 r = in_addr_random_prefix(p->family, &u, p->prefixlen, prefixlen);
159 if (r <= 0)
160 return r;
11bf3cce 161
304e7e9d 162 if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
c71384a9 163 log_debug("Found range %s", IN_ADDR_PREFIX_TO_STRING(p->family, &u, prefixlen));
11bf3cce
LP
164
165 *found = u;
166 return 1;
167 }
11bf3cce
LP
168 }
169
170 return 0;
171}
ed76f585
YW
172
173int address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
174 AddressPool *p;
175 int r;
176
177 assert(m);
178 assert(IN_SET(family, AF_INET, AF_INET6));
179 assert(prefixlen > 0);
180 assert(found);
181
bfbf150e 182 ORDERED_SET_FOREACH(p, m->address_pools) {
ed76f585
YW
183 r = address_pool_acquire_one(p, family, prefixlen, found);
184 if (r != 0)
185 return r;
186 }
187
188 return 0;
189}