]>
Commit | Line | Data |
---|---|---|
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 | 12 | static 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 | 43 | static 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 | 62 | int 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 |
87 | static 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 |
102 | static 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 | 139 | static 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 | |
171 | int 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 | } |