tizen 2.4 release
[external/systemd.git] / src / network / networkd-address-pool.c
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 #include <arpa/inet.h>
23
24 #include "networkd.h"
25 #include "networkd-link.h"
26
27 int address_pool_new(
28                 Manager *m,
29                 AddressPool **ret,
30                 int family,
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
55 int address_pool_new_from_string(
56                 Manager *m,
57                 AddressPool **ret,
58                 int family,
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
76 void 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
87 static 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;
101
102                 /* Don't clash with assigned addresses */
103                 LIST_FOREACH(addresses, a, l->addresses) {
104                         if (a->family != p->family)
105                                 continue;
106
107                         if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
108                                 return true;
109                 }
110
111                 /* Don't clash with addresses already pulled from the pool, but not assigned yet */
112                 LIST_FOREACH(addresses, a, l->pool_addresses) {
113                         if (a->family != p->family)
114                                 continue;
115
116                         if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
117                                 return true;
118                 }
119         }
120
121         /* And don't clash with configured but un-assigned addresses either */
122         LIST_FOREACH(networks, n, p->manager->networks) {
123                 Address *a;
124
125                 LIST_FOREACH(addresses, a, n->static_addresses) {
126                         if (a->family != p->family)
127                                 continue;
128
129                         if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
130                                 return true;
131                 }
132         }
133
134         return false;
135 }
136
137 int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found) {
138         union in_addr_union u;
139
140         assert(p);
141         assert(prefixlen > 0);
142         assert(found);
143
144         if (p->prefixlen > prefixlen)
145                 return 0;
146
147         u = p->in_addr;
148         for (;;) {
149                 if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
150                         _cleanup_free_ char *s = NULL;
151
152                         in_addr_to_string(p->family, &u, &s);
153                         log_debug("Found range %s/%u", strna(s), prefixlen);
154
155                         *found = u;
156                         return 1;
157                 }
158
159                 if (!in_addr_prefix_next(p->family, &u, prefixlen))
160                         return 0;
161
162                 if (!in_addr_prefix_intersect(p->family, &p->in_addr, p->prefixlen, &u, prefixlen))
163                         return 0;
164         }
165
166         return 0;
167 }