]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address.c
network: add support for dropping address
[thirdparty/systemd.git] / src / network / networkd-address.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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 <net/if.h>
23
24#include "networkd.h"
25
26#include "utf8.h"
27#include "util.h"
28#include "conf-parser.h"
29#include "net-util.h"
30
6ae115c1 31int address_new(Network *network, unsigned section, Address **ret) {
f579559b
TG
32 _cleanup_address_free_ Address *address = NULL;
33
6ae115c1
TG
34 if (section) {
35 uint64_t key = section;
36 address = hashmap_get(network->addresses_by_section, &key);
37 if (address) {
38 *ret = address;
39 address = NULL;
40
41 return 0;
42 }
43 }
44
f579559b
TG
45 address = new0(Address, 1);
46 if (!address)
47 return -ENOMEM;
48
49 address->network = network;
50
51 LIST_PREPEND(addresses, network->addresses, address);
52
6ae115c1
TG
53 if (section) {
54 address->section = section;
55 hashmap_put(network->addresses_by_section, &address->section, address);
56 }
57
f579559b
TG
58 *ret = address;
59 address = NULL;
60
61 return 0;
62}
63
64void address_free(Address *address) {
65 if (!address)
66 return;
67
68 LIST_REMOVE(addresses, address->network->addresses, address);
69
6ae115c1
TG
70 if (address->section)
71 hashmap_remove(address->network->addresses_by_section,
72 &address->section);
73
f579559b
TG
74 free(address);
75}
76
407fe036
TG
77int address_drop(Address *address, Link *link,
78 sd_rtnl_message_handler_t callback) {
79 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
80 int r;
81
82 assert(address);
83 assert(address->family == AF_INET || address->family == AF_INET6);
84 assert(link);
85 assert(link->ifindex > 0);
86 assert(link->manager);
87 assert(link->manager->rtnl);
88
89 r = sd_rtnl_message_addr_new(RTM_DELADDR, link->ifindex,
90 address->family, address->prefixlen, 0, 0, &req);
91 if (r < 0) {
92 log_error("Could not allocate RTM_DELADDR message: %s",
93 strerror(-r));
94 return r;
95 }
96
97 if (address->family == AF_INET)
98 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
99 else if (address->family == AF_INET6)
100 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
101 if (r < 0) {
102 log_error("Could not append IFA_LOCAL attribute: %s",
103 strerror(-r));
104 return r;
105 }
106
107 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
108 if (r < 0) {
109 log_error("Could not send rtnetlink message: %s", strerror(-r));
110 return r;
111 }
112
113 return 0;
114}
115
f882c247
TG
116int address_configure(Address *address, Link *link,
117 sd_rtnl_message_handler_t callback) {
f579559b
TG
118 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
119 int r;
120
c166a070
TG
121 assert(address);
122 assert(address->family == AF_INET || address->family == AF_INET6);
123 assert(link);
124 assert(link->ifindex > 0);
f882c247 125 assert(link->manager);
c166a070 126 assert(link->manager->rtnl);
f882c247 127
f579559b
TG
128 r = sd_rtnl_message_addr_new(RTM_NEWADDR, link->ifindex,
129 address->family, address->prefixlen,
130 IFA_F_PERMANENT, RT_SCOPE_UNIVERSE, &req);
131 if (r < 0) {
132 log_error("Could not allocate RTM_NEWADDR message: %s",
133 strerror(-r));
134 return r;
135 }
136
0a0dc69b
TG
137 if (address->family == AF_INET)
138 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
139 else if (address->family == AF_INET6)
140 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
f579559b
TG
141 if (r < 0) {
142 log_error("Could not append IFA_LOCAL attribute: %s",
143 strerror(-r));
144 return r;
145 }
146
147 if (address->family == AF_INET) {
148 struct in_addr broadcast;
149
8cd11a0f 150 broadcast.s_addr = address->in_addr.in.s_addr | address->netmask.s_addr;
f579559b 151
0a0dc69b 152 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &broadcast);
f579559b
TG
153 if (r < 0) {
154 log_error("Could not append IFA_BROADCAST attribute: %s",
155 strerror(-r));
156 return r;
157 }
158 }
159
160 if (address->label) {
0a0dc69b 161 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
f579559b
TG
162 if (r < 0) {
163 log_error("Could not append IFA_LABEL attribute: %s",
164 strerror(-r));
165 return r;
166 }
167 }
168
f882c247 169 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
f579559b 170 if (r < 0) {
f882c247
TG
171 log_error("Could not send rtnetlink message: %s", strerror(-r));
172 return r;
f579559b
TG
173 }
174
f579559b
TG
175 return 0;
176}
177
178int config_parse_address(const char *unit,
179 const char *filename,
180 unsigned line,
181 const char *section,
71a61510 182 unsigned section_line,
f579559b
TG
183 const char *lvalue,
184 int ltype,
185 const char *rvalue,
186 void *data,
187 void *userdata) {
6ae115c1 188 Network *network = userdata;
f579559b
TG
189 _cleanup_address_free_ Address *n = NULL;
190 _cleanup_free_ char *address = NULL;
191 const char *e;
192 int r;
193
194 assert(filename);
6ae115c1 195 assert(section);
f579559b
TG
196 assert(lvalue);
197 assert(rvalue);
198 assert(data);
199
92fe133a
TG
200 if (streq(section, "Network")) {
201 /* we are not in an Address section, so treat
202 * this as the special '0' section */
203 section_line = 0;
204 }
205
6ae115c1 206 r = address_new(network, section_line, &n);
f579559b
TG
207 if (r < 0)
208 return r;
209
210 /* Address=address/prefixlen */
211
212 /* prefixlen */
213 e = strchr(rvalue, '/');
214 if (e) {
215 unsigned i;
216 r = safe_atou(e + 1, &i);
217 if (r < 0) {
218 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
219 "Interface prefix length is invalid, "
220 "ignoring assignment: %s", e + 1);
221 return 0;
222 }
223
224 n->prefixlen = (unsigned char) i;
8cd11a0f
TG
225 n->netmask.s_addr = htonl(0xfffffffflu >> n->prefixlen);
226
f579559b
TG
227 address = strndup(rvalue, e - rvalue);
228 if (!address)
229 return log_oom();
230 } else {
231 address = strdup(rvalue);
232 if (!address)
233 return log_oom();
234 }
235
236 r = net_parse_inaddr(address, &n->family, &n->in_addr);
237 if (r < 0) {
238 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
239 "Address is invalid, ignoring assignment: %s", address);
240 return 0;
241 }
242
243 n = NULL;
244
245 return 0;
246}
6ae115c1
TG
247
248int config_parse_label(const char *unit,
249 const char *filename,
250 unsigned line,
251 const char *section,
252 unsigned section_line,
253 const char *lvalue,
254 int ltype,
255 const char *rvalue,
256 void *data,
257 void *userdata) {
258 Network *network = userdata;
259 _cleanup_address_free_ Address *n = NULL;
6ae115c1
TG
260 char *label;
261 int r;
262
263 assert(filename);
264 assert(section);
265 assert(lvalue);
266 assert(rvalue);
267 assert(data);
268
269 r = address_new(network, section_line, &n);
270 if (r < 0)
271 return r;
272
273 label = strdup(rvalue);
274 if (!label)
275 return log_oom();
276
277 if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
278 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
279 "Interface label is not ASCII clean or is too"
280 " long, ignoring assignment: %s", rvalue);
281 free(label);
282 return 0;
283 }
284
285 free(n->label);
286 if (*label)
287 n->label = label;
288 else {
289 free(label);
290 n->label = NULL;
291 }
292
293 n = NULL;
294
295 return 0;
296}