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