]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address-pool.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / network / networkd-address-pool.c
CommitLineData
11bf3cce
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
fc2f9534 22#include "networkd-address-pool.h"
07630cea 23#include "networkd.h"
cf1d700d 24#include "set.h"
07630cea 25#include "string-util.h"
11bf3cce
LP
26
27int address_pool_new(
28 Manager *m,
29 AddressPool **ret,
0dd25fb9 30 int family,
11bf3cce
LP
31 const union in_addr_union *u,
32 unsigned prefixlen) {
33
34 AddressPool *p;
35
36 assert(m);
37 assert(ret);
38 assert(u);
39
40 p = new0(AddressPool, 1);
41 if (!p)
42 return -ENOMEM;
43
44 p->manager = m;
45 p->family = family;
46 p->prefixlen = prefixlen;
47 p->in_addr = *u;
48
49 LIST_PREPEND(address_pools, m->address_pools, p);
50
51 *ret = p;
52 return 0;
53}
54
55int address_pool_new_from_string(
56 Manager *m,
57 AddressPool **ret,
0dd25fb9 58 int family,
11bf3cce
LP
59 const char *p,
60 unsigned prefixlen) {
61
62 union in_addr_union u;
63 int r;
64
65 assert(m);
66 assert(ret);
67 assert(p);
68
69 r = in_addr_from_string(family, p, &u);
70 if (r < 0)
71 return r;
72
73 return address_pool_new(m, ret, family, &u, prefixlen);
74}
75
76void address_pool_free(AddressPool *p) {
77
78 if (!p)
79 return;
80
81 if (p->manager)
82 LIST_REMOVE(address_pools, p->manager->address_pools, p);
83
84 free(p);
85}
86
87static bool address_pool_prefix_is_taken(
88 AddressPool *p,
89 const union in_addr_union *u,
90 unsigned prefixlen) {
91
92 Iterator i;
93 Link *l;
94 Network *n;
95
96 assert(p);
97 assert(u);
98
99 HASHMAP_FOREACH(l, p->manager->links, i) {
100 Address *a;
cf1d700d 101 Iterator j;
11bf3cce
LP
102
103 /* Don't clash with assigned addresses */
cf1d700d 104 SET_FOREACH(a, l->addresses, j) {
11bf3cce
LP
105 if (a->family != p->family)
106 continue;
107
108 if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
109 return true;
110 }
111
112 /* Don't clash with addresses already pulled from the pool, but not assigned yet */
113 LIST_FOREACH(addresses, a, l->pool_addresses) {
114 if (a->family != p->family)
115 continue;
116
117 if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
118 return true;
119 }
120 }
121
122 /* And don't clash with configured but un-assigned addresses either */
123 LIST_FOREACH(networks, n, p->manager->networks) {
124 Address *a;
125
126 LIST_FOREACH(addresses, a, n->static_addresses) {
127 if (a->family != p->family)
128 continue;
129
130 if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
131 return true;
132 }
133 }
134
135 return false;
136}
137
138int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found) {
139 union in_addr_union u;
140
141 assert(p);
142 assert(prefixlen > 0);
143 assert(found);
144
145 if (p->prefixlen > prefixlen)
146 return 0;
147
148 u = p->in_addr;
149 for (;;) {
150 if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
151 _cleanup_free_ char *s = NULL;
152
153 in_addr_to_string(p->family, &u, &s);
154 log_debug("Found range %s/%u", strna(s), prefixlen);
155
156 *found = u;
157 return 1;
158 }
159
160 if (!in_addr_prefix_next(p->family, &u, prefixlen))
161 return 0;
162
163 if (!in_addr_prefix_intersect(p->family, &p->in_addr, p->prefixlen, &u, prefixlen))
164 return 0;
165 }
166
167 return 0;
168}