chiark / gitweb /
rtnl: rename constructors from the form sd_rtnl_xxx_yyy_new() to sd_rtnl_xxx_new_yyy()
[elogind.git] / src / network / networkd-address.c
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
31 int address_new_static(Network *network, unsigned section, Address **ret) {
32         _cleanup_address_free_ Address *address = NULL;
33
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
45         address = new0(Address, 1);
46         if (!address)
47                 return -ENOMEM;
48
49         address->family = AF_UNSPEC;
50
51         address->network = network;
52
53         LIST_PREPEND(static_addresses, network->static_addresses, address);
54
55         if (section) {
56                 address->section = section;
57                 hashmap_put(network->addresses_by_section, &address->section, address);
58         }
59
60         *ret = address;
61         address = NULL;
62
63         return 0;
64 }
65
66 int address_new_dynamic(Address **ret) {
67         _cleanup_address_free_ Address *address = NULL;
68
69         address = new0(Address, 1);
70         if (!address)
71                 return -ENOMEM;
72
73         address->family = AF_UNSPEC;
74
75         *ret = address;
76         address = NULL;
77
78         return 0;
79 }
80
81 void address_free(Address *address) {
82         if (!address)
83                 return;
84
85         if (address->network) {
86                 LIST_REMOVE(static_addresses, address->network->static_addresses, address);
87
88                 if (address->section)
89                         hashmap_remove(address->network->addresses_by_section,
90                                        &address->section);
91         }
92
93         free(address);
94 }
95
96 int address_drop(Address *address, Link *link,
97                  sd_rtnl_message_handler_t callback) {
98         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
99         int r;
100
101         assert(address);
102         assert(address->family == AF_INET || address->family == AF_INET6);
103         assert(link);
104         assert(link->ifindex > 0);
105         assert(link->manager);
106         assert(link->manager->rtnl);
107
108         r = sd_rtnl_message_new_addr(RTM_DELADDR, link->ifindex, address->family, &req);
109         if (r < 0) {
110                 log_error("Could not allocate RTM_DELADDR message: %s",
111                           strerror(-r));
112                 return r;
113         }
114
115         r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
116         if (r < 0) {
117                 log_error("Could not set prefixlen: %s", strerror(-r));
118                 return r;
119         }
120
121         if (address->family == AF_INET)
122                 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
123         else if (address->family == AF_INET6)
124                 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
125         if (r < 0) {
126                 log_error("Could not append IFA_LOCAL attribute: %s",
127                           strerror(-r));
128                 return r;
129         }
130
131         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
132         if (r < 0) {
133                 log_error("Could not send rtnetlink message: %s", strerror(-r));
134                 return r;
135         }
136
137         return 0;
138 }
139
140 int address_configure(Address *address, Link *link,
141                       sd_rtnl_message_handler_t callback) {
142         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
143         int r;
144
145         assert(address);
146         assert(address->family == AF_INET || address->family == AF_INET6);
147         assert(link);
148         assert(link->ifindex > 0);
149         assert(link->manager);
150         assert(link->manager->rtnl);
151
152         r = sd_rtnl_message_new_addr(RTM_NEWADDR, link->ifindex,
153                         address->family, &req);
154         if (r < 0) {
155                 log_error("Could not allocate RTM_NEWADDR message: %s",
156                           strerror(-r));
157                 return r;
158         }
159
160         r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
161         if (r < 0) {
162                 log_error("Could not set prefixlen: %s", strerror(-r));
163                 return r;
164         }
165
166         r = sd_rtnl_message_addr_set_flags(req, IFA_F_PERMANENT);
167         if (r < 0) {
168                 log_error("Could not set flags: %s", strerror(-r));
169                 return r;
170         }
171
172         r = sd_rtnl_message_addr_set_scope(req, RT_SCOPE_UNIVERSE);
173         if (r < 0) {
174                 log_error("Could not set scope: %s", strerror(-r));
175                 return r;
176         }
177
178         if (address->family == AF_INET)
179                 r = sd_rtnl_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
180         else if (address->family == AF_INET6)
181                 r = sd_rtnl_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
182         if (r < 0) {
183                 log_error("Could not append IFA_LOCAL attribute: %s",
184                           strerror(-r));
185                 return r;
186         }
187
188         if (address->family == AF_INET) {
189                 r = sd_rtnl_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
190                 if (r < 0) {
191                         log_error("Could not append IFA_BROADCAST attribute: %s",
192                                   strerror(-r));
193                         return r;
194                 }
195         }
196
197         if (address->label) {
198                 r = sd_rtnl_message_append_string(req, IFA_LABEL, address->label);
199                 if (r < 0) {
200                         log_error("Could not append IFA_LABEL attribute: %s",
201                                   strerror(-r));
202                         return r;
203                 }
204         }
205
206         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
207         if (r < 0) {
208                 log_error("Could not send rtnetlink message: %s", strerror(-r));
209                 return r;
210         }
211
212         return 0;
213 }
214
215 int config_parse_dns(const char *unit,
216                 const char *filename,
217                 unsigned line,
218                 const char *section,
219                 unsigned section_line,
220                 const char *lvalue,
221                 int ltype,
222                 const char *rvalue,
223                 void *data,
224                 void *userdata) {
225         Address **dns = data;
226         _cleanup_address_free_ Address *n = NULL;
227         int r;
228
229         assert(filename);
230         assert(section);
231         assert(lvalue);
232         assert(rvalue);
233         assert(data);
234
235         r = address_new_dynamic(&n);
236         if (r < 0)
237                 return r;
238
239         r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
240         if (r < 0) {
241                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
242                            "DNS address is invalid, ignoring assignment: %s", rvalue);
243                 return 0;
244         }
245
246         *dns = n;
247         n = NULL;
248
249         return 0;
250 }
251
252 int config_parse_broadcast(const char *unit,
253                 const char *filename,
254                 unsigned line,
255                 const char *section,
256                 unsigned section_line,
257                 const char *lvalue,
258                 int ltype,
259                 const char *rvalue,
260                 void *data,
261                 void *userdata) {
262         Network *network = userdata;
263         _cleanup_address_free_ Address *n = NULL;
264         _cleanup_free_ char *address = NULL;
265         int r;
266
267         assert(filename);
268         assert(section);
269         assert(lvalue);
270         assert(rvalue);
271         assert(data);
272
273         r = address_new_static(network, section_line, &n);
274         if (r < 0)
275                 return r;
276
277         r = net_parse_inaddr(address, &n->family, &n->broadcast);
278         if (r < 0) {
279                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
280                            "Broadcast is invalid, ignoring assignment: %s", address);
281                 return 0;
282         }
283
284         n = NULL;
285
286         return 0;
287 }
288
289 int config_parse_address(const char *unit,
290                 const char *filename,
291                 unsigned line,
292                 const char *section,
293                 unsigned section_line,
294                 const char *lvalue,
295                 int ltype,
296                 const char *rvalue,
297                 void *data,
298                 void *userdata) {
299         Network *network = userdata;
300         _cleanup_address_free_ Address *n = NULL;
301         _cleanup_free_ char *address = NULL;
302         const char *e;
303         int r;
304
305         assert(filename);
306         assert(section);
307         assert(lvalue);
308         assert(rvalue);
309         assert(data);
310
311         if (streq(section, "Network")) {
312                 /* we are not in an Address section, so treat
313                  * this as the special '0' section */
314                 section_line = 0;
315         }
316
317         r = address_new_static(network, section_line, &n);
318         if (r < 0)
319                 return r;
320
321         /* Address=address/prefixlen */
322
323         /* prefixlen */
324         e = strchr(rvalue, '/');
325         if (e) {
326                 unsigned i;
327                 r = safe_atou(e + 1, &i);
328                 if (r < 0) {
329                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
330                                    "Interface prefix length is invalid, "
331                                    "ignoring assignment: %s", e + 1);
332                         return 0;
333                 }
334
335                 n->prefixlen = (unsigned char) i;
336
337                 address = strndup(rvalue, e - rvalue);
338                 if (!address)
339                         return log_oom();
340         } else {
341                 address = strdup(rvalue);
342                 if (!address)
343                         return log_oom();
344         }
345
346         r = net_parse_inaddr(address, &n->family, &n->in_addr);
347         if (r < 0) {
348                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
349                            "Address is invalid, ignoring assignment: %s", address);
350                 return 0;
351         }
352
353         if (n->family == AF_INET && !n->broadcast.s_addr)
354                 n->broadcast.s_addr = n->in_addr.in.s_addr |
355                                       htonl(0xfffffffflu >> n->prefixlen);
356
357         n = NULL;
358
359         return 0;
360 }
361
362 int config_parse_label(const char *unit,
363                 const char *filename,
364                 unsigned line,
365                 const char *section,
366                 unsigned section_line,
367                 const char *lvalue,
368                 int ltype,
369                 const char *rvalue,
370                 void *data,
371                 void *userdata) {
372         Network *network = userdata;
373         _cleanup_address_free_ Address *n = NULL;
374         char *label;
375         int r;
376
377         assert(filename);
378         assert(section);
379         assert(lvalue);
380         assert(rvalue);
381         assert(data);
382
383         r = address_new_static(network, section_line, &n);
384         if (r < 0)
385                 return r;
386
387         label = strdup(rvalue);
388         if (!label)
389                 return log_oom();
390
391         if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
392                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
393                            "Interface label is not ASCII clean or is too"
394                            " long, ignoring assignment: %s", rvalue);
395                 free(label);
396                 return 0;
397         }
398
399         free(n->label);
400         if (*label)
401                 n->label = label;
402         else {
403                 free(label);
404                 n->label = NULL;
405         }
406
407         n = NULL;
408
409         return 0;
410 }