Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include "alloc-util.h"
4 : #include "networkd-address-pool.h"
5 : #include "networkd-manager.h"
6 : #include "set.h"
7 : #include "string-util.h"
8 :
9 : #define RANDOM_PREFIX_TRIAL_MAX 1024
10 :
11 4 : static int address_pool_new(
12 : Manager *m,
13 : AddressPool **ret,
14 : int family,
15 : const union in_addr_union *u,
16 : unsigned prefixlen) {
17 :
18 : AddressPool *p;
19 :
20 4 : assert(m);
21 4 : assert(ret);
22 4 : assert(u);
23 :
24 4 : p = new(AddressPool, 1);
25 4 : if (!p)
26 0 : return -ENOMEM;
27 :
28 4 : *p = (AddressPool) {
29 : .manager = m,
30 : .family = family,
31 : .prefixlen = prefixlen,
32 4 : .in_addr = *u,
33 : };
34 :
35 4 : LIST_PREPEND(address_pools, m->address_pools, p);
36 :
37 4 : *ret = p;
38 4 : return 0;
39 : }
40 :
41 4 : int address_pool_new_from_string(
42 : Manager *m,
43 : AddressPool **ret,
44 : int family,
45 : const char *p,
46 : unsigned prefixlen) {
47 :
48 : union in_addr_union u;
49 : int r;
50 :
51 4 : assert(m);
52 4 : assert(ret);
53 4 : assert(p);
54 :
55 4 : r = in_addr_from_string(family, p, &u);
56 4 : if (r < 0)
57 0 : return r;
58 :
59 4 : return address_pool_new(m, ret, family, &u, prefixlen);
60 : }
61 :
62 4 : void address_pool_free(AddressPool *p) {
63 :
64 4 : if (!p)
65 0 : return;
66 :
67 4 : if (p->manager)
68 4 : LIST_REMOVE(address_pools, p->manager->address_pools, p);
69 :
70 4 : free(p);
71 : }
72 :
73 0 : static 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 0 : assert(p);
83 0 : assert(u);
84 :
85 0 : HASHMAP_FOREACH(l, p->manager->links, i) {
86 : Address *a;
87 : Iterator j;
88 :
89 : /* Don't clash with assigned addresses */
90 0 : SET_FOREACH(a, l->addresses, j) {
91 0 : if (a->family != p->family)
92 0 : continue;
93 :
94 0 : if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
95 0 : return true;
96 : }
97 :
98 : /* Don't clash with addresses already pulled from the pool, but not assigned yet */
99 0 : LIST_FOREACH(addresses, a, l->pool_addresses) {
100 0 : if (a->family != p->family)
101 0 : continue;
102 :
103 0 : if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
104 0 : return true;
105 : }
106 : }
107 :
108 : /* And don't clash with configured but un-assigned addresses either */
109 0 : ORDERED_HASHMAP_FOREACH(n, p->manager->networks, i) {
110 : Address *a;
111 :
112 0 : LIST_FOREACH(addresses, a, n->static_addresses) {
113 0 : if (a->family != p->family)
114 0 : continue;
115 :
116 0 : if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
117 0 : return true;
118 : }
119 : }
120 :
121 0 : return false;
122 : }
123 :
124 0 : int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found) {
125 : union in_addr_union u;
126 : unsigned i;
127 : int r;
128 :
129 0 : assert(p);
130 0 : assert(prefixlen > 0);
131 0 : assert(found);
132 :
133 0 : if (p->prefixlen >= prefixlen)
134 0 : return 0;
135 :
136 0 : u = p->in_addr;
137 :
138 0 : for (i = 0; i < RANDOM_PREFIX_TRIAL_MAX; i++) {
139 0 : r = in_addr_random_prefix(p->family, &u, p->prefixlen, prefixlen);
140 0 : if (r <= 0)
141 0 : return r;
142 :
143 0 : if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
144 0 : if (DEBUG_LOGGING) {
145 0 : _cleanup_free_ char *s = NULL;
146 :
147 0 : (void) in_addr_to_string(p->family, &u, &s);
148 0 : log_debug("Found range %s/%u", strna(s), prefixlen);
149 : }
150 :
151 0 : *found = u;
152 0 : return 1;
153 : }
154 : }
155 :
156 0 : return 0;
157 : }
|