]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address-pool.c
network: rename settings about DHCPv6 Prefix Delegation
[thirdparty/systemd.git] / src / network / networkd-address-pool.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
11bf3cce 2
b5efdb8a 3#include "alloc-util.h"
fc2f9534 4#include "networkd-address-pool.h"
23f53b99 5#include "networkd-manager.h"
cf1d700d 6#include "set.h"
07630cea 7#include "string-util.h"
11bf3cce 8
304e7e9d
YW
9#define RANDOM_PREFIX_TRIAL_MAX 1024
10
198afaab 11static int address_pool_new(
11bf3cce
LP
12 Manager *m,
13 AddressPool **ret,
0dd25fb9 14 int family,
11bf3cce
LP
15 const union in_addr_union *u,
16 unsigned prefixlen) {
17
18 AddressPool *p;
19
20 assert(m);
21 assert(ret);
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
LP
34
35 LIST_PREPEND(address_pools, m->address_pools, p);
36
37 *ret = p;
38 return 0;
39}
40
41int address_pool_new_from_string(
42 Manager *m,
43 AddressPool **ret,
0dd25fb9 44 int family,
11bf3cce
LP
45 const char *p,
46 unsigned prefixlen) {
47
48 union in_addr_union u;
49 int r;
50
51 assert(m);
52 assert(ret);
53 assert(p);
54
55 r = in_addr_from_string(family, p, &u);
56 if (r < 0)
57 return r;
58
59 return address_pool_new(m, ret, family, &u, prefixlen);
60}
61
62void address_pool_free(AddressPool *p) {
63
64 if (!p)
65 return;
66
67 if (p->manager)
68 LIST_REMOVE(address_pools, p->manager->address_pools, p);
69
70 free(p);
71}
72
73static bool address_pool_prefix_is_taken(
74 AddressPool *p,
75 const union in_addr_union *u,
76 unsigned prefixlen) {
77
78 Iterator i;
79 Link *l;
80 Network *n;
81
82 assert(p);
83 assert(u);
84
85 HASHMAP_FOREACH(l, p->manager->links, i) {
86 Address *a;
cf1d700d 87 Iterator j;
11bf3cce
LP
88
89 /* Don't clash with assigned addresses */
cf1d700d 90 SET_FOREACH(a, l->addresses, j) {
11bf3cce
LP
91 if (a->family != p->family)
92 continue;
93
94 if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
95 return true;
96 }
97
98 /* Don't clash with addresses already pulled from the pool, but not assigned yet */
99 LIST_FOREACH(addresses, a, l->pool_addresses) {
100 if (a->family != p->family)
101 continue;
102
103 if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
104 return true;
105 }
106 }
107
108 /* And don't clash with configured but un-assigned addresses either */
715d398e 109 ORDERED_HASHMAP_FOREACH(n, p->manager->networks, i) {
11bf3cce
LP
110 Address *a;
111
112 LIST_FOREACH(addresses, a, n->static_addresses) {
113 if (a->family != p->family)
114 continue;
115
116 if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
117 return true;
118 }
119 }
120
121 return false;
122}
123
124int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found) {
125 union in_addr_union u;
304e7e9d
YW
126 unsigned i;
127 int r;
11bf3cce
LP
128
129 assert(p);
130 assert(prefixlen > 0);
131 assert(found);
132
304e7e9d 133 if (p->prefixlen >= prefixlen)
11bf3cce
LP
134 return 0;
135
136 u = p->in_addr;
0229100b 137
304e7e9d
YW
138 for (i = 0; i < RANDOM_PREFIX_TRIAL_MAX; i++) {
139 r = in_addr_random_prefix(p->family, &u, p->prefixlen, prefixlen);
140 if (r <= 0)
141 return r;
11bf3cce 142
304e7e9d
YW
143 if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
144 if (DEBUG_LOGGING) {
145 _cleanup_free_ char *s = NULL;
146
147 (void) in_addr_to_string(p->family, &u, &s);
148 log_debug("Found range %s/%u", strna(s), prefixlen);
149 }
11bf3cce
LP
150
151 *found = u;
152 return 1;
153 }
11bf3cce
LP
154 }
155
156 return 0;
157}