Coverage Report

Created: 2019-06-19 13:33

/src/systemd/src/network/networkd-address-pool.c
Line
Count
Source (jump to first uncovered line)
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
0
#define RANDOM_PREFIX_TRIAL_MAX  1024
10
11
static int address_pool_new(
12
                Manager *m,
13
                AddressPool **ret,
14
                int family,
15
                const union in_addr_union *u,
16
80.1k
                unsigned prefixlen) {
17
80.1k
18
80.1k
        AddressPool *p;
19
80.1k
20
80.1k
        assert(m);
21
80.1k
        assert(ret);
22
80.1k
        assert(u);
23
80.1k
24
80.1k
        p = new(AddressPool, 1);
25
80.1k
        if (!p)
26
0
                return -ENOMEM;
27
80.1k
28
80.1k
        *p = (AddressPool) {
29
80.1k
                .manager = m,
30
80.1k
                .family = family,
31
80.1k
                .prefixlen = prefixlen,
32
80.1k
                .in_addr = *u,
33
80.1k
        };
34
80.1k
35
80.1k
        LIST_PREPEND(address_pools, m->address_pools, p);
36
80.1k
37
80.1k
        *ret = p;
38
80.1k
        return 0;
39
80.1k
}
40
41
int address_pool_new_from_string(
42
                Manager *m,
43
                AddressPool **ret,
44
                int family,
45
                const char *p,
46
80.1k
                unsigned prefixlen) {
47
80.1k
48
80.1k
        union in_addr_union u;
49
80.1k
        int r;
50
80.1k
51
80.1k
        assert(m);
52
80.1k
        assert(ret);
53
80.1k
        assert(p);
54
80.1k
55
80.1k
        r = in_addr_from_string(family, p, &u);
56
80.1k
        if (r < 0)
57
0
                return r;
58
80.1k
59
80.1k
        return address_pool_new(m, ret, family, &u, prefixlen);
60
80.1k
}
61
62
80.1k
void address_pool_free(AddressPool *p) {
63
80.1k
64
80.1k
        if (!p)
65
0
                return;
66
80.1k
67
80.1k
        if (p->manager)
68
80.1k
                LIST_REMOVE(address_pools, p->manager->address_pools, p);
69
80.1k
70
80.1k
        free(p);
71
80.1k
}
72
73
static bool address_pool_prefix_is_taken(
74
                AddressPool *p,
75
                const union in_addr_union *u,
76
0
                unsigned prefixlen) {
77
0
78
0
        Iterator i;
79
0
        Link *l;
80
0
        Network *n;
81
0
82
0
        assert(p);
83
0
        assert(u);
84
0
85
0
        HASHMAP_FOREACH(l, p->manager->links, i) {
86
0
                Address *a;
87
0
                Iterator j;
88
0
89
0
                /* 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
0
94
0
                        if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
95
0
                                return true;
96
0
                }
97
0
98
0
                /* 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
0
103
0
                        if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
104
0
                                return true;
105
0
                }
106
0
        }
107
0
108
0
        /* And don't clash with configured but un-assigned addresses either */
109
0
        ORDERED_HASHMAP_FOREACH(n, p->manager->networks, i) {
110
0
                Address *a;
111
0
112
0
                LIST_FOREACH(addresses, a, n->static_addresses) {
113
0
                        if (a->family != p->family)
114
0
                                continue;
115
0
116
0
                        if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
117
0
                                return true;
118
0
                }
119
0
        }
120
0
121
0
        return false;
122
0
}
123
124
0
int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found) {
125
0
        union in_addr_union u;
126
0
        unsigned i;
127
0
        int r;
128
0
129
0
        assert(p);
130
0
        assert(prefixlen > 0);
131
0
        assert(found);
132
0
133
0
        if (p->prefixlen >= prefixlen)
134
0
                return 0;
135
0
136
0
        u = p->in_addr;
137
0
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
0
143
0
                if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
144
0
                        if (DEBUG_LOGGING) {
145
0
                                _cleanup_free_ char *s = NULL;
146
0
147
0
                                (void) in_addr_to_string(p->family, &u, &s);
148
0
                                log_debug("Found range %s/%u", strna(s), prefixlen);
149
0
                        }
150
0
151
0
                        *found = u;
152
0
                        return 1;
153
0
                }
154
0
        }
155
0
156
0
        return 0;
157
0
}