]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-route.c
tree-wide: use TAKE_PTR() and TAKE_FD() macros
[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 route->quickack = -1;
78
79 *ret = TAKE_PTR(route);
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 = TAKE_PTR(route);
101
102 return 0;
103 }
104 }
105
106 if (network->n_static_routes >= routes_max())
107 return -E2BIG;
108
109 r = route_new(&route);
110 if (r < 0)
111 return r;
112
113 route->protocol = RTPROT_STATIC;
114
115 if (filename) {
116 route->section = TAKE_PTR(n);
117
118 r = hashmap_put(network->routes_by_section, route->section, route);
119 if (r < 0)
120 return r;
121 }
122
123 route->network = network;
124 LIST_PREPEND(routes, network->static_routes, route);
125 network->n_static_routes++;
126
127 *ret = TAKE_PTR(route);
128
129 return 0;
130 }
131
132 void route_free(Route *route) {
133 if (!route)
134 return;
135
136 if (route->network) {
137 LIST_REMOVE(routes, route->network->static_routes, route);
138
139 assert(route->network->n_static_routes > 0);
140 route->network->n_static_routes--;
141
142 if (route->section)
143 hashmap_remove(route->network->routes_by_section, route->section);
144 }
145
146 network_config_section_free(route->section);
147
148 if (route->link) {
149 set_remove(route->link->routes, route);
150 set_remove(route->link->routes_foreign, route);
151 }
152
153 sd_event_source_unref(route->expire);
154
155 free(route);
156 }
157
158 static void route_hash_func(const void *b, struct siphash *state) {
159 const Route *route = b;
160
161 assert(route);
162
163 siphash24_compress(&route->family, sizeof(route->family), state);
164
165 switch (route->family) {
166 case AF_INET:
167 case AF_INET6:
168 /* Equality of routes are given by the 4-touple
169 (dst_prefix,dst_prefixlen,tos,priority,table) */
170 siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
171 siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
172 siphash24_compress(&route->tos, sizeof(route->tos), state);
173 siphash24_compress(&route->priority, sizeof(route->priority), state);
174 siphash24_compress(&route->table, sizeof(route->table), state);
175
176 break;
177 default:
178 /* treat any other address family as AF_UNSPEC */
179 break;
180 }
181 }
182
183 static int route_compare_func(const void *_a, const void *_b) {
184 const Route *a = _a, *b = _b;
185
186 if (a->family < b->family)
187 return -1;
188 if (a->family > b->family)
189 return 1;
190
191 switch (a->family) {
192 case AF_INET:
193 case AF_INET6:
194 if (a->dst_prefixlen < b->dst_prefixlen)
195 return -1;
196 if (a->dst_prefixlen > b->dst_prefixlen)
197 return 1;
198
199 if (a->tos < b->tos)
200 return -1;
201 if (a->tos > b->tos)
202 return 1;
203
204 if (a->priority < b->priority)
205 return -1;
206 if (a->priority > b->priority)
207 return 1;
208
209 if (a->table < b->table)
210 return -1;
211 if (a->table > b->table)
212 return 1;
213
214 return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
215 default:
216 /* treat any other address family as AF_UNSPEC */
217 return 0;
218 }
219 }
220
221 static const struct hash_ops route_hash_ops = {
222 .hash = route_hash_func,
223 .compare = route_compare_func
224 };
225
226 int route_get(Link *link,
227 int family,
228 const union in_addr_union *dst,
229 unsigned char dst_prefixlen,
230 unsigned char tos,
231 uint32_t priority,
232 uint32_t table,
233 Route **ret) {
234
235 Route route, *existing;
236
237 assert(link);
238 assert(dst);
239
240 route = (Route) {
241 .family = family,
242 .dst = *dst,
243 .dst_prefixlen = dst_prefixlen,
244 .tos = tos,
245 .priority = priority,
246 .table = table,
247 };
248
249 existing = set_get(link->routes, &route);
250 if (existing) {
251 if (ret)
252 *ret = existing;
253 return 1;
254 }
255
256 existing = set_get(link->routes_foreign, &route);
257 if (existing) {
258 if (ret)
259 *ret = existing;
260 return 0;
261 }
262
263 return -ENOENT;
264 }
265
266 static int route_add_internal(
267 Link *link,
268 Set **routes,
269 int family,
270 const union in_addr_union *dst,
271 unsigned char dst_prefixlen,
272 unsigned char tos,
273 uint32_t priority,
274 uint32_t table,
275 Route **ret) {
276
277 _cleanup_route_free_ Route *route = NULL;
278 int r;
279
280 assert(link);
281 assert(routes);
282 assert(dst);
283
284 r = route_new(&route);
285 if (r < 0)
286 return r;
287
288 route->family = family;
289 route->dst = *dst;
290 route->dst_prefixlen = dst_prefixlen;
291 route->tos = tos;
292 route->priority = priority;
293 route->table = table;
294
295 r = set_ensure_allocated(routes, &route_hash_ops);
296 if (r < 0)
297 return r;
298
299 r = set_put(*routes, route);
300 if (r < 0)
301 return r;
302
303 route->link = link;
304
305 if (ret)
306 *ret = route;
307
308 route = NULL;
309
310 return 0;
311 }
312
313 int route_add_foreign(
314 Link *link,
315 int family,
316 const union in_addr_union *dst,
317 unsigned char dst_prefixlen,
318 unsigned char tos,
319 uint32_t priority,
320 uint32_t table,
321 Route **ret) {
322
323 return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
324 }
325
326 int route_add(
327 Link *link,
328 int family,
329 const union in_addr_union *dst,
330 unsigned char dst_prefixlen,
331 unsigned char tos,
332 uint32_t priority,
333 uint32_t table,
334 Route **ret) {
335
336 Route *route;
337 int r;
338
339 r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route);
340 if (r == -ENOENT) {
341 /* Route does not exist, create a new one */
342 r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route);
343 if (r < 0)
344 return r;
345 } else if (r == 0) {
346 /* Take over a foreign route */
347 r = set_ensure_allocated(&link->routes, &route_hash_ops);
348 if (r < 0)
349 return r;
350
351 r = set_put(link->routes, route);
352 if (r < 0)
353 return r;
354
355 set_remove(link->routes_foreign, route);
356 } else if (r == 1) {
357 /* Route exists, do nothing */
358 ;
359 } else
360 return r;
361
362 if (ret)
363 *ret = route;
364
365 return 0;
366 }
367
368 void route_update(Route *route,
369 const union in_addr_union *src,
370 unsigned char src_prefixlen,
371 const union in_addr_union *gw,
372 const union in_addr_union *prefsrc,
373 unsigned char scope,
374 unsigned char protocol,
375 unsigned char type) {
376
377 assert(route);
378 assert(src);
379 assert(gw);
380 assert(prefsrc);
381
382 route->src = *src;
383 route->src_prefixlen = src_prefixlen;
384 route->gw = *gw;
385 route->prefsrc = *prefsrc;
386 route->scope = scope;
387 route->protocol = protocol;
388 route->type = type;
389 }
390
391 int route_remove(Route *route, Link *link,
392 sd_netlink_message_handler_t callback) {
393 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
394 int r;
395
396 assert(link);
397 assert(link->manager);
398 assert(link->manager->rtnl);
399 assert(link->ifindex > 0);
400 assert(IN_SET(route->family, AF_INET, AF_INET6));
401
402 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
403 RTM_DELROUTE, route->family,
404 route->protocol);
405 if (r < 0)
406 return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
407
408 if (!in_addr_is_null(route->family, &route->gw)) {
409 if (route->family == AF_INET)
410 r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
411 else if (route->family == AF_INET6)
412 r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
413 if (r < 0)
414 return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
415 }
416
417 if (route->dst_prefixlen) {
418 if (route->family == AF_INET)
419 r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
420 else if (route->family == AF_INET6)
421 r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
422 if (r < 0)
423 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
424
425 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
426 if (r < 0)
427 return log_error_errno(r, "Could not set destination prefix length: %m");
428 }
429
430 if (route->src_prefixlen) {
431 if (route->family == AF_INET)
432 r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
433 else if (route->family == AF_INET6)
434 r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
435 if (r < 0)
436 return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
437
438 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
439 if (r < 0)
440 return log_error_errno(r, "Could not set source prefix length: %m");
441 }
442
443 if (!in_addr_is_null(route->family, &route->prefsrc)) {
444 if (route->family == AF_INET)
445 r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
446 else if (route->family == AF_INET6)
447 r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
448 if (r < 0)
449 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
450 }
451
452 r = sd_rtnl_message_route_set_scope(req, route->scope);
453 if (r < 0)
454 return log_error_errno(r, "Could not set scope: %m");
455
456 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
457 if (r < 0)
458 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
459
460 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) {
461 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
462 if (r < 0)
463 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
464 }
465
466 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
467 if (r < 0)
468 return log_error_errno(r, "Could not send rtnetlink message: %m");
469
470 link_ref(link);
471
472 return 0;
473 }
474
475 static int route_expire_callback(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
476 Link *link = userdata;
477 int r;
478
479 assert(rtnl);
480 assert(m);
481 assert(link);
482 assert(link->ifname);
483
484 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
485 return 1;
486
487 r = sd_netlink_message_get_errno(m);
488 if (r < 0 && r != -EEXIST)
489 log_link_warning_errno(link, r, "could not remove route: %m");
490
491 return 1;
492 }
493
494 int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
495 Route *route = userdata;
496 int r;
497
498 assert(route);
499
500 r = route_remove(route, route->link, route_expire_callback);
501 if (r < 0)
502 log_warning_errno(r, "Could not remove route: %m");
503 else
504 route_free(route);
505
506 return 1;
507 }
508
509 int route_configure(
510 Route *route,
511 Link *link,
512 sd_netlink_message_handler_t callback) {
513
514 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
515 _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
516 usec_t lifetime;
517 int r;
518
519 assert(link);
520 assert(link->manager);
521 assert(link->manager->rtnl);
522 assert(link->ifindex > 0);
523 assert(IN_SET(route->family, AF_INET, AF_INET6));
524
525 if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 &&
526 set_size(link->routes) >= routes_max())
527 return -E2BIG;
528
529 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
530 RTM_NEWROUTE, route->family,
531 route->protocol);
532 if (r < 0)
533 return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
534
535 if (!in_addr_is_null(route->family, &route->gw)) {
536 if (route->family == AF_INET)
537 r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
538 else if (route->family == AF_INET6)
539 r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
540 if (r < 0)
541 return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
542
543 r = sd_rtnl_message_route_set_family(req, route->family);
544 if (r < 0)
545 return log_error_errno(r, "Could not set route family: %m");
546 }
547
548 if (route->dst_prefixlen) {
549 if (route->family == AF_INET)
550 r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
551 else if (route->family == AF_INET6)
552 r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
553 if (r < 0)
554 return log_error_errno(r, "Could not append RTA_DST attribute: %m");
555
556 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
557 if (r < 0)
558 return log_error_errno(r, "Could not set destination prefix length: %m");
559 }
560
561 if (route->src_prefixlen) {
562 if (route->family == AF_INET)
563 r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
564 else if (route->family == AF_INET6)
565 r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
566 if (r < 0)
567 return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
568
569 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
570 if (r < 0)
571 return log_error_errno(r, "Could not set source prefix length: %m");
572 }
573
574 if (!in_addr_is_null(route->family, &route->prefsrc)) {
575 if (route->family == AF_INET)
576 r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
577 else if (route->family == AF_INET6)
578 r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
579 if (r < 0)
580 return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
581 }
582
583 r = sd_rtnl_message_route_set_scope(req, route->scope);
584 if (r < 0)
585 return log_error_errno(r, "Could not set scope: %m");
586
587 r = sd_rtnl_message_route_set_flags(req, route->flags);
588 if (r < 0)
589 return log_error_errno(r, "Could not set flags: %m");
590
591 if (route->table != RT_TABLE_MAIN) {
592 if (route->table < 256) {
593 r = sd_rtnl_message_route_set_table(req, route->table);
594 if (r < 0)
595 return log_error_errno(r, "Could not set route table: %m");
596 } else {
597 r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
598 if (r < 0)
599 return log_error_errno(r, "Could not set route table: %m");
600
601 /* Table attribute to allow more than 256. */
602 r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
603 if (r < 0)
604 return log_error_errno(r, "Could not append RTA_TABLE attribute: %m");
605 }
606 }
607
608 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
609 if (r < 0)
610 return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
611
612 r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
613 if (r < 0)
614 return log_error_errno(r, "Could not append RTA_PREF attribute: %m");
615
616 if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
617 r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
618 DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
619 if (r < 0)
620 return log_error_errno(r, "Could not append RTA_EXPIRES attribute: %m");
621 }
622
623 r = sd_rtnl_message_route_set_type(req, route->type);
624 if (r < 0)
625 return log_error_errno(r, "Could not set route type: %m");
626
627 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE)) {
628 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
629 if (r < 0)
630 return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
631 }
632
633 r = sd_netlink_message_open_container(req, RTA_METRICS);
634 if (r < 0)
635 return log_error_errno(r, "Could not append RTA_METRICS attribute: %m");
636
637 if (route->mtu > 0) {
638 r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
639 if (r < 0)
640 return log_error_errno(r, "Could not append RTAX_MTU attribute: %m");
641 }
642
643 if (route->initcwnd > 0) {
644 r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
645 if (r < 0)
646 return log_error_errno(r, "Could not append RTAX_INITCWND attribute: %m");
647 }
648
649 if (route->initrwnd > 0) {
650 r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
651 if (r < 0)
652 return log_error_errno(r, "Could not append RTAX_INITRWND attribute: %m");
653 }
654
655 if (route->quickack != -1) {
656 r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
657 if (r < 0)
658 return log_error_errno(r, "Could not append RTAX_QUICKACK attribute: %m");
659 }
660
661 r = sd_netlink_message_close_container(req);
662 if (r < 0)
663 return log_error_errno(r, "Could not append RTA_METRICS attribute: %m");
664
665 r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL);
666 if (r < 0)
667 return log_error_errno(r, "Could not send rtnetlink message: %m");
668
669 link_ref(link);
670
671 lifetime = route->lifetime;
672
673 r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
674 if (r < 0)
675 return log_error_errno(r, "Could not add route: %m");
676
677 /* TODO: drop expiration handling once it can be pushed into the kernel */
678 route->lifetime = lifetime;
679
680 if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
681 r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
682 route->lifetime, 0, route_expire_handler, route);
683 if (r < 0)
684 return log_error_errno(r, "Could not arm expiration timer: %m");
685 }
686
687 sd_event_source_unref(route->expire);
688 route->expire = TAKE_PTR(expire);
689
690 return 0;
691 }
692
693 int config_parse_gateway(const char *unit,
694 const char *filename,
695 unsigned line,
696 const char *section,
697 unsigned section_line,
698 const char *lvalue,
699 int ltype,
700 const char *rvalue,
701 void *data,
702 void *userdata) {
703
704 Network *network = userdata;
705 _cleanup_route_free_ Route *n = NULL;
706 union in_addr_union buffer;
707 int r, f;
708
709 assert(filename);
710 assert(section);
711 assert(lvalue);
712 assert(rvalue);
713 assert(data);
714
715 if (streq(section, "Network")) {
716 /* we are not in an Route section, so treat
717 * this as the special '0' section */
718 r = route_new_static(network, NULL, 0, &n);
719 } else
720 r = route_new_static(network, filename, section_line, &n);
721
722 if (r < 0)
723 return r;
724
725 r = in_addr_from_string_auto(rvalue, &f, &buffer);
726 if (r < 0) {
727 log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue);
728 return 0;
729 }
730
731 n->family = f;
732 n->gw = buffer;
733 n = NULL;
734
735 return 0;
736 }
737
738 int config_parse_preferred_src(const char *unit,
739 const char *filename,
740 unsigned line,
741 const char *section,
742 unsigned section_line,
743 const char *lvalue,
744 int ltype,
745 const char *rvalue,
746 void *data,
747 void *userdata) {
748
749 Network *network = userdata;
750 _cleanup_route_free_ Route *n = NULL;
751 union in_addr_union buffer;
752 int r, f;
753
754 assert(filename);
755 assert(section);
756 assert(lvalue);
757 assert(rvalue);
758 assert(data);
759
760 r = route_new_static(network, filename, section_line, &n);
761 if (r < 0)
762 return r;
763
764 r = in_addr_from_string_auto(rvalue, &f, &buffer);
765 if (r < 0) {
766 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
767 "Preferred source is invalid, ignoring assignment: %s", rvalue);
768 return 0;
769 }
770
771 n->family = f;
772 n->prefsrc = buffer;
773 n = NULL;
774
775 return 0;
776 }
777
778 int config_parse_destination(const char *unit,
779 const char *filename,
780 unsigned line,
781 const char *section,
782 unsigned section_line,
783 const char *lvalue,
784 int ltype,
785 const char *rvalue,
786 void *data,
787 void *userdata) {
788
789 Network *network = userdata;
790 _cleanup_route_free_ Route *n = NULL;
791 union in_addr_union buffer;
792 unsigned char prefixlen;
793 int r;
794
795 assert(filename);
796 assert(section);
797 assert(lvalue);
798 assert(rvalue);
799 assert(data);
800
801 r = route_new_static(network, filename, section_line, &n);
802 if (r < 0)
803 return r;
804
805 r = in_addr_prefix_from_string(rvalue, AF_INET, &buffer, &prefixlen);
806 if (r < 0) {
807 r = in_addr_prefix_from_string(rvalue, AF_INET6, &buffer, &prefixlen);
808 if (r < 0) {
809 log_syntax(unit, LOG_ERR, filename, line, r,
810 "Route %s= prefix is invalid, ignoring assignment: %s",
811 lvalue, rvalue);
812 return 0;
813 }
814
815 n->family = AF_INET6;
816 } else
817 n->family = AF_INET;
818
819 if (streq(lvalue, "Destination")) {
820 n->dst = buffer;
821 n->dst_prefixlen = prefixlen;
822 } else if (streq(lvalue, "Source")) {
823 n->src = buffer;
824 n->src_prefixlen = prefixlen;
825 } else
826 assert_not_reached(lvalue);
827
828 n = NULL;
829
830 return 0;
831 }
832
833 int config_parse_route_priority(const char *unit,
834 const char *filename,
835 unsigned line,
836 const char *section,
837 unsigned section_line,
838 const char *lvalue,
839 int ltype,
840 const char *rvalue,
841 void *data,
842 void *userdata) {
843 Network *network = userdata;
844 _cleanup_route_free_ Route *n = NULL;
845 uint32_t k;
846 int r;
847
848 assert(filename);
849 assert(section);
850 assert(lvalue);
851 assert(rvalue);
852 assert(data);
853
854 r = route_new_static(network, filename, section_line, &n);
855 if (r < 0)
856 return r;
857
858 r = safe_atou32(rvalue, &k);
859 if (r < 0) {
860 log_syntax(unit, LOG_ERR, filename, line, r,
861 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
862 return 0;
863 }
864
865 n->priority = k;
866 n = NULL;
867
868 return 0;
869 }
870
871 int config_parse_route_scope(const char *unit,
872 const char *filename,
873 unsigned line,
874 const char *section,
875 unsigned section_line,
876 const char *lvalue,
877 int ltype,
878 const char *rvalue,
879 void *data,
880 void *userdata) {
881 Network *network = userdata;
882 _cleanup_route_free_ Route *n = NULL;
883 int r;
884
885 assert(filename);
886 assert(section);
887 assert(lvalue);
888 assert(rvalue);
889 assert(data);
890
891 r = route_new_static(network, filename, section_line, &n);
892 if (r < 0)
893 return r;
894
895 if (streq(rvalue, "host"))
896 n->scope = RT_SCOPE_HOST;
897 else if (streq(rvalue, "link"))
898 n->scope = RT_SCOPE_LINK;
899 else if (streq(rvalue, "global"))
900 n->scope = RT_SCOPE_UNIVERSE;
901 else {
902 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue);
903 return 0;
904 }
905
906 n = NULL;
907
908 return 0;
909 }
910
911 int config_parse_route_table(const char *unit,
912 const char *filename,
913 unsigned line,
914 const char *section,
915 unsigned section_line,
916 const char *lvalue,
917 int ltype,
918 const char *rvalue,
919 void *data,
920 void *userdata) {
921 _cleanup_route_free_ Route *n = NULL;
922 Network *network = userdata;
923 uint32_t k;
924 int r;
925
926 assert(filename);
927 assert(section);
928 assert(lvalue);
929 assert(rvalue);
930 assert(data);
931
932 r = route_new_static(network, filename, section_line, &n);
933 if (r < 0)
934 return r;
935
936 r = safe_atou32(rvalue, &k);
937 if (r < 0) {
938 log_syntax(unit, LOG_ERR, filename, line, r,
939 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
940 return 0;
941 }
942
943 n->table = k;
944
945 n = NULL;
946
947 return 0;
948 }
949
950 int config_parse_gateway_onlink(const char *unit,
951 const char *filename,
952 unsigned line,
953 const char *section,
954 unsigned section_line,
955 const char *lvalue,
956 int ltype,
957 const char *rvalue,
958 void *data,
959 void *userdata) {
960 Network *network = userdata;
961 _cleanup_route_free_ Route *n = NULL;
962 int r;
963
964 assert(filename);
965 assert(section);
966 assert(lvalue);
967 assert(rvalue);
968 assert(data);
969
970 r = route_new_static(network, filename, section_line, &n);
971 if (r < 0)
972 return r;
973
974 r = parse_boolean(rvalue);
975 if (r < 0) {
976 log_syntax(unit, LOG_ERR, filename, line, r,
977 "Could not parse gateway onlink \"%s\", ignoring assignment: %m", rvalue);
978 return 0;
979 }
980
981 SET_FLAG(n->flags, RTNH_F_ONLINK, r);
982 n = NULL;
983
984 return 0;
985 }
986
987 int config_parse_ipv6_route_preference(const char *unit,
988 const char *filename,
989 unsigned line,
990 const char *section,
991 unsigned section_line,
992 const char *lvalue,
993 int ltype,
994 const char *rvalue,
995 void *data,
996 void *userdata) {
997 Network *network = userdata;
998 _cleanup_route_free_ Route *n = NULL;
999 int r;
1000
1001 r = route_new_static(network, filename, section_line, &n);
1002 if (r < 0)
1003 return r;
1004
1005 if (streq(rvalue, "low"))
1006 n->pref = ICMPV6_ROUTER_PREF_LOW;
1007 else if (streq(rvalue, "medium"))
1008 n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
1009 else if (streq(rvalue, "high"))
1010 n->pref = ICMPV6_ROUTER_PREF_HIGH;
1011 else {
1012 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route preference: %s", rvalue);
1013 return 0;
1014 }
1015
1016 n = NULL;
1017
1018 return 0;
1019 }
1020
1021 int config_parse_route_protocol(const char *unit,
1022 const char *filename,
1023 unsigned line,
1024 const char *section,
1025 unsigned section_line,
1026 const char *lvalue,
1027 int ltype,
1028 const char *rvalue,
1029 void *data,
1030 void *userdata) {
1031 Network *network = userdata;
1032 _cleanup_route_free_ Route *n = NULL;
1033 int r;
1034
1035 r = route_new_static(network, filename, section_line, &n);
1036 if (r < 0)
1037 return r;
1038
1039 if (streq(rvalue, "kernel"))
1040 n->protocol = RTPROT_KERNEL;
1041 else if (streq(rvalue, "boot"))
1042 n->protocol = RTPROT_BOOT;
1043 else if (streq(rvalue, "static"))
1044 n->protocol = RTPROT_STATIC;
1045 else {
1046 r = safe_atou8(rvalue , &n->protocol);
1047 if (r < 0) {
1048 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
1049 return 0;
1050 }
1051 }
1052
1053 n = NULL;
1054
1055 return 0;
1056 }
1057
1058 int config_parse_route_type(const char *unit,
1059 const char *filename,
1060 unsigned line,
1061 const char *section,
1062 unsigned section_line,
1063 const char *lvalue,
1064 int ltype,
1065 const char *rvalue,
1066 void *data,
1067 void *userdata) {
1068 Network *network = userdata;
1069 _cleanup_route_free_ Route *n = NULL;
1070 int r;
1071
1072 r = route_new_static(network, filename, section_line, &n);
1073 if (r < 0)
1074 return r;
1075
1076 if (streq(rvalue, "unicast"))
1077 n->type = RTN_UNICAST;
1078 else if (streq(rvalue, "blackhole"))
1079 n->type = RTN_BLACKHOLE;
1080 else if (streq(rvalue, "unreachable"))
1081 n->type = RTN_UNREACHABLE;
1082 else if (streq(rvalue, "prohibit"))
1083 n->type = RTN_PROHIBIT;
1084 else {
1085 log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
1086 return 0;
1087 }
1088
1089 n = NULL;
1090
1091 return 0;
1092 }
1093
1094 int config_parse_tcp_window(const char *unit,
1095 const char *filename,
1096 unsigned line,
1097 const char *section,
1098 unsigned section_line,
1099 const char *lvalue,
1100 int ltype,
1101 const char *rvalue,
1102 void *data,
1103 void *userdata) {
1104 _cleanup_route_free_ Route *n = NULL;
1105 Network *network = userdata;
1106 uint64_t k;
1107 int r;
1108
1109 assert(filename);
1110 assert(section);
1111 assert(lvalue);
1112 assert(rvalue);
1113 assert(data);
1114
1115 r = route_new_static(network, filename, section_line, &n);
1116 if (r < 0)
1117 return r;
1118
1119 r = parse_size(rvalue, 1024, &k);
1120 if (r < 0 || k > UINT32_MAX) {
1121 log_syntax(unit, LOG_ERR, filename, line, r,
1122 "Could not parse TCP %s \"%s\" bytes, ignoring assignment: %m", rvalue, lvalue);
1123 return 0;
1124 }
1125
1126 if (streq(lvalue, "InitialCongestionWindow"))
1127 n->initcwnd = k;
1128 else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
1129 n->initrwnd = k;
1130 else {
1131 log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse TCP %s: %s", lvalue, rvalue);
1132 return 0;
1133 }
1134
1135 n = NULL;
1136
1137 return 0;
1138 }
1139
1140 int config_parse_quickack(const char *unit,
1141 const char *filename,
1142 unsigned line,
1143 const char *section,
1144 unsigned section_line,
1145 const char *lvalue,
1146 int ltype,
1147 const char *rvalue,
1148 void *data,
1149 void *userdata) {
1150 _cleanup_route_free_ Route *n = NULL;
1151 Network *network = userdata;
1152 int k, r;
1153
1154 assert(filename);
1155 assert(section);
1156 assert(lvalue);
1157 assert(rvalue);
1158 assert(data);
1159
1160 r = route_new_static(network, filename, section_line, &n);
1161 if (r < 0)
1162 return r;
1163
1164 k = parse_boolean(rvalue);
1165 if (k < 0) {
1166 log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse TCP quickack, ignoring: %s", rvalue);
1167 return 0;
1168 }
1169
1170 n->quickack = !!k;
1171 n = NULL;
1172
1173 return 0;
1174 }