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