Line data Source code
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 :
22 :
23 : #include "networkd.h"
24 : #include "networkd-link.h"
25 :
26 4 : int address_pool_new(
27 : Manager *m,
28 : AddressPool **ret,
29 : int family,
30 : const union in_addr_union *u,
31 : unsigned prefixlen) {
32 :
33 : AddressPool *p;
34 :
35 4 : assert(m);
36 4 : assert(ret);
37 4 : assert(u);
38 :
39 4 : p = new0(AddressPool, 1);
40 4 : if (!p)
41 0 : return -ENOMEM;
42 :
43 4 : p->manager = m;
44 4 : p->family = family;
45 4 : p->prefixlen = prefixlen;
46 4 : p->in_addr = *u;
47 :
48 4 : LIST_PREPEND(address_pools, m->address_pools, p);
49 :
50 4 : *ret = p;
51 4 : return 0;
52 : }
53 :
54 4 : int address_pool_new_from_string(
55 : Manager *m,
56 : AddressPool **ret,
57 : int family,
58 : const char *p,
59 : unsigned prefixlen) {
60 :
61 : union in_addr_union u;
62 : int r;
63 :
64 4 : assert(m);
65 4 : assert(ret);
66 4 : assert(p);
67 :
68 4 : r = in_addr_from_string(family, p, &u);
69 4 : if (r < 0)
70 0 : return r;
71 :
72 4 : return address_pool_new(m, ret, family, &u, prefixlen);
73 : }
74 :
75 4 : void address_pool_free(AddressPool *p) {
76 :
77 4 : if (!p)
78 0 : return;
79 :
80 4 : if (p->manager)
81 4 : LIST_REMOVE(address_pools, p->manager->address_pools, p);
82 :
83 4 : free(p);
84 : }
85 :
86 0 : static bool address_pool_prefix_is_taken(
87 : AddressPool *p,
88 : const union in_addr_union *u,
89 : unsigned prefixlen) {
90 :
91 : Iterator i;
92 : Link *l;
93 : Network *n;
94 :
95 0 : assert(p);
96 0 : assert(u);
97 :
98 0 : HASHMAP_FOREACH(l, p->manager->links, i) {
99 : Address *a;
100 :
101 : /* Don't clash with assigned addresses */
102 0 : LIST_FOREACH(addresses, a, l->addresses) {
103 0 : if (a->family != p->family)
104 0 : continue;
105 :
106 0 : if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
107 0 : return true;
108 : }
109 :
110 : /* Don't clash with addresses already pulled from the pool, but not assigned yet */
111 0 : LIST_FOREACH(addresses, a, l->pool_addresses) {
112 0 : if (a->family != p->family)
113 0 : continue;
114 :
115 0 : if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
116 0 : return true;
117 : }
118 : }
119 :
120 : /* And don't clash with configured but un-assigned addresses either */
121 0 : LIST_FOREACH(networks, n, p->manager->networks) {
122 : Address *a;
123 :
124 0 : LIST_FOREACH(addresses, a, n->static_addresses) {
125 0 : if (a->family != p->family)
126 0 : continue;
127 :
128 0 : if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
129 0 : return true;
130 : }
131 : }
132 :
133 0 : return false;
134 : }
135 :
136 0 : int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found) {
137 : union in_addr_union u;
138 :
139 0 : assert(p);
140 0 : assert(prefixlen > 0);
141 0 : assert(found);
142 :
143 0 : if (p->prefixlen > prefixlen)
144 0 : return 0;
145 :
146 0 : u = p->in_addr;
147 : for (;;) {
148 0 : if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
149 0 : _cleanup_free_ char *s = NULL;
150 :
151 0 : in_addr_to_string(p->family, &u, &s);
152 0 : log_debug("Found range %s/%u", strna(s), prefixlen);
153 :
154 0 : *found = u;
155 0 : return 1;
156 : }
157 :
158 0 : if (!in_addr_prefix_next(p->family, &u, prefixlen))
159 0 : return 0;
160 :
161 0 : if (!in_addr_prefix_intersect(p->family, &p->in_addr, p->prefixlen, &u, prefixlen))
162 0 : return 0;
163 0 : }
164 :
165 : return 0;
166 : }
|