]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-route.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / network / networkd-route.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2013 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <linux/icmpv6.h>
22
23 #include "alloc-util.h"
24 #include "conf-parser.h"
25 #include "in-addr-util.h"
26 #include "netlink-util.h"
27 #include "networkd-manager.h"
28 #include "networkd-route.h"
29 #include "parse-util.h"
30 #include "set.h"
31 #include "string-util.h"
32 #include "sysctl-util.h"
33 #include "util.h"
34
35 #define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
36
37 static unsigned routes_max(void) {
38 static thread_local unsigned cached = 0;
39
40 _cleanup_free_ char *s4 = NULL, *s6 = NULL;
41 unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
42
43 if (cached > 0)
44 return cached;
45
46 if (sysctl_read("net/ipv4/route/max_size", &s4) >= 0) {
47 truncate_nl(s4);
48 if (safe_atou(s4, &val4) >= 0 &&
49 val4 == 2147483647U)
50 /* This is the default "no limit" value in the kernel */
51 val4 = ROUTES_DEFAULT_MAX_PER_FAMILY;
52 }
53
54 if (sysctl_read("net/ipv6/route/max_size", &s6) >= 0) {
55 truncate_nl(s6);
56 (void) safe_atou(s6, &val6);
57 }
58
59 cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) +
60 MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6);
61 return cached;
62 }
63
64 int route_new(Route **ret) {
65 _cleanup_route_free_ Route *route = NULL;
66
67 route = new0(Route, 1);
68 if (!route)
69 return -ENOMEM;
70
71 route->family = AF_UNSPEC;
72 route->scope = RT_SCOPE_UNIVERSE;
73 route->protocol = RTPROT_UNSPEC;
74 route->type = RTN_UNICAST;
75 route->table = RT_TABLE_MAIN;
76 route->lifetime = USEC_INFINITY;
77
78 *ret = route;
79 route = NULL;
80
81 return 0;
82 }
83
84 int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
85 _cleanup_network_config_section_free_ NetworkConfigSection *n = NULL;
86 _cleanup_route_free_ Route *route = NULL;
87 int r;
88
89 assert(network);
90 assert(ret);
91 assert(!!filename == (section_line > 0));
92
93 if (filename) {
94 r = network_config_section_new(filename, section_line, &n);
95 if (r < 0)
96 return r;
97
98 route = hashmap_get(network->routes_by_section, n);
99 if (route) {
100 *ret = route;
101 route = NULL;
102
103 return 0;
104 }
105 }
106
107 if (network->n_static_routes >= routes_max())
108 return -E2BIG;
109
110 r = route_new(&route);
111 if (r < 0)
112 return r;
113
114 route->protocol = RTPROT_STATIC;
115
116 if (filename) {
117 route->section = n;
118 n = NULL;
119
120 r = hashmap_put(network->routes_by_section, route->section, route);
121 if (r < 0)
122 return r;
123 }
124
125 route->network = network;
126 LIST_PREPEND(routes, network->static_routes, route);
127 network->n_static_routes++;
128
129 *ret = route;
130 route = NULL;
131
132 return 0;
133 }
134
135 void route_free(Route *route) {
136 if (!route)
137 return;
138
139 if (route->network) {
140 LIST_REMOVE(routes, route->network->static_routes, route);
141
142 assert(route->network->n_static_routes > 0);
143 route->network->n_static_routes--;
144
145 if (route->section)
146 hashmap_remove(route->network->routes_by_section, route->section);
147 }
148
149 network_config_section_free(route->section);
150
151 if (route->link) {
152 set_remove(route->link->routes, route);
153 set_remove(route->link->routes_foreign, route);
154 }
155
156 sd_event_source_unref(route->expire);
157
158 free(route);
159 }
160
161 static void route_hash_func(const void *b, struct siphash *state) {
162 const Route *route = b;
163
164 assert(route);
165
166 siphash24_compress(&route->family, sizeof(route->family), state);
167
168 switch (route->family) {
169 case AF_INET:
170 case AF_INET6:
171 /* Equality of routes are given by the 4-touple
172 (dst_prefix,dst_prefixlen,tos,priority,table) */
173 siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
174 siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
175 siphash24_compress(&route->tos, sizeof(route->tos), state);
176 siphash24_compress(&route->priority, sizeof(route->priority), state);
177 siphash24_compress(&route->table, sizeof(route->table), state);
178
179 break;
180 default:
181 /* treat any other address family as AF_UNSPEC */
182 break;
183 }
184 }
185
186 static int route_compare_func(const void *_a, const void *_b) {
187 const Route *a = _a, *b = _b;
188
189 if (a->family < b->family)
190 return -1;
191 if (a->family > b->family)
192 return 1;
193
194 switch (a->family) {
195 case AF_INET:
196 case AF_INET6:
197 if (a->dst_prefixlen < b->dst_prefixlen)
198 return -1;
199 if (a->dst_prefixlen > b->dst_prefixlen)
200 return 1;
201
202 if (a->tos < b->tos)
203 return -1;
204 if (a->tos > b->tos)
205 return 1;
206
207 if (a->priority < b->priority)
208 return -1;
209 if (a->priority > b->priority)
210 return 1;
211
212 if (a->table < b->table)
213 return -1;
214 if (a->table > b->table)
215 return 1;
216
217 return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
218 default:
219 /* treat any other address family as AF_UNSPEC */
220 return 0;
221 }
222 }
223
224 static const struct hash_ops route_hash_ops = {
225 .hash = route_hash_func,
226 .compare = route_compare_func
227 };
228
229 int route_get(Link *link,
230 int family,
231 const union in_addr_union *dst,
232 unsigned char dst_prefixlen,
233 unsigned char tos,
234 uint32_t priority,
235 uint32_t table,
236 Route **ret) {
237
238 Route route, *existing;
239
240 assert(link);
241 assert(dst);
242
243 route = (Route) {
244 .family = family,
245 .dst = *dst,
246 .dst_prefixlen = dst_prefixlen,
247 .tos = tos,
248 .priority = priority,
249 .table = table,
250 };
251
252 existing = set_get(link->routes, &route);
253 if (existing) {
254 if (ret)
255 *ret = existing;
256 return 1;
257 }
258
259 existing = set_get(link->routes_foreign, &route);
260 if (existing) {
261 if (ret)
262 *ret = existing;
263 return 0;
264 }
265
266 return -ENOENT;
267 }
268
269 static int route_add_internal(
270 Link *link,
271 Set **routes,
272 int family,
273 const union in_addr_union *dst,
274 unsigned char dst_prefixlen,
275 unsigned char tos,
276 uint32_t priority,
277 uint32_t table,
278 Route **ret) {
279
280 _cleanup_route_free_ Route *route = NULL;
281 int r;
282
283 assert(link);
284 assert(routes);
285 assert(dst);
286
287 r = route_new(&route);
288 if (r < 0)
289 return r;
290
291 route->family = family;
292 route->dst = *dst;
293 route->dst_prefixlen = dst_prefixlen;
294 route->tos = tos;
295 route->priority = priority;
296 route->table = table;
297
298 r = set_ensure_allocated(routes, &route_hash_ops);
299 if (r < 0)
300 return r;
301
302 r = set_put(*routes, route);
303 if (r < 0)
304 return r;
305
306 route->link = link;
307
308 if (ret)
309 *ret = route;
310
311 route = NULL;
312
313 return 0;
314 }
315
316 int route_add_foreign(
317 Link *link,
318 int family,
319 const union in_addr_union *dst,
320 unsigned char dst_prefixlen,
321 unsigned char tos,
322 uint32_t priority,
323 uint32_t table,
324 Route **ret) {
325
326 return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
327 }
328
329 int route_add(
330 Link *link,
331 int family,
332 const union in_addr_union *dst,
333 unsigned char dst_prefixlen,
334 unsigned char tos,
335 uint32_t priority,
336 uint32_t table,
337 Route **ret) {
338
339 Route *route;
340 int r;
341
342 r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route);
343 if (r == -ENOENT) {
344 /* Route does not exist, create a new one */
345 r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route);
346 if (r < 0)
347 return r;
348 } else if (r == 0) {
349 /* Take over a foreign route */
350 r = set_ensure_allocated(&link->routes, &route_hash_ops);
351 if (r < 0)
352 return r;
353
354 r = set_put(link->routes, route);
355 if (r < 0)
356 return r;
357
358 set_remove(link->routes_foreign, route);
359 } else if (r == 1) {
360 /* Route exists, do nothing */
361 ;
362 } else
363 return r;
364
365 if (ret)
366 *ret = route;
367
368 return 0;
369 }
370
371 int route_update(Route *route,
372 const union in_addr_union *src,
373 unsigned char src_prefixlen,
374 const union in_addr_union *gw,
375 const union in_addr_union *prefsrc,
376 unsigned char scope,
377 unsigned char protocol,
378 unsigned char type) {
379
380 assert(route);
381 assert(src);
382 assert(gw);
383 assert(prefsrc);
384
385 route->src = *src;
386 route->src_prefixlen = src_prefixlen;
387 route->gw = *gw;
388 route->prefsrc = *prefsrc;
389 route->scope = scope;
390 route->protocol = protocol;
391 route->type = type;
392
393 return 0;
394 }
395
396 int route_remove(Route *route, Link *link,
397 sd_netlink_message_handler_t callback) {
398 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
399 int r;
400
401 assert(link);
402 assert(link->manager);
403 assert(link->manager->rtnl);
404 assert(link->ifindex > 0);
405 assert(IN_SET(route->family, AF_INET, AF_INET6));
406
407 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
408 RTM_DELROUTE, route->family,
409 route->protocol);
410 if (r < 0)
411 return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
412
413 if (!in_addr_is_null(route->family, &route->gw)) {
414 if (route->family == AF_INET)
415 r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
416 else if (route->family == AF_INET6)
417 r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
418 if (r < 0)
419 return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
420 }
421
422 if (route->dst_prefixlen) {
423 if (route->family == AF_INET)
424 r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
425 else if (route->family == AF_INET6)
426 r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
427 if (r < 0)
428 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
429
430 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
431 if (r < 0)
432 return log_error_errno(r, "Could not set destination prefix length: %m");
433 }
434
435 if (route->src_prefixlen) {
436 if (route->family == AF_INET)
437 r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
438 else if (route->family == AF_INET6)
439 r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
440 if (r < 0)
441 return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
442
443 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
444 if (r < 0)
445 return log_error_errno(r, "Could not set source prefix length: %m");
446 }
447
448 if (!in_addr_is_null(route->family, &route->prefsrc)) {
449 if (route->family == AF_INET)
450 r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
451 else if (route->family == AF_INET6)
452 r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
453 if (r < 0)
454 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
455 }
456
457 r = sd_rtnl_message_route_set_scope(req, route->scope);
458 if (r < 0)
459 return log_error_errno(r, "Could not set scope: %m");
460
461 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
462 if (r < 0)
463 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
464
465 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) {
466 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
467 if (r < 0)
468 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
469 }
470
471 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
472 if (r < 0)
473 return log_error_errno(r, "Could not send rtnetlink message: %m");
474
475 link_ref(link);
476
477 return 0;
478 }
479
480 static int route_expire_callback(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
481 Link *link = userdata;
482 int r;
483
484 assert(rtnl);
485 assert(m);
486 assert(link);
487 assert(link->ifname);
488
489 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
490 return 1;
491
492 r = sd_netlink_message_get_errno(m);
493 if (r < 0 && r != -EEXIST)
494 log_link_warning_errno(link, r, "could not remove route: %m");
495
496 return 1;
497 }
498
499 int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
500 Route *route = userdata;
501 int r;
502
503 assert(route);
504
505 r = route_remove(route, route->link, route_expire_callback);
506 if (r < 0)
507 log_warning_errno(r, "Could not remove route: %m");
508 else
509 route_free(route);
510
511 return 1;
512 }
513
514 int route_configure(
515 Route *route,
516 Link *link,
517 sd_netlink_message_handler_t callback) {
518
519 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
520 _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
521 usec_t lifetime;
522 int r;
523
524 assert(link);
525 assert(link->manager);
526 assert(link->manager->rtnl);
527 assert(link->ifindex > 0);
528 assert(IN_SET(route->family, AF_INET, AF_INET6));
529
530 if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 &&
531 set_size(link->routes) >= routes_max())
532 return -E2BIG;
533
534 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
535 RTM_NEWROUTE, route->family,
536 route->protocol);
537 if (r < 0)
538 return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
539
540 if (!in_addr_is_null(route->family, &route->gw)) {
541 if (route->family == AF_INET)
542 r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
543 else if (route->family == AF_INET6)
544 r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
545 if (r < 0)
546 return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
547
548 r = sd_rtnl_message_route_set_family(req, route->family);
549 if (r < 0)
550 return log_error_errno(r, "Could not set route family: %m");
551 }
552
553 if (route->dst_prefixlen) {
554 if (route->family == AF_INET)
555 r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
556 else if (route->family == AF_INET6)
557 r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
558 if (r < 0)
559 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
560
561 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
562 if (r < 0)
563 return log_error_errno(r, "Could not set destination prefix length: %m");
564 }
565
566 if (route->src_prefixlen) {
567 if (route->family == AF_INET)
568 r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
569 else if (route->family == AF_INET6)
570 r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
571 if (r < 0)
572 return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
573
574 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
575 if (r < 0)
576 return log_error_errno(r, "Could not set source prefix length: %m");
577 }
578
579 if (!in_addr_is_null(route->family, &route->prefsrc)) {
580 if (route->family == AF_INET)
581 r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
582 else if (route->family == AF_INET6)
583 r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
584 if (r < 0)
585 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
586 }
587
588 r = sd_rtnl_message_route_set_scope(req, route->scope);
589 if (r < 0)
590 return log_error_errno(r, "Could not set scope: %m");
591
592 r = sd_rtnl_message_route_set_flags(req, route->flags);
593 if (r < 0)
594 return log_error_errno(r, "Could not set flags: %m");
595
596 if (route->table != RT_TABLE_MAIN) {
597 if (route->table < 256) {
598 r = sd_rtnl_message_route_set_table(req, route->table);
599 if (r < 0)
600 return log_error_errno(r, "Could not set route table: %m");
601 } else {
602 r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
603 if (r < 0)
604 return log_error_errno(r, "Could not set route table: %m");
605
606 /* Table attribute to allow more than 256. */
607 r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
608 if (r < 0)
609 return log_error_errno(r, "Could not append RTA_TABLE attribute: %m");
610 }
611 }
612
613 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
614 if (r < 0)
615 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
616
617 r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
618 if (r < 0)
619 return log_error_errno(r, "Could not append RTA_PREF attribute: %m");
620
621 r = sd_rtnl_message_route_set_type(req, route->type);
622 if (r < 0)
623 return log_error_errno(r, "Could not set route type: %m");
624
625 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) {
626 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
627 if (r < 0)
628 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
629 }
630
631 r = sd_netlink_message_open_container(req, RTA_METRICS);
632 if (r < 0)
633 return log_error_errno(r, "Could not append RTA_METRICS attribute: %m");
634
635 if (route->mtu > 0) {
636 r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
637 if (r < 0)
638 return log_error_errno(r, "Could not append RTAX_MTU attribute: %m");
639 }
640
641 r = sd_netlink_message_close_container(req);
642 if (r < 0)
643 return log_error_errno(r, "Could not append RTA_METRICS attribute: %m");
644
645 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
646 if (r < 0)
647 return log_error_errno(r, "Could not send rtnetlink message: %m");
648
649 link_ref(link);
650
651 lifetime = route->lifetime;
652
653 r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
654 if (r < 0)
655 return log_error_errno(r, "Could not add route: %m");
656
657 /* TODO: drop expiration handling once it can be pushed into the kernel */
658 route->lifetime = lifetime;
659
660 if (route->lifetime != USEC_INFINITY) {
661 r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
662 route->lifetime, 0, route_expire_handler, route);
663 if (r < 0)
664 return log_error_errno(r, "Could not arm expiration timer: %m");
665 }
666
667 sd_event_source_unref(route->expire);
668 route->expire = expire;
669 expire = NULL;
670
671 return 0;
672 }
673
674 int config_parse_gateway(const char *unit,
675 const char *filename,
676 unsigned line,
677 const char *section,
678 unsigned section_line,
679 const char *lvalue,
680 int ltype,
681 const char *rvalue,
682 void *data,
683 void *userdata) {
684
685 Network *network = userdata;
686 _cleanup_route_free_ Route *n = NULL;
687 union in_addr_union buffer;
688 int r, f;
689
690 assert(filename);
691 assert(section);
692 assert(lvalue);
693 assert(rvalue);
694 assert(data);
695
696 if (streq(section, "Network")) {
697 /* we are not in an Route section, so treat
698 * this as the special '0' section */
699 r = route_new_static(network, NULL, 0, &n);
700 } else
701 r = route_new_static(network, filename, section_line, &n);
702
703 if (r < 0)
704 return r;
705
706 r = in_addr_from_string_auto(rvalue, &f, &buffer);
707 if (r < 0) {
708 log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue);
709 return 0;
710 }
711
712 n->family = f;
713 n->gw = buffer;
714 n = NULL;
715
716 return 0;
717 }
718
719 int config_parse_preferred_src(const char *unit,
720 const char *filename,
721 unsigned line,
722 const char *section,
723 unsigned section_line,
724 const char *lvalue,
725 int ltype,
726 const char *rvalue,
727 void *data,
728 void *userdata) {
729
730 Network *network = userdata;
731 _cleanup_route_free_ Route *n = NULL;
732 union in_addr_union buffer;
733 int r, f;
734
735 assert(filename);
736 assert(section);
737 assert(lvalue);
738 assert(rvalue);
739 assert(data);
740
741 r = route_new_static(network, filename, section_line, &n);
742 if (r < 0)
743 return r;
744
745 r = in_addr_from_string_auto(rvalue, &f, &buffer);
746 if (r < 0) {
747 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
748 "Preferred source is invalid, ignoring assignment: %s", rvalue);
749 return 0;
750 }
751
752 n->family = f;
753 n->prefsrc = buffer;
754 n = NULL;
755
756 return 0;
757 }
758
759 int config_parse_destination(const char *unit,
760 const char *filename,
761 unsigned line,
762 const char *section,
763 unsigned section_line,
764 const char *lvalue,
765 int ltype,
766 const char *rvalue,
767 void *data,
768 void *userdata) {
769
770 Network *network = userdata;
771 _cleanup_route_free_ Route *n = NULL;
772 union in_addr_union buffer;
773 unsigned char prefixlen;
774 int r;
775
776 assert(filename);
777 assert(section);
778 assert(lvalue);
779 assert(rvalue);
780 assert(data);
781
782 r = route_new_static(network, filename, section_line, &n);
783 if (r < 0)
784 return r;
785
786 r = in_addr_prefix_from_string(rvalue, AF_INET, &buffer, &prefixlen);
787 if (r < 0) {
788 r = in_addr_prefix_from_string(rvalue, AF_INET6, &buffer, &prefixlen);
789 if (r < 0) {
790 log_syntax(unit, LOG_ERR, filename, line, r,
791 "Route %s= prefix is invalid, ignoring assignment: %s",
792 lvalue, rvalue);
793 return 0;
794 }
795
796 n->family = AF_INET6;
797 } else
798 n->family = AF_INET;
799
800 if (streq(lvalue, "Destination")) {
801 n->dst = buffer;
802 n->dst_prefixlen = prefixlen;
803 } else if (streq(lvalue, "Source")) {
804 n->src = buffer;
805 n->src_prefixlen = prefixlen;
806 } else
807 assert_not_reached(lvalue);
808
809 n = NULL;
810
811 return 0;
812 }
813
814 int config_parse_route_priority(const char *unit,
815 const char *filename,
816 unsigned line,
817 const char *section,
818 unsigned section_line,
819 const char *lvalue,
820 int ltype,
821 const char *rvalue,
822 void *data,
823 void *userdata) {
824 Network *network = userdata;
825 _cleanup_route_free_ Route *n = NULL;
826 uint32_t k;
827 int r;
828
829 assert(filename);
830 assert(section);
831 assert(lvalue);
832 assert(rvalue);
833 assert(data);
834
835 r = route_new_static(network, filename, section_line, &n);
836 if (r < 0)
837 return r;
838
839 r = safe_atou32(rvalue, &k);
840 if (r < 0) {
841 log_syntax(unit, LOG_ERR, filename, line, r,
842 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
843 return 0;
844 }
845
846 n->priority = k;
847 n = NULL;
848
849 return 0;
850 }
851
852 int config_parse_route_scope(const char *unit,
853 const char *filename,
854 unsigned line,
855 const char *section,
856 unsigned section_line,
857 const char *lvalue,
858 int ltype,
859 const char *rvalue,
860 void *data,
861 void *userdata) {
862 Network *network = userdata;
863 _cleanup_route_free_ Route *n = NULL;
864 int r;
865
866 assert(filename);
867 assert(section);
868 assert(lvalue);
869 assert(rvalue);
870 assert(data);
871
872 r = route_new_static(network, filename, section_line, &n);
873 if (r < 0)
874 return r;
875
876 if (streq(rvalue, "host"))
877 n->scope = RT_SCOPE_HOST;
878 else if (streq(rvalue, "link"))
879 n->scope = RT_SCOPE_LINK;
880 else if (streq(rvalue, "global"))
881 n->scope = RT_SCOPE_UNIVERSE;
882 else {
883 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue);
884 return 0;
885 }
886
887 n = NULL;
888
889 return 0;
890 }
891
892 int config_parse_route_table(const char *unit,
893 const char *filename,
894 unsigned line,
895 const char *section,
896 unsigned section_line,
897 const char *lvalue,
898 int ltype,
899 const char *rvalue,
900 void *data,
901 void *userdata) {
902 _cleanup_route_free_ Route *n = NULL;
903 Network *network = userdata;
904 uint32_t k;
905 int r;
906
907 assert(filename);
908 assert(section);
909 assert(lvalue);
910 assert(rvalue);
911 assert(data);
912
913 r = route_new_static(network, filename, section_line, &n);
914 if (r < 0)
915 return r;
916
917 r = safe_atou32(rvalue, &k);
918 if (r < 0) {
919 log_syntax(unit, LOG_ERR, filename, line, r,
920 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
921 return 0;
922 }
923
924 n->table = k;
925
926 n = NULL;
927
928 return 0;
929 }
930
931 int config_parse_gateway_onlink(const char *unit,
932 const char *filename,
933 unsigned line,
934 const char *section,
935 unsigned section_line,
936 const char *lvalue,
937 int ltype,
938 const char *rvalue,
939 void *data,
940 void *userdata) {
941 Network *network = userdata;
942 _cleanup_route_free_ Route *n = NULL;
943 int r;
944
945 assert(filename);
946 assert(section);
947 assert(lvalue);
948 assert(rvalue);
949 assert(data);
950
951 r = route_new_static(network, filename, section_line, &n);
952 if (r < 0)
953 return r;
954
955 r = parse_boolean(rvalue);
956 if (r < 0) {
957 log_syntax(unit, LOG_ERR, filename, line, r,
958 "Could not parse gateway onlink \"%s\", ignoring assignment: %m", rvalue);
959 return 0;
960 }
961
962 SET_FLAG(n->flags, RTNH_F_ONLINK, r);
963 n = NULL;
964
965 return 0;
966 }
967
968 int config_parse_ipv6_route_preference(const char *unit,
969 const char *filename,
970 unsigned line,
971 const char *section,
972 unsigned section_line,
973 const char *lvalue,
974 int ltype,
975 const char *rvalue,
976 void *data,
977 void *userdata) {
978 Network *network = userdata;
979 _cleanup_route_free_ Route *n = NULL;
980 int r;
981
982 r = route_new_static(network, filename, section_line, &n);
983 if (r < 0)
984 return r;
985
986 if (streq(rvalue, "low"))
987 n->pref = ICMPV6_ROUTER_PREF_LOW;
988 else if (streq(rvalue, "medium"))
989 n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
990 else if (streq(rvalue, "high"))
991 n->pref = ICMPV6_ROUTER_PREF_HIGH;
992 else {
993 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route preference: %s", rvalue);
994 return 0;
995 }
996
997 n = NULL;
998
999 return 0;
1000 }
1001
1002 int config_parse_route_protocol(const char *unit,
1003 const char *filename,
1004 unsigned line,
1005 const char *section,
1006 unsigned section_line,
1007 const char *lvalue,
1008 int ltype,
1009 const char *rvalue,
1010 void *data,
1011 void *userdata) {
1012 Network *network = userdata;
1013 _cleanup_route_free_ Route *n = NULL;
1014 int r;
1015
1016 r = route_new_static(network, filename, section_line, &n);
1017 if (r < 0)
1018 return r;
1019
1020 if (streq(rvalue, "kernel"))
1021 n->protocol = RTPROT_KERNEL;
1022 else if (streq(rvalue, "boot"))
1023 n->protocol = RTPROT_BOOT;
1024 else if (streq(rvalue, "static"))
1025 n->protocol = RTPROT_STATIC;
1026 else {
1027 r = safe_atou8(rvalue , &n->protocol);
1028 if (r < 0) {
1029 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
1030 return 0;
1031 }
1032 }
1033
1034 n = NULL;
1035
1036 return 0;
1037 }
1038
1039 int config_parse_route_type(const char *unit,
1040 const char *filename,
1041 unsigned line,
1042 const char *section,
1043 unsigned section_line,
1044 const char *lvalue,
1045 int ltype,
1046 const char *rvalue,
1047 void *data,
1048 void *userdata) {
1049 Network *network = userdata;
1050 _cleanup_route_free_ Route *n = NULL;
1051 int r;
1052
1053 r = route_new_static(network, filename, section_line, &n);
1054 if (r < 0)
1055 return r;
1056
1057 if (streq(rvalue, "unicast"))
1058 n->type = RTN_UNICAST;
1059 else if (streq(rvalue, "blackhole"))
1060 n->type = RTN_BLACKHOLE;
1061 else if (streq(rvalue, "unreachable"))
1062 n->type = RTN_UNREACHABLE;
1063 else if (streq(rvalue, "prohibit"))
1064 n->type = RTN_PROHIBIT;
1065 else {
1066 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
1067 return 0;
1068 }
1069
1070 n = NULL;
1071
1072 return 0;
1073 }