Branch data 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 : 16 : 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 [ - + ]: 16 : assert(m);
21 [ - + ]: 16 : assert(ret);
22 [ - + ]: 16 : assert(u);
23 : :
24 : 16 : p = new(AddressPool, 1);
25 [ - + ]: 16 : if (!p)
26 : 0 : return -ENOMEM;
27 : :
28 : 16 : *p = (AddressPool) {
29 : : .manager = m,
30 : : .family = family,
31 : : .prefixlen = prefixlen,
32 : 16 : .in_addr = *u,
33 : : };
34 : :
35 [ - + + + ]: 16 : LIST_PREPEND(address_pools, m->address_pools, p);
36 : :
37 : 16 : *ret = p;
38 : 16 : return 0;
39 : : }
40 : :
41 : 16 : 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 [ - + ]: 16 : assert(m);
52 [ - + ]: 16 : assert(ret);
53 [ - + ]: 16 : assert(p);
54 : :
55 : 16 : r = in_addr_from_string(family, p, &u);
56 [ - + ]: 16 : if (r < 0)
57 : 0 : return r;
58 : :
59 : 16 : return address_pool_new(m, ret, family, &u, prefixlen);
60 : : }
61 : :
62 : 16 : void address_pool_free(AddressPool *p) {
63 : :
64 [ - + ]: 16 : if (!p)
65 : 0 : return;
66 : :
67 [ + - ]: 16 : if (p->manager)
68 [ - + + + : 16 : LIST_REMOVE(address_pools, p->manager->address_pools, p);
- + - + ]
69 : :
70 : 16 : 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 : : }
|