]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-route.c
network: introduce route_full_hash_ops
[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 "missing_network.h"
9 #include "netlink-util.h"
10 #include "networkd-ipv4ll.h"
11 #include "networkd-manager.h"
12 #include "networkd-route.h"
13 #include "parse-util.h"
14 #include "set.h"
15 #include "string-table.h"
16 #include "string-util.h"
17 #include "strxcpyx.h"
18 #include "sysctl-util.h"
19 #include "util.h"
20
21 #define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
22
23 static unsigned routes_max(void) {
24 static thread_local unsigned cached = 0;
25
26 _cleanup_free_ char *s4 = NULL, *s6 = NULL;
27 unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
28
29 if (cached > 0)
30 return cached;
31
32 if (sysctl_read("net/ipv4/route/max_size", &s4) >= 0) {
33 truncate_nl(s4);
34 if (safe_atou(s4, &val4) >= 0 &&
35 val4 == 2147483647U)
36 /* This is the default "no limit" value in the kernel */
37 val4 = ROUTES_DEFAULT_MAX_PER_FAMILY;
38 }
39
40 if (sysctl_read("net/ipv6/route/max_size", &s6) >= 0) {
41 truncate_nl(s6);
42 (void) safe_atou(s6, &val6);
43 }
44
45 cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) +
46 MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6);
47 return cached;
48 }
49
50 int route_new(Route **ret) {
51 _cleanup_(route_freep) Route *route = NULL;
52
53 route = new(Route, 1);
54 if (!route)
55 return -ENOMEM;
56
57 *route = (Route) {
58 .family = AF_UNSPEC,
59 .scope = RT_SCOPE_UNIVERSE,
60 .protocol = RTPROT_UNSPEC,
61 .type = RTN_UNICAST,
62 .table = RT_TABLE_MAIN,
63 .lifetime = USEC_INFINITY,
64 .quickack = -1,
65 .fast_open_no_cookie = -1,
66 .gateway_onlink = -1,
67 .ttl_propagate = -1,
68 };
69
70 *ret = TAKE_PTR(route);
71
72 return 0;
73 }
74
75 static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
76 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
77 _cleanup_(route_freep) Route *route = NULL;
78 int r;
79
80 assert(network);
81 assert(ret);
82 assert(!!filename == (section_line > 0));
83
84 if (filename) {
85 r = network_config_section_new(filename, section_line, &n);
86 if (r < 0)
87 return r;
88
89 route = hashmap_get(network->routes_by_section, n);
90 if (route) {
91 *ret = TAKE_PTR(route);
92
93 return 0;
94 }
95 }
96
97 if (network->n_static_routes >= routes_max())
98 return -E2BIG;
99
100 r = route_new(&route);
101 if (r < 0)
102 return r;
103
104 route->protocol = RTPROT_STATIC;
105 route->network = network;
106 LIST_PREPEND(routes, network->static_routes, route);
107 network->n_static_routes++;
108
109 if (filename) {
110 route->section = TAKE_PTR(n);
111
112 r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops);
113 if (r < 0)
114 return r;
115
116 r = hashmap_put(network->routes_by_section, route->section, route);
117 if (r < 0)
118 return r;
119 }
120
121 *ret = TAKE_PTR(route);
122
123 return 0;
124 }
125
126 void route_free(Route *route) {
127 if (!route)
128 return;
129
130 if (route->network) {
131 LIST_REMOVE(routes, route->network->static_routes, route);
132
133 assert(route->network->n_static_routes > 0);
134 route->network->n_static_routes--;
135
136 if (route->section)
137 hashmap_remove(route->network->routes_by_section, route->section);
138 }
139
140 network_config_section_free(route->section);
141
142 if (route->link) {
143 set_remove(route->link->routes, route);
144 set_remove(route->link->routes_foreign, route);
145 }
146
147 sd_event_source_unref(route->expire);
148
149 free(route);
150 }
151
152 static void route_hash_func(const Route *route, struct siphash *state) {
153 assert(route);
154
155 siphash24_compress(&route->family, sizeof(route->family), state);
156
157 switch (route->family) {
158 case AF_INET:
159 case AF_INET6:
160 /* Equality of routes are given by the 4-touple
161 (dst_prefix,dst_prefixlen,tos,priority,table) */
162 siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
163 siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
164 siphash24_compress(&route->tos, sizeof(route->tos), state);
165 siphash24_compress(&route->priority, sizeof(route->priority), state);
166 siphash24_compress(&route->table, sizeof(route->table), state);
167
168 break;
169 default:
170 /* treat any other address family as AF_UNSPEC */
171 break;
172 }
173 }
174
175 static int route_compare_func(const Route *a, const Route *b) {
176 int r;
177
178 r = CMP(a->family, b->family);
179 if (r != 0)
180 return r;
181
182 switch (a->family) {
183 case AF_INET:
184 case AF_INET6:
185 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
186 if (r != 0)
187 return r;
188
189 r = CMP(a->tos, b->tos);
190 if (r != 0)
191 return r;
192
193 r = CMP(a->priority, b->priority);
194 if (r != 0)
195 return r;
196
197 r = CMP(a->table, b->table);
198 if (r != 0)
199 return r;
200
201 return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
202 default:
203 /* treat any other address family as AF_UNSPEC */
204 return 0;
205 }
206 }
207
208 DEFINE_PRIVATE_HASH_OPS(route_hash_ops, Route, route_hash_func, route_compare_func);
209
210 static void route_full_hash_func(const Route *route, struct siphash *state) {
211 assert(route);
212
213 siphash24_compress(&route->family, sizeof(route->family), state);
214
215 switch (route->family) {
216 case AF_INET:
217 case AF_INET6:
218 siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->family), state);
219 siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
220 siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
221 siphash24_compress(&route->src, FAMILY_ADDRESS_SIZE(route->family), state);
222 siphash24_compress(&route->src_prefixlen, sizeof(route->src_prefixlen), state);
223 siphash24_compress(&route->prefsrc, FAMILY_ADDRESS_SIZE(route->family), state);
224
225 siphash24_compress(&route->tos, sizeof(route->tos), state);
226 siphash24_compress(&route->priority, sizeof(route->priority), state);
227 siphash24_compress(&route->table, sizeof(route->table), state);
228 siphash24_compress(&route->protocol, sizeof(route->protocol), state);
229 siphash24_compress(&route->scope, sizeof(route->scope), state);
230 siphash24_compress(&route->type, sizeof(route->type), state);
231
232 break;
233 default:
234 /* treat any other address family as AF_UNSPEC */
235 break;
236 }
237 }
238
239 static int route_full_compare_func(const Route *a, const Route *b) {
240 int r;
241
242 r = CMP(a->family, b->family);
243 if (r != 0)
244 return r;
245
246 switch (a->family) {
247 case AF_INET:
248 case AF_INET6:
249 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
250 if (r != 0)
251 return r;
252
253 r = CMP(a->src_prefixlen, b->src_prefixlen);
254 if (r != 0)
255 return r;
256
257 r = CMP(a->tos, b->tos);
258 if (r != 0)
259 return r;
260
261 r = CMP(a->priority, b->priority);
262 if (r != 0)
263 return r;
264
265 r = CMP(a->table, b->table);
266 if (r != 0)
267 return r;
268
269 r = CMP(a->protocol, b->protocol);
270 if (r != 0)
271 return r;
272
273 r = CMP(a->scope, b->scope);
274 if (r != 0)
275 return r;
276
277 r = CMP(a->type, b->type);
278 if (r != 0)
279 return r;
280
281 r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
282 if (r != 0)
283 return r;
284
285 r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
286 if (r != 0)
287 return r;
288
289 r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
290 if (r != 0)
291 return r;
292
293 return memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
294 default:
295 /* treat any other address family as AF_UNSPEC */
296 return 0;
297 }
298 }
299
300 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
301 route_full_hash_ops,
302 Route,
303 route_full_hash_func,
304 route_full_compare_func,
305 route_free);
306
307 bool route_equal(Route *r1, Route *r2) {
308 if (r1 == r2)
309 return true;
310
311 if (!r1 || !r2)
312 return false;
313
314 return route_compare_func(r1, r2) == 0;
315 }
316
317 int route_get(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 Route route, *existing;
327
328 assert(link);
329 assert(dst);
330
331 route = (Route) {
332 .family = family,
333 .dst = *dst,
334 .dst_prefixlen = dst_prefixlen,
335 .tos = tos,
336 .priority = priority,
337 .table = table,
338 };
339
340 existing = set_get(link->routes, &route);
341 if (existing) {
342 if (ret)
343 *ret = existing;
344 return 1;
345 }
346
347 existing = set_get(link->routes_foreign, &route);
348 if (existing) {
349 if (ret)
350 *ret = existing;
351 return 0;
352 }
353
354 return -ENOENT;
355 }
356
357 static int route_add_internal(
358 Link *link,
359 Set **routes,
360 int family,
361 const union in_addr_union *dst,
362 unsigned char dst_prefixlen,
363 unsigned char tos,
364 uint32_t priority,
365 uint32_t table,
366 Route **ret) {
367
368 _cleanup_(route_freep) Route *route = NULL;
369 int r;
370
371 assert(link);
372 assert(routes);
373 assert(dst);
374
375 r = route_new(&route);
376 if (r < 0)
377 return r;
378
379 route->family = family;
380 route->dst = *dst;
381 route->dst_prefixlen = dst_prefixlen;
382 route->tos = tos;
383 route->priority = priority;
384 route->table = table;
385
386 r = set_ensure_allocated(routes, &route_hash_ops);
387 if (r < 0)
388 return r;
389
390 r = set_put(*routes, route);
391 if (r < 0)
392 return r;
393
394 route->link = link;
395
396 if (ret)
397 *ret = route;
398
399 route = NULL;
400
401 return 0;
402 }
403
404 int route_add_foreign(
405 Link *link,
406 int family,
407 const union in_addr_union *dst,
408 unsigned char dst_prefixlen,
409 unsigned char tos,
410 uint32_t priority,
411 uint32_t table,
412 Route **ret) {
413
414 return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret);
415 }
416
417 int route_add(Link *link,
418 int family,
419 const union in_addr_union *dst,
420 unsigned char dst_prefixlen,
421 unsigned char tos,
422 uint32_t priority,
423 uint32_t table,
424 Route **ret) {
425
426 Route *route;
427 int r;
428
429 r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route);
430 if (r == -ENOENT) {
431 /* Route does not exist, create a new one */
432 r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route);
433 if (r < 0)
434 return r;
435 } else if (r == 0) {
436 /* Take over a foreign route */
437 r = set_ensure_allocated(&link->routes, &route_hash_ops);
438 if (r < 0)
439 return r;
440
441 r = set_put(link->routes, route);
442 if (r < 0)
443 return r;
444
445 set_remove(link->routes_foreign, route);
446 } else if (r == 1) {
447 /* Route exists, do nothing */
448 ;
449 } else
450 return r;
451
452 if (ret)
453 *ret = route;
454
455 return 0;
456 }
457
458 void route_update(Route *route,
459 const union in_addr_union *src,
460 unsigned char src_prefixlen,
461 const union in_addr_union *gw,
462 const union in_addr_union *prefsrc,
463 unsigned char scope,
464 unsigned char protocol,
465 unsigned char type) {
466
467 assert(route);
468 assert(src || src_prefixlen == 0);
469
470 route->src = src ? *src : IN_ADDR_NULL;
471 route->src_prefixlen = src_prefixlen;
472 route->gw = gw ? *gw : IN_ADDR_NULL;
473 route->prefsrc = prefsrc ? *prefsrc : IN_ADDR_NULL;
474 route->scope = scope;
475 route->protocol = protocol;
476 route->type = type;
477 }
478
479 static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
480 int r;
481
482 assert(m);
483 assert(link);
484 assert(link->ifname);
485
486 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
487 return 1;
488
489 r = sd_netlink_message_get_errno(m);
490 if (r < 0 && r != -ESRCH)
491 log_link_warning_errno(link, r, "Could not drop route: %m");
492
493 return 1;
494 }
495
496 int route_remove(Route *route, Link *link,
497 link_netlink_message_handler_t callback) {
498
499 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
500 int r;
501
502 assert(link);
503 assert(link->manager);
504 assert(link->manager->rtnl);
505 assert(link->ifindex > 0);
506 assert(IN_SET(route->family, AF_INET, AF_INET6));
507
508 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
509 RTM_DELROUTE, route->family,
510 route->protocol);
511 if (r < 0)
512 return log_link_error_errno(link, r, "Could not create RTM_DELROUTE message: %m");
513
514 if (DEBUG_LOGGING) {
515 _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
516 char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
517
518 if (!in_addr_is_null(route->family, &route->dst)) {
519 (void) in_addr_to_string(route->family, &route->dst, &dst);
520 (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen);
521 }
522 if (!in_addr_is_null(route->family, &route->src))
523 (void) in_addr_to_string(route->family, &route->src, &src);
524 if (!in_addr_is_null(route->family, &route->gw))
525 (void) in_addr_to_string(route->family, &route->gw, &gw);
526 if (!in_addr_is_null(route->family, &route->prefsrc))
527 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
528
529 log_link_debug(link, "Removing route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
530 strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc),
531 format_route_scope(route->scope, scope, sizeof(scope)),
532 format_route_table(route->table, table, sizeof(table)),
533 format_route_protocol(route->protocol, protocol, sizeof(protocol)),
534 strna(route_type_to_string(route->type)));
535 }
536
537 if (in_addr_is_null(route->family, &route->gw) == 0) {
538 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
539 if (r < 0)
540 return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
541 }
542
543 if (route->dst_prefixlen) {
544 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
545 if (r < 0)
546 return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
547
548 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
549 if (r < 0)
550 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
551 }
552
553 if (route->src_prefixlen) {
554 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
555 if (r < 0)
556 return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
557
558 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
559 if (r < 0)
560 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
561 }
562
563 if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
564 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
565 if (r < 0)
566 return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
567 }
568
569 r = sd_rtnl_message_route_set_scope(req, route->scope);
570 if (r < 0)
571 return log_link_error_errno(link, r, "Could not set scope: %m");
572
573 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
574 if (r < 0)
575 return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
576
577 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
578 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
579 if (r < 0)
580 return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
581 }
582
583 r = netlink_call_async(link->manager->rtnl, NULL, req,
584 callback ?: route_remove_handler,
585 link_netlink_destroy_callback, link);
586 if (r < 0)
587 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
588
589 link_ref(link);
590
591 return 0;
592 }
593
594 int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
595 Route *route = userdata;
596 int r;
597
598 assert(route);
599
600 r = route_remove(route, route->link, NULL);
601 if (r < 0)
602 log_warning_errno(r, "Could not remove route: %m");
603 else
604 route_free(route);
605
606 return 1;
607 }
608
609 int route_configure(
610 Route *route,
611 Link *link,
612 link_netlink_message_handler_t callback) {
613
614 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
615 _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
616 usec_t lifetime;
617 int r;
618
619 assert(link);
620 assert(link->manager);
621 assert(link->manager->rtnl);
622 assert(link->ifindex > 0);
623 assert(IN_SET(route->family, AF_INET, AF_INET6));
624 assert(callback);
625
626 if (route->family == AF_INET6 && link_sysctl_ipv6_enabled(link) == 0) {
627 log_link_warning(link, "An IPv6 route is requested, but IPv6 is disabled by sysctl, ignoring.");
628 return 0;
629 }
630
631 if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 &&
632 set_size(link->routes) >= routes_max())
633 return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
634 "Too many routes are configured, refusing: %m");
635
636 if (DEBUG_LOGGING) {
637 _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
638 char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
639
640 if (!in_addr_is_null(route->family, &route->dst)) {
641 (void) in_addr_to_string(route->family, &route->dst, &dst);
642 (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen);
643 }
644 if (!in_addr_is_null(route->family, &route->src))
645 (void) in_addr_to_string(route->family, &route->src, &src);
646 if (!in_addr_is_null(route->family, &route->gw))
647 (void) in_addr_to_string(route->family, &route->gw, &gw);
648 if (!in_addr_is_null(route->family, &route->prefsrc))
649 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
650
651 log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
652 strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc),
653 format_route_scope(route->scope, scope, sizeof(scope)),
654 format_route_table(route->table, table, sizeof(table)),
655 format_route_protocol(route->protocol, protocol, sizeof(protocol)),
656 strna(route_type_to_string(route->type)));
657 }
658
659 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
660 RTM_NEWROUTE, route->family,
661 route->protocol);
662 if (r < 0)
663 return log_link_error_errno(link, r, "Could not create RTM_NEWROUTE message: %m");
664
665 if (in_addr_is_null(route->family, &route->gw) == 0) {
666 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
667 if (r < 0)
668 return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
669
670 r = sd_rtnl_message_route_set_family(req, route->family);
671 if (r < 0)
672 return log_link_error_errno(link, r, "Could not set route family: %m");
673 }
674
675 if (route->dst_prefixlen) {
676 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
677 if (r < 0)
678 return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
679
680 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
681 if (r < 0)
682 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
683 }
684
685 if (route->src_prefixlen) {
686 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
687 if (r < 0)
688 return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
689
690 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
691 if (r < 0)
692 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
693 }
694
695 if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
696 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
697 if (r < 0)
698 return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
699 }
700
701 r = sd_rtnl_message_route_set_scope(req, route->scope);
702 if (r < 0)
703 return log_link_error_errno(link, r, "Could not set scope: %m");
704
705 if (route->gateway_onlink >= 0)
706 SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
707
708 r = sd_rtnl_message_route_set_flags(req, route->flags);
709 if (r < 0)
710 return log_link_error_errno(link, r, "Could not set flags: %m");
711
712 if (route->table != RT_TABLE_MAIN) {
713 if (route->table < 256) {
714 r = sd_rtnl_message_route_set_table(req, route->table);
715 if (r < 0)
716 return log_link_error_errno(link, r, "Could not set route table: %m");
717 } else {
718 r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
719 if (r < 0)
720 return log_link_error_errno(link, r, "Could not set route table: %m");
721
722 /* Table attribute to allow more than 256. */
723 r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
724 if (r < 0)
725 return log_link_error_errno(link, r, "Could not append RTA_TABLE attribute: %m");
726 }
727 }
728
729 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
730 if (r < 0)
731 return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
732
733 r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
734 if (r < 0)
735 return log_link_error_errno(link, r, "Could not append RTA_PREF attribute: %m");
736
737 if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
738 r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
739 DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
740 if (r < 0)
741 return log_link_error_errno(link, r, "Could not append RTA_EXPIRES attribute: %m");
742 }
743
744 r = sd_rtnl_message_route_set_type(req, route->type);
745 if (r < 0)
746 return log_link_error_errno(link, r, "Could not set route type: %m");
747
748 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
749 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
750 if (r < 0)
751 return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
752 }
753
754 if (route->ttl_propagate >= 0) {
755 r = sd_netlink_message_append_u8(req, RTA_TTL_PROPAGATE, route->ttl_propagate);
756 if (r < 0)
757 return log_link_error_errno(link, r, "Could not append RTA_TTL_PROPAGATE attribute: %m");
758 }
759
760 r = sd_netlink_message_open_container(req, RTA_METRICS);
761 if (r < 0)
762 return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
763
764 if (route->mtu > 0) {
765 r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
766 if (r < 0)
767 return log_link_error_errno(link, r, "Could not append RTAX_MTU attribute: %m");
768 }
769
770 if (route->initcwnd > 0) {
771 r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
772 if (r < 0)
773 return log_link_error_errno(link, r, "Could not append RTAX_INITCWND attribute: %m");
774 }
775
776 if (route->initrwnd > 0) {
777 r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
778 if (r < 0)
779 return log_link_error_errno(link, r, "Could not append RTAX_INITRWND attribute: %m");
780 }
781
782 if (route->quickack >= 0) {
783 r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
784 if (r < 0)
785 return log_link_error_errno(link, r, "Could not append RTAX_QUICKACK attribute: %m");
786 }
787
788 if (route->fast_open_no_cookie >= 0) {
789 r = sd_netlink_message_append_u32(req, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
790 if (r < 0)
791 return log_link_error_errno(link, r, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
792 }
793
794 r = sd_netlink_message_close_container(req);
795 if (r < 0)
796 return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
797
798 r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
799 link_netlink_destroy_callback, link);
800 if (r < 0)
801 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
802
803 link_ref(link);
804
805 lifetime = route->lifetime;
806
807 r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
808 if (r < 0)
809 return log_link_error_errno(link, r, "Could not add route: %m");
810
811 /* TODO: drop expiration handling once it can be pushed into the kernel */
812 route->lifetime = lifetime;
813
814 if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
815 r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
816 route->lifetime, 0, route_expire_handler, route);
817 if (r < 0)
818 return log_link_error_errno(link, r, "Could not arm expiration timer: %m");
819 }
820
821 sd_event_source_unref(route->expire);
822 route->expire = TAKE_PTR(expire);
823
824 return 1;
825 }
826
827 int network_add_ipv4ll_route(Network *network) {
828 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
829 int r;
830
831 assert(network);
832
833 if (!network->ipv4ll_route)
834 return 0;
835
836 /* IPv4LLRoute= is in [Network] section. */
837 r = route_new_static(network, NULL, 0, &n);
838 if (r < 0)
839 return r;
840
841 r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
842 if (r < 0)
843 return r;
844
845 n->family = AF_INET;
846 n->dst_prefixlen = 16;
847 n->scope = RT_SCOPE_LINK;
848 n->scope_set = true;
849 n->table_set = true;
850 n->priority = IPV4LL_ROUTE_METRIC;
851 n->protocol = RTPROT_STATIC;
852
853 TAKE_PTR(n);
854 return 0;
855 }
856
857 int network_add_default_route_on_device(Network *network) {
858 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
859 int r;
860
861 assert(network);
862
863 if (!network->default_route_on_device)
864 return 0;
865
866 /* DefaultRouteOnDevice= is in [Network] section. */
867 r = route_new_static(network, NULL, 0, &n);
868 if (r < 0)
869 return r;
870
871 r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
872 if (r < 0)
873 return r;
874
875 n->family = AF_INET;
876
877 TAKE_PTR(n);
878 return 0;
879 }
880
881 static const char * const route_type_table[__RTN_MAX] = {
882 [RTN_UNICAST] = "unicast",
883 [RTN_LOCAL] = "local",
884 [RTN_BROADCAST] = "broadcast",
885 [RTN_ANYCAST] = "anycast",
886 [RTN_MULTICAST] = "multicast",
887 [RTN_BLACKHOLE] = "blackhole",
888 [RTN_UNREACHABLE] = "unreachable",
889 [RTN_PROHIBIT] = "prohibit",
890 [RTN_THROW] = "throw",
891 [RTN_NAT] = "nat",
892 [RTN_XRESOLVE] = "xresolve",
893 };
894
895 assert_cc(__RTN_MAX <= UCHAR_MAX);
896 DEFINE_STRING_TABLE_LOOKUP(route_type, int);
897
898 static const char * const route_scope_table[] = {
899 [RT_SCOPE_UNIVERSE] = "global",
900 [RT_SCOPE_SITE] = "site",
901 [RT_SCOPE_LINK] = "link",
902 [RT_SCOPE_HOST] = "host",
903 [RT_SCOPE_NOWHERE] = "nowhere",
904 };
905
906 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int);
907
908 const char *format_route_scope(int scope, char *buf, size_t size) {
909 const char *s;
910 char *p = buf;
911
912 s = route_scope_to_string(scope);
913 if (s)
914 strpcpy(&p, size, s);
915 else
916 strpcpyf(&p, size, "%d", scope);
917
918 return buf;
919 }
920
921 static const char * const route_table_table[] = {
922 [RT_TABLE_DEFAULT] = "default",
923 [RT_TABLE_MAIN] = "main",
924 [RT_TABLE_LOCAL] = "local",
925 };
926
927 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
928
929 const char *format_route_table(int table, char *buf, size_t size) {
930 const char *s;
931 char *p = buf;
932
933 s = route_table_to_string(table);
934 if (s)
935 strpcpy(&p, size, s);
936 else
937 strpcpyf(&p, size, "%d", table);
938
939 return buf;
940 }
941
942 static const char * const route_protocol_table[] = {
943 [RTPROT_KERNEL] = "kernel",
944 [RTPROT_BOOT] = "boot",
945 [RTPROT_STATIC] = "static",
946 };
947
948 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int);
949
950 static const char * const route_protocol_full_table[] = {
951 [RTPROT_REDIRECT] = "redirect",
952 [RTPROT_KERNEL] = "kernel",
953 [RTPROT_BOOT] = "boot",
954 [RTPROT_STATIC] = "static",
955 [RTPROT_GATED] = "gated",
956 [RTPROT_RA] = "ra",
957 [RTPROT_MRT] = "mrt",
958 [RTPROT_ZEBRA] = "zebra",
959 [RTPROT_BIRD] = "bird",
960 [RTPROT_DNROUTED] = "dnrouted",
961 [RTPROT_XORP] = "xorp",
962 [RTPROT_NTK] = "ntk",
963 [RTPROT_DHCP] = "dhcp",
964 [RTPROT_MROUTED] = "mrouted",
965 [RTPROT_BABEL] = "babel",
966 [RTPROT_BGP] = "bgp",
967 [RTPROT_ISIS] = "isis",
968 [RTPROT_OSPF] = "ospf",
969 [RTPROT_RIP] = "rip",
970 [RTPROT_EIGRP] = "eigrp",
971 };
972
973 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int);
974
975 const char *format_route_protocol(int protocol, char *buf, size_t size) {
976 const char *s;
977 char *p = buf;
978
979 s = route_protocol_full_to_string(protocol);
980 if (s)
981 strpcpy(&p, size, s);
982 else
983 strpcpyf(&p, size, "%d", protocol);
984
985 return buf;
986 }
987
988 int config_parse_gateway(
989 const char *unit,
990 const char *filename,
991 unsigned line,
992 const char *section,
993 unsigned section_line,
994 const char *lvalue,
995 int ltype,
996 const char *rvalue,
997 void *data,
998 void *userdata) {
999
1000 Network *network = userdata;
1001 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1002 int r;
1003
1004 assert(filename);
1005 assert(section);
1006 assert(lvalue);
1007 assert(rvalue);
1008 assert(data);
1009
1010 if (streq(section, "Network")) {
1011 /* we are not in an Route section, so treat
1012 * this as the special '0' section */
1013 r = route_new_static(network, NULL, 0, &n);
1014 } else
1015 r = route_new_static(network, filename, section_line, &n);
1016 if (r < 0)
1017 return r;
1018
1019 if (n->family == AF_UNSPEC)
1020 r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
1021 else
1022 r = in_addr_from_string(n->family, rvalue, &n->gw);
1023 if (r < 0) {
1024 log_syntax(unit, LOG_ERR, filename, line, r,
1025 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
1026 return 0;
1027 }
1028
1029 TAKE_PTR(n);
1030 return 0;
1031 }
1032
1033 int config_parse_preferred_src(
1034 const char *unit,
1035 const char *filename,
1036 unsigned line,
1037 const char *section,
1038 unsigned section_line,
1039 const char *lvalue,
1040 int ltype,
1041 const char *rvalue,
1042 void *data,
1043 void *userdata) {
1044
1045 Network *network = userdata;
1046 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1047 int r;
1048
1049 assert(filename);
1050 assert(section);
1051 assert(lvalue);
1052 assert(rvalue);
1053 assert(data);
1054
1055 r = route_new_static(network, filename, section_line, &n);
1056 if (r < 0)
1057 return r;
1058
1059 if (n->family == AF_UNSPEC)
1060 r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
1061 else
1062 r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
1063 if (r < 0) {
1064 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1065 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
1066 return 0;
1067 }
1068
1069 TAKE_PTR(n);
1070 return 0;
1071 }
1072
1073 int config_parse_destination(
1074 const char *unit,
1075 const char *filename,
1076 unsigned line,
1077 const char *section,
1078 unsigned section_line,
1079 const char *lvalue,
1080 int ltype,
1081 const char *rvalue,
1082 void *data,
1083 void *userdata) {
1084
1085 Network *network = userdata;
1086 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1087 union in_addr_union *buffer;
1088 unsigned char *prefixlen;
1089 int r;
1090
1091 assert(filename);
1092 assert(section);
1093 assert(lvalue);
1094 assert(rvalue);
1095 assert(data);
1096
1097 r = route_new_static(network, filename, section_line, &n);
1098 if (r < 0)
1099 return r;
1100
1101 if (streq(lvalue, "Destination")) {
1102 buffer = &n->dst;
1103 prefixlen = &n->dst_prefixlen;
1104 } else if (streq(lvalue, "Source")) {
1105 buffer = &n->src;
1106 prefixlen = &n->src_prefixlen;
1107 } else
1108 assert_not_reached(lvalue);
1109
1110 if (n->family == AF_UNSPEC)
1111 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
1112 else
1113 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
1114 if (r < 0) {
1115 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1116 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
1117 return 0;
1118 }
1119
1120 TAKE_PTR(n);
1121 return 0;
1122 }
1123
1124 int config_parse_route_priority(
1125 const char *unit,
1126 const char *filename,
1127 unsigned line,
1128 const char *section,
1129 unsigned section_line,
1130 const char *lvalue,
1131 int ltype,
1132 const char *rvalue,
1133 void *data,
1134 void *userdata) {
1135
1136 Network *network = userdata;
1137 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1138 int r;
1139
1140 assert(filename);
1141 assert(section);
1142 assert(lvalue);
1143 assert(rvalue);
1144 assert(data);
1145
1146 r = route_new_static(network, filename, section_line, &n);
1147 if (r < 0)
1148 return r;
1149
1150 r = safe_atou32(rvalue, &n->priority);
1151 if (r < 0) {
1152 log_syntax(unit, LOG_ERR, filename, line, r,
1153 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
1154 return 0;
1155 }
1156
1157 TAKE_PTR(n);
1158 return 0;
1159 }
1160
1161 int config_parse_route_scope(
1162 const char *unit,
1163 const char *filename,
1164 unsigned line,
1165 const char *section,
1166 unsigned section_line,
1167 const char *lvalue,
1168 int ltype,
1169 const char *rvalue,
1170 void *data,
1171 void *userdata) {
1172
1173 Network *network = userdata;
1174 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1175 int r;
1176
1177 assert(filename);
1178 assert(section);
1179 assert(lvalue);
1180 assert(rvalue);
1181 assert(data);
1182
1183 r = route_new_static(network, filename, section_line, &n);
1184 if (r < 0)
1185 return r;
1186
1187 r = route_scope_from_string(rvalue);
1188 if (r < 0) {
1189 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue);
1190 return 0;
1191 }
1192
1193 n->scope = r;
1194 n->scope_set = true;
1195 TAKE_PTR(n);
1196 return 0;
1197 }
1198
1199 int config_parse_route_table(
1200 const char *unit,
1201 const char *filename,
1202 unsigned line,
1203 const char *section,
1204 unsigned section_line,
1205 const char *lvalue,
1206 int ltype,
1207 const char *rvalue,
1208 void *data,
1209 void *userdata) {
1210
1211 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1212 Network *network = userdata;
1213 int r;
1214
1215 assert(filename);
1216 assert(section);
1217 assert(lvalue);
1218 assert(rvalue);
1219 assert(data);
1220
1221 r = route_new_static(network, filename, section_line, &n);
1222 if (r < 0)
1223 return r;
1224
1225 r = route_table_from_string(rvalue);
1226 if (r >= 0)
1227 n->table = r;
1228 else {
1229 r = safe_atou32(rvalue, &n->table);
1230 if (r < 0) {
1231 log_syntax(unit, LOG_ERR, filename, line, r,
1232 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
1233 return 0;
1234 }
1235 }
1236
1237 n->table_set = true;
1238 TAKE_PTR(n);
1239 return 0;
1240 }
1241
1242 int config_parse_gateway_onlink(
1243 const char *unit,
1244 const char *filename,
1245 unsigned line,
1246 const char *section,
1247 unsigned section_line,
1248 const char *lvalue,
1249 int ltype,
1250 const char *rvalue,
1251 void *data,
1252 void *userdata) {
1253
1254 Network *network = userdata;
1255 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1256 int r;
1257
1258 assert(filename);
1259 assert(section);
1260 assert(lvalue);
1261 assert(rvalue);
1262 assert(data);
1263
1264 r = route_new_static(network, filename, section_line, &n);
1265 if (r < 0)
1266 return r;
1267
1268 r = parse_boolean(rvalue);
1269 if (r < 0) {
1270 log_syntax(unit, LOG_ERR, filename, line, r,
1271 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
1272 return 0;
1273 }
1274
1275 n->gateway_onlink = r;
1276
1277 TAKE_PTR(n);
1278 return 0;
1279 }
1280
1281 int config_parse_ipv6_route_preference(
1282 const char *unit,
1283 const char *filename,
1284 unsigned line,
1285 const char *section,
1286 unsigned section_line,
1287 const char *lvalue,
1288 int ltype,
1289 const char *rvalue,
1290 void *data,
1291 void *userdata) {
1292
1293 Network *network = userdata;
1294 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1295 int r;
1296
1297 r = route_new_static(network, filename, section_line, &n);
1298 if (r < 0)
1299 return r;
1300
1301 if (streq(rvalue, "low"))
1302 n->pref = ICMPV6_ROUTER_PREF_LOW;
1303 else if (streq(rvalue, "medium"))
1304 n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
1305 else if (streq(rvalue, "high"))
1306 n->pref = ICMPV6_ROUTER_PREF_HIGH;
1307 else {
1308 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route preference: %s", rvalue);
1309 return 0;
1310 }
1311
1312 TAKE_PTR(n);
1313 return 0;
1314 }
1315
1316 int config_parse_route_protocol(
1317 const char *unit,
1318 const char *filename,
1319 unsigned line,
1320 const char *section,
1321 unsigned section_line,
1322 const char *lvalue,
1323 int ltype,
1324 const char *rvalue,
1325 void *data,
1326 void *userdata) {
1327
1328 Network *network = userdata;
1329 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1330 int r;
1331
1332 r = route_new_static(network, filename, section_line, &n);
1333 if (r < 0)
1334 return r;
1335
1336 r = route_protocol_from_string(rvalue);
1337 if (r >= 0)
1338 n->protocol = r;
1339 else {
1340 r = safe_atou8(rvalue , &n->protocol);
1341 if (r < 0) {
1342 log_syntax(unit, LOG_ERR, filename, line, r,
1343 "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
1344 return 0;
1345 }
1346 }
1347
1348 TAKE_PTR(n);
1349 return 0;
1350 }
1351
1352 int config_parse_route_type(
1353 const char *unit,
1354 const char *filename,
1355 unsigned line,
1356 const char *section,
1357 unsigned section_line,
1358 const char *lvalue,
1359 int ltype,
1360 const char *rvalue,
1361 void *data,
1362 void *userdata) {
1363
1364 Network *network = userdata;
1365 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1366 int t, r;
1367
1368 r = route_new_static(network, filename, section_line, &n);
1369 if (r < 0)
1370 return r;
1371
1372 t = route_type_from_string(rvalue);
1373 if (t < 0) {
1374 log_syntax(unit, LOG_ERR, filename, line, 0,
1375 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
1376 return 0;
1377 }
1378
1379 n->type = (unsigned char) t;
1380
1381 TAKE_PTR(n);
1382 return 0;
1383 }
1384
1385 int config_parse_tcp_window(
1386 const char *unit,
1387 const char *filename,
1388 unsigned line,
1389 const char *section,
1390 unsigned section_line,
1391 const char *lvalue,
1392 int ltype,
1393 const char *rvalue,
1394 void *data,
1395 void *userdata) {
1396
1397 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1398 Network *network = userdata;
1399 uint64_t k;
1400 int r;
1401
1402 assert(filename);
1403 assert(section);
1404 assert(lvalue);
1405 assert(rvalue);
1406 assert(data);
1407
1408 r = route_new_static(network, filename, section_line, &n);
1409 if (r < 0)
1410 return r;
1411
1412 r = parse_size(rvalue, 1024, &k);
1413 if (r < 0) {
1414 log_syntax(unit, LOG_ERR, filename, line, r,
1415 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
1416 return 0;
1417 }
1418 if (k > UINT32_MAX) {
1419 log_syntax(unit, LOG_ERR, filename, line, 0,
1420 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
1421 return 0;
1422 }
1423
1424 if (streq(lvalue, "InitialCongestionWindow"))
1425 n->initcwnd = k;
1426 else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
1427 n->initrwnd = k;
1428 else
1429 assert_not_reached("Invalid TCP window type.");
1430
1431 TAKE_PTR(n);
1432 return 0;
1433 }
1434
1435 int config_parse_quickack(
1436 const char *unit,
1437 const char *filename,
1438 unsigned line,
1439 const char *section,
1440 unsigned section_line,
1441 const char *lvalue,
1442 int ltype,
1443 const char *rvalue,
1444 void *data,
1445 void *userdata) {
1446
1447 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1448 Network *network = userdata;
1449 int k, r;
1450
1451 assert(filename);
1452 assert(section);
1453 assert(lvalue);
1454 assert(rvalue);
1455 assert(data);
1456
1457 r = route_new_static(network, filename, section_line, &n);
1458 if (r < 0)
1459 return r;
1460
1461 k = parse_boolean(rvalue);
1462 if (k < 0) {
1463 log_syntax(unit, LOG_ERR, filename, line, k,
1464 "Failed to parse TCP quickack, ignoring: %s", rvalue);
1465 return 0;
1466 }
1467
1468 n->quickack = !!k;
1469 TAKE_PTR(n);
1470 return 0;
1471 }
1472
1473 int config_parse_fast_open_no_cookie(
1474 const char *unit,
1475 const char *filename,
1476 unsigned line,
1477 const char *section,
1478 unsigned section_line,
1479 const char *lvalue,
1480 int ltype,
1481 const char *rvalue,
1482 void *data,
1483 void *userdata) {
1484
1485 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1486 Network *network = userdata;
1487 int k, r;
1488
1489 assert(filename);
1490 assert(section);
1491 assert(lvalue);
1492 assert(rvalue);
1493 assert(data);
1494
1495 r = route_new_static(network, filename, section_line, &n);
1496 if (r < 0)
1497 return r;
1498
1499 k = parse_boolean(rvalue);
1500 if (k < 0) {
1501 log_syntax(unit, LOG_ERR, filename, line, k,
1502 "Failed to parse TCP fastopen no cookie, ignoring: %s", rvalue);
1503 return 0;
1504 }
1505
1506 n->fast_open_no_cookie = k;
1507 TAKE_PTR(n);
1508 return 0;
1509 }
1510
1511 int config_parse_route_mtu(
1512 const char *unit,
1513 const char *filename,
1514 unsigned line,
1515 const char *section,
1516 unsigned section_line,
1517 const char *lvalue,
1518 int ltype,
1519 const char *rvalue,
1520 void *data,
1521 void *userdata) {
1522
1523 Network *network = userdata;
1524 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1525 int r;
1526
1527 assert(filename);
1528 assert(section);
1529 assert(lvalue);
1530 assert(rvalue);
1531 assert(data);
1532
1533 r = route_new_static(network, filename, section_line, &n);
1534 if (r < 0)
1535 return r;
1536
1537 r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &n->mtu, userdata);
1538 if (r < 0)
1539 return r;
1540
1541 TAKE_PTR(n);
1542 return 0;
1543 }
1544
1545 int config_parse_route_ttl_propagate(
1546 const char *unit,
1547 const char *filename,
1548 unsigned line,
1549 const char *section,
1550 unsigned section_line,
1551 const char *lvalue,
1552 int ltype,
1553 const char *rvalue,
1554 void *data,
1555 void *userdata) {
1556
1557 Network *network = userdata;
1558 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1559 int r, k;
1560
1561 assert(filename);
1562 assert(section);
1563 assert(lvalue);
1564 assert(rvalue);
1565 assert(data);
1566
1567 r = route_new_static(network, filename, section_line, &n);
1568 if (r < 0)
1569 return r;
1570
1571 k = parse_boolean(rvalue);
1572 if (k < 0) {
1573 log_syntax(unit, LOG_ERR, filename, line, k,
1574 "Failed to parse TTLPropagate= value, ignoring: %s", rvalue);
1575 return 0;
1576 }
1577
1578 n->ttl_propagate = k;
1579
1580 TAKE_PTR(n);
1581 return 0;
1582 }
1583
1584 int route_section_verify(Route *route, Network *network) {
1585 if (section_is_invalid(route->section))
1586 return -EINVAL;
1587
1588 if (route->family == AF_UNSPEC) {
1589 assert(route->section);
1590
1591 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
1592 "%s: Route section without Gateway=, Destination=, Source=, "
1593 "or PreferredSource= field configured. "
1594 "Ignoring [Route] section from line %u.",
1595 route->section->filename, route->section->line);
1596 }
1597
1598 if (route->family != AF_INET6) {
1599 if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
1600 route->table = RT_TABLE_LOCAL;
1601
1602 if (!route->scope_set) {
1603 if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
1604 route->scope = RT_SCOPE_HOST;
1605 else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST))
1606 route->scope = RT_SCOPE_LINK;
1607 }
1608 }
1609
1610 if (network->n_static_addresses == 0 &&
1611 in_addr_is_null(route->family, &route->gw) == 0 &&
1612 route->gateway_onlink < 0) {
1613 log_warning("%s: Gateway= without static address configured. "
1614 "Enabling GatewayOnLink= option.",
1615 network->filename);
1616 route->gateway_onlink = true;
1617 }
1618
1619 return 0;
1620 }