]> git.proxmox.com Git - systemd.git/blame - src/network/networkd-route.c
Imported Upstream version 217
[systemd.git] / src / network / networkd-route.c
CommitLineData
60f067b4
JS
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"
5eef597e 25#include "networkd-link.h"
60f067b4
JS
26
27#include "utf8.h"
28#include "util.h"
29#include "conf-parser.h"
30#include "network-internal.h"
31
32int route_new_static(Network *network, unsigned section, Route **ret) {
33 _cleanup_route_free_ Route *route = NULL;
34
35 if (section) {
5eef597e
MP
36 route = hashmap_get(network->routes_by_section,
37 UINT_TO_PTR(section));
60f067b4
JS
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;
5eef597e 52 route->protocol = RTPROT_STATIC;
60f067b4
JS
53
54 route->network = network;
55
56 LIST_PREPEND(routes, network->static_routes, route);
57
58 if (section) {
59 route->section = section;
5eef597e
MP
60 hashmap_put(network->routes_by_section,
61 UINT_TO_PTR(route->section), route);
60f067b4
JS
62 }
63
64 *ret = route;
65 route = NULL;
66
67 return 0;
68}
69
5eef597e 70int route_new_dynamic(Route **ret, unsigned char rtm_protocol) {
60f067b4
JS
71 _cleanup_route_free_ Route *route = NULL;
72
73 route = new0(Route, 1);
74 if (!route)
75 return -ENOMEM;
76
77 route->family = AF_UNSPEC;
78 route->scope = RT_SCOPE_UNIVERSE;
5eef597e 79 route->protocol = rtm_protocol;
60f067b4
JS
80
81 *ret = route;
82 route = NULL;
83
84 return 0;
85}
86
87void route_free(Route *route) {
88 if (!route)
89 return;
90
91 if (route->network) {
92 LIST_REMOVE(routes, route->network->static_routes, route);
93
94 if (route->section)
95 hashmap_remove(route->network->routes_by_section,
5eef597e 96 UINT_TO_PTR(route->section));
60f067b4
JS
97 }
98
99 free(route);
100}
101
102int route_drop(Route *route, Link *link,
103 sd_rtnl_message_handler_t callback) {
104 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
105 int r;
106
107 assert(link);
108 assert(link->manager);
109 assert(link->manager->rtnl);
110 assert(link->ifindex > 0);
111 assert(route->family == AF_INET || route->family == AF_INET6);
112
113 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
5eef597e
MP
114 RTM_DELROUTE, route->family,
115 route->protocol);
60f067b4
JS
116 if (r < 0) {
117 log_error("Could not create RTM_DELROUTE message: %s", strerror(-r));
118 return r;
119 }
120
121 if (route->family == AF_INET)
122 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
123 else if (route->family == AF_INET6)
124 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
125 if (r < 0) {
126 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
127 return r;
128 }
129
130 if (route->dst_prefixlen) {
131 if (route->family == AF_INET)
132 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
133 else if (route->family == AF_INET6)
134 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
135 if (r < 0) {
136 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
137 return r;
138 }
139
140 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
141 if (r < 0) {
142 log_error("Could not set destination prefix length: %s", strerror(-r));
143 return r;
144 }
145 }
146
5eef597e
MP
147 if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
148 if (route->family == AF_INET)
149 r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
150 else if (route->family == AF_INET6)
151 r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
152 if (r < 0) {
153 log_error("Could not append RTA_PREFSRC attribute: %s", strerror(-r));
154 return r;
155 }
156 }
157
60f067b4
JS
158 r = sd_rtnl_message_route_set_scope(req, route->scope);
159 if (r < 0) {
160 log_error("Could not set scope: %s", strerror(-r));
161 return r;
162 }
163
164 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
165 if (r < 0) {
166 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
167 return r;
168 }
169
170 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
171 if (r < 0) {
172 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
173 return r;
174 }
175
176 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
177 if (r < 0) {
178 log_error("Could not send rtnetlink message: %s", strerror(-r));
179 return r;
180 }
181
e842803a
MB
182 link_ref(link);
183
60f067b4
JS
184 return 0;
185}
186
187int route_configure(Route *route, Link *link,
188 sd_rtnl_message_handler_t callback) {
189 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
190 int r;
191
192 assert(link);
193 assert(link->manager);
194 assert(link->manager->rtnl);
195 assert(link->ifindex > 0);
196 assert(route->family == AF_INET || route->family == AF_INET6);
197
198 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
5eef597e
MP
199 RTM_NEWROUTE, route->family,
200 route->protocol);
60f067b4
JS
201 if (r < 0) {
202 log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
203 return r;
204 }
205
206 if (route->family == AF_INET)
207 r = sd_rtnl_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in);
208 else if (route->family == AF_INET6)
209 r = sd_rtnl_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6);
210 if (r < 0) {
211 log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
212 return r;
213 }
214
215 if (route->dst_prefixlen) {
216 if (route->family == AF_INET)
217 r = sd_rtnl_message_append_in_addr(req, RTA_DST, &route->dst_addr.in);
218 else if (route->family == AF_INET6)
219 r = sd_rtnl_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6);
220 if (r < 0) {
221 log_error("Could not append RTA_DST attribute: %s", strerror(-r));
222 return r;
223 }
224
225 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
226 if (r < 0) {
227 log_error("Could not set destination prefix length: %s", strerror(-r));
228 return r;
229 }
230 }
231
5eef597e
MP
232 if (!in_addr_is_null(route->family, &route->prefsrc_addr)) {
233 if (route->family == AF_INET)
234 r = sd_rtnl_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in);
235 else if (route->family == AF_INET6)
236 r = sd_rtnl_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6);
237 if (r < 0) {
238 log_error("Could not append RTA_PREFSRC attribute: %s", strerror(-r));
239 return r;
240 }
241 }
242
60f067b4
JS
243 r = sd_rtnl_message_route_set_scope(req, route->scope);
244 if (r < 0) {
245 log_error("Could not set scope: %s", strerror(-r));
246 return r;
247 }
248
249 r = sd_rtnl_message_append_u32(req, RTA_PRIORITY, route->metrics);
250 if (r < 0) {
251 log_error("Could not append RTA_PRIORITY attribute: %s", strerror(-r));
252 return r;
253 }
254
255 r = sd_rtnl_message_append_u32(req, RTA_OIF, link->ifindex);
256 if (r < 0) {
257 log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
258 return r;
259 }
260
261 r = sd_rtnl_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
262 if (r < 0) {
263 log_error("Could not send rtnetlink message: %s", strerror(-r));
264 return r;
265 }
266
e842803a
MB
267 link_ref(link);
268
60f067b4
JS
269 return 0;
270}
271
272int config_parse_gateway(const char *unit,
273 const char *filename,
274 unsigned line,
275 const char *section,
276 unsigned section_line,
277 const char *lvalue,
278 int ltype,
279 const char *rvalue,
280 void *data,
281 void *userdata) {
5eef597e 282
60f067b4
JS
283 Network *network = userdata;
284 _cleanup_route_free_ Route *n = NULL;
5eef597e
MP
285 union in_addr_union buffer;
286 int r, f;
60f067b4
JS
287
288 assert(filename);
289 assert(section);
290 assert(lvalue);
291 assert(rvalue);
292 assert(data);
293
294 if (streq(section, "Network")) {
295 /* we are not in an Route section, so treat
296 * this as the special '0' section */
297 section_line = 0;
298 }
299
300 r = route_new_static(network, section_line, &n);
301 if (r < 0)
302 return r;
303
5eef597e 304 r = in_addr_from_string_auto(rvalue, &f, &buffer);
60f067b4
JS
305 if (r < 0) {
306 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
5eef597e 307 "Route is invalid, ignoring assignment: %s", rvalue);
60f067b4
JS
308 return 0;
309 }
310
5eef597e
MP
311 n->family = f;
312 n->in_addr = buffer;
60f067b4
JS
313 n = NULL;
314
315 return 0;
316}
317
318int config_parse_destination(const char *unit,
319 const char *filename,
320 unsigned line,
321 const char *section,
322 unsigned section_line,
323 const char *lvalue,
324 int ltype,
325 const char *rvalue,
326 void *data,
327 void *userdata) {
5eef597e 328
60f067b4
JS
329 Network *network = userdata;
330 _cleanup_route_free_ Route *n = NULL;
5eef597e
MP
331 const char *address, *e;
332 union in_addr_union buffer;
333 int r, f;
60f067b4
JS
334
335 assert(filename);
336 assert(section);
337 assert(lvalue);
338 assert(rvalue);
339 assert(data);
340
341 r = route_new_static(network, section_line, &n);
342 if (r < 0)
343 return r;
344
345 /* Destination=address/prefixlen */
346
347 /* address */
348 e = strchr(rvalue, '/');
5eef597e
MP
349 if (e)
350 address = strndupa(rvalue, e - rvalue);
351 else
352 address = rvalue;
60f067b4 353
5eef597e 354 r = in_addr_from_string_auto(address, &f, &buffer);
60f067b4
JS
355 if (r < 0) {
356 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
357 "Destination is invalid, ignoring assignment: %s", address);
358 return 0;
359 }
360
361 /* prefixlen */
362 if (e) {
363 unsigned i;
364
365 r = safe_atou(e + 1, &i);
366 if (r < 0) {
367 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
5eef597e 368 "Route destination prefix length is invalid, ignoring assignment: %s", e + 1);
60f067b4
JS
369 return 0;
370 }
371
372 n->dst_prefixlen = (unsigned char) i;
373 } else {
374 switch (n->family) {
375 case AF_INET:
376 n->dst_prefixlen = 32;
377 break;
378 case AF_INET6:
379 n->dst_prefixlen = 128;
380 break;
381 }
382 }
383
5eef597e
MP
384 n->family = f;
385 n->dst_addr = buffer;
386 n = NULL;
387
388 return 0;
389}
390
391int config_parse_route_priority(const char *unit,
392 const char *filename,
393 unsigned line,
394 const char *section,
395 unsigned section_line,
396 const char *lvalue,
397 int ltype,
398 const char *rvalue,
399 void *data,
400 void *userdata) {
401 Network *network = userdata;
402 _cleanup_route_free_ Route *n = NULL;
403 int r;
404
405 assert(filename);
406 assert(section);
407 assert(lvalue);
408 assert(rvalue);
409 assert(data);
410
411 r = route_new_static(network, section_line, &n);
412 if (r < 0)
413 return r;
414
415 r = config_parse_unsigned(unit, filename, line, section,
416 section_line, lvalue, ltype,
417 rvalue, &n->metrics, userdata);
418 if (r < 0)
419 return r;
420
60f067b4
JS
421 n = NULL;
422
423 return 0;
424}