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