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