chiark / gitweb /
systemctl: when "systemctl status" is called without arguments show a short overall...
[elogind.git] / src / network / networkd-route.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 route_new_static(Network *network, unsigned section, Route **ret) {
32         _cleanup_route_free_ Route *route = NULL;
33
34         if (section) {
35                 uint64_t key = section;
36
37                 route = hashmap_get(network->routes_by_section, &key);
38                 if (route) {
39                         *ret = route;
40                         route = NULL;
41
42                         return 0;
43                 }
44         }
45
46         route = new0(Route, 1);
47         if (!route)
48                 return -ENOMEM;
49
50         route->family = AF_UNSPEC;
51         route->scope = RT_SCOPE_UNIVERSE;
52
53         route->network = network;
54
55         LIST_PREPEND(static_routes, network->static_routes, route);
56
57         if (section) {
58                 route->section = section;
59                 hashmap_put(network->routes_by_section, &route->section, route);
60         }
61
62         *ret = route;
63         route = NULL;
64
65         return 0;
66 }
67
68 int route_new_dynamic(Route **ret) {
69         _cleanup_route_free_ Route *route = NULL;
70
71         route = new0(Route, 1);
72         if (!route)
73                 return -ENOMEM;
74
75         route->family = AF_UNSPEC;
76         route->scope = RT_SCOPE_UNIVERSE;
77
78         *ret = route;
79         route = NULL;
80
81         return 0;
82 }
83
84 void route_free(Route *route) {
85         if (!route)
86                 return;
87
88         if (route->network) {
89                 LIST_REMOVE(static_routes, route->network->static_routes, route);
90
91                 if (route->section)
92                         hashmap_remove(route->network->routes_by_section,
93                                        &route->section);
94         }
95
96         free(route);
97 }
98
99 int route_drop(Route *route, Link *link,
100                sd_rtnl_message_handler_t callback) {
101         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
102         int r;
103
104         assert(link);
105         assert(link->manager);
106         assert(link->manager->rtnl);
107         assert(link->ifindex > 0);
108         assert(route->family == AF_INET || route->family == AF_INET6);
109
110         r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
111                                       RTM_DELROUTE, route->family);
112         if (r < 0) {
113                 log_error("Could not create RTM_DELROUTE message: %s", strerror(-r));
114                 return r;
115         }
116
117         if (route->family == AF_INET)
118                 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
119         else if (route->family == AF_INET6)
120                 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
121         if (r < 0) {
122                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
123                 return r;
124         }
125
126         if (route->dst_prefixlen) {
127                 if (route->family == AF_INET)
128                         r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
129                 else if (route->family == AF_INET6)
130                         r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
131                 if (r < 0) {
132                         log_error("Could not append RTA_DST attribute: %s", strerror(-r));
133                         return r;
134                 }
135
136                 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
137                 if (r < 0) {
138                         log_error("Could not set destination prefix length: %s", strerror(-r));
139                         return r;
140                 }
141         }
142
143         r = sd_rtnl_message_route_set_scope(req, route->scope);
144         if (r < 0) {
145                 log_error("Could not set scope: %s", strerror(-r));
146                 return r;
147         }
148
149         r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
150         if (r < 0) {
151                 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
152                 return r;
153         }
154
155         r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
156         if (r < 0) {
157                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
158                 return r;
159         }
160
161         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
162         if (r < 0) {
163                 log_error("Could not send rtnetlink message: %s", strerror(-r));
164                 return r;
165         }
166
167         return 0;
168 }
169
170 int route_configure(Route *route, Link *link,
171                     sd_rtnl_message_handler_t callback) {
172         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
173         int r;
174
175         assert(link);
176         assert(link->manager);
177         assert(link->manager->rtnl);
178         assert(link->ifindex > 0);
179         assert(route->family == AF_INET || route->family == AF_INET6);
180
181         r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
182                                       RTM_NEWROUTE, route->family);
183         if (r < 0) {
184                 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
185                 return r;
186         }
187
188         if (route->family == AF_INET)
189                 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
190         else if (route->family == AF_INET6)
191                 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
192         if (r < 0) {
193                 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
194                 return r;
195         }
196
197         if (route->dst_prefixlen) {
198                 if (route->family == AF_INET)
199                         r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
200                 else if (route->family == AF_INET6)
201                         r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
202                 if (r < 0) {
203                         log_error("Could not append RTA_DST attribute: %s", strerror(-r));
204                         return r;
205                 }
206
207                 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
208                 if (r < 0) {
209                         log_error("Could not set destination prefix length: %s", strerror(-r));
210                         return r;
211                 }
212         }
213
214         r = sd_rtnl_message_route_set_scope(req, route->scope);
215         if (r < 0) {
216                 log_error("Could not set scope: %s", strerror(-r));
217                 return r;
218         }
219
220         r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
221         if (r < 0) {
222                 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
223                 return r;
224         }
225
226         r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
227         if (r < 0) {
228                 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
229                 return r;
230         }
231
232         r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
233         if (r < 0) {
234                 log_error("Could not send rtnetlink message: %s", strerror(-r));
235                 return r;
236         }
237
238         return 0;
239 }
240
241 int config_parse_gateway(const char *unit,
242                 const char *filename,
243                 unsigned line,
244                 const char *section,
245                 unsigned section_line,
246                 const char *lvalue,
247                 int ltype,
248                 const char *rvalue,
249                 void *data,
250                 void *userdata) {
251         Network *network = userdata;
252         _cleanup_route_free_ Route *n = NULL;
253         _cleanup_free_ char *route = NULL;
254         int r;
255
256         assert(filename);
257         assert(section);
258         assert(lvalue);
259         assert(rvalue);
260         assert(data);
261
262         if (streq(section, "Network")) {
263                 /* we are not in an Route section, so treat
264                  * this as the special '0' section */
265                 section_line = 0;
266         }
267
268         r = route_new_static(network, section_line, &n);
269         if (r < 0)
270                 return r;
271
272         r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
273         if (r < 0) {
274                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
275                            "Route is invalid, ignoring assignment: %s", route);
276                 return 0;
277         }
278
279         n = NULL;
280
281         return 0;
282 }
283
284 int config_parse_destination(const char *unit,
285                 const char *filename,
286                 unsigned line,
287                 const char *section,
288                 unsigned section_line,
289                 const char *lvalue,
290                 int ltype,
291                 const char *rvalue,
292                 void *data,
293                 void *userdata) {
294         Network *network = userdata;
295         _cleanup_route_free_ Route *n = NULL;
296         _cleanup_free_ char *address = NULL;
297         const char *e;
298         int r;
299
300         assert(filename);
301         assert(section);
302         assert(lvalue);
303         assert(rvalue);
304         assert(data);
305
306         r = route_new_static(network, section_line, &n);
307         if (r < 0)
308                 return r;
309
310         /* Destination=address/prefixlen */
311
312         /* address */
313         e = strchr(rvalue, '/');
314         if (e) {
315                 address = strndup(rvalue, e - rvalue);
316                 if (!address)
317                         return log_oom();
318         } else {
319                 address = strdup(rvalue);
320                 if (!address)
321                         return log_oom();
322         }
323
324         r = net_parse_inaddr(address, &n->family, &n->dst_addr);
325         if (r < 0) {
326                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
327                            "Destination is invalid, ignoring assignment: %s", address);
328                 return 0;
329         }
330
331         /* prefixlen */
332         if (e) {
333                 unsigned i;
334
335                 r = safe_atou(e + 1, &i);
336                 if (r < 0) {
337                         log_syntax(unit, LOG_ERR, filename, line, EINVAL,
338                                    "Route destination prefix length is invalid, "
339                                    "ignoring assignment: %s", e + 1);
340                         return 0;
341                 }
342
343                 n->dst_prefixlen = (unsigned char) i;
344         } else {
345                 switch (n->family) {
346                         case AF_INET:
347                                 n->dst_prefixlen = 32;
348                                 break;
349                         case AF_INET6:
350                                 n->dst_prefixlen = 128;
351                                 break;
352                 }
353         }
354
355         n = NULL;
356
357         return 0;
358 }