]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-route.c
Merge pull request #30284 from YHNdnzj/fstab-wantedby-defaultdeps
[thirdparty/systemd.git] / src / network / networkd-route.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <linux/icmpv6.h>
4 #include <linux/ipv6_route.h>
5 #include <linux/nexthop.h>
6
7 #include "alloc-util.h"
8 #include "event-util.h"
9 #include "netlink-util.h"
10 #include "networkd-address.h"
11 #include "networkd-ipv4ll.h"
12 #include "networkd-manager.h"
13 #include "networkd-network.h"
14 #include "networkd-nexthop.h"
15 #include "networkd-queue.h"
16 #include "networkd-route-util.h"
17 #include "networkd-route.h"
18 #include "parse-util.h"
19 #include "string-util.h"
20 #include "strv.h"
21 #include "vrf.h"
22 #include "wireguard.h"
23
24 int route_new(Route **ret) {
25 _cleanup_(route_freep) Route *route = NULL;
26
27 route = new(Route, 1);
28 if (!route)
29 return -ENOMEM;
30
31 *route = (Route) {
32 .family = AF_UNSPEC,
33 .scope = RT_SCOPE_UNIVERSE,
34 .protocol = RTPROT_UNSPEC,
35 .type = RTN_UNICAST,
36 .table = RT_TABLE_MAIN,
37 .lifetime_usec = USEC_INFINITY,
38 .quickack = -1,
39 .fast_open_no_cookie = -1,
40 .gateway_onlink = -1,
41 .ttl_propagate = -1,
42 };
43
44 *ret = TAKE_PTR(route);
45
46 return 0;
47 }
48
49 static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
50 _cleanup_(config_section_freep) ConfigSection *n = NULL;
51 _cleanup_(route_freep) Route *route = NULL;
52 int r;
53
54 assert(network);
55 assert(ret);
56 assert(filename);
57 assert(section_line > 0);
58
59 r = config_section_new(filename, section_line, &n);
60 if (r < 0)
61 return r;
62
63 route = hashmap_get(network->routes_by_section, n);
64 if (route) {
65 *ret = TAKE_PTR(route);
66 return 0;
67 }
68
69 if (hashmap_size(network->routes_by_section) >= routes_max())
70 return -E2BIG;
71
72 r = route_new(&route);
73 if (r < 0)
74 return r;
75
76 route->protocol = RTPROT_STATIC;
77 route->network = network;
78 route->section = TAKE_PTR(n);
79 route->source = NETWORK_CONFIG_SOURCE_STATIC;
80
81 r = hashmap_ensure_put(&network->routes_by_section, &config_section_hash_ops, route->section, route);
82 if (r < 0)
83 return r;
84
85 *ret = TAKE_PTR(route);
86 return 0;
87 }
88
89 Route *route_free(Route *route) {
90 if (!route)
91 return NULL;
92
93 if (route->network) {
94 assert(route->section);
95 hashmap_remove(route->network->routes_by_section, route->section);
96 }
97
98 config_section_free(route->section);
99
100 if (route->link)
101 set_remove(route->link->routes, route);
102
103 if (route->manager)
104 set_remove(route->manager->routes, route);
105
106 ordered_set_free_with_destructor(route->multipath_routes, multipath_route_free);
107
108 sd_event_source_disable_unref(route->expire);
109
110 free(route->tcp_congestion_control_algo);
111
112 return mfree(route);
113 }
114
115 static void route_hash_func(const Route *route, struct siphash *state) {
116 assert(route);
117
118 siphash24_compress(&route->family, sizeof(route->family), state);
119
120 switch (route->family) {
121 case AF_INET:
122 case AF_INET6:
123 siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
124 siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
125
126 siphash24_compress(&route->src_prefixlen, sizeof(route->src_prefixlen), state);
127 siphash24_compress(&route->src, FAMILY_ADDRESS_SIZE(route->family), state);
128
129 siphash24_compress(&route->gw_family, sizeof(route->gw_family), state);
130 if (IN_SET(route->gw_family, AF_INET, AF_INET6)) {
131 siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->gw_family), state);
132 siphash24_compress(&route->gw_weight, sizeof(route->gw_weight), state);
133 }
134
135 siphash24_compress(&route->prefsrc, FAMILY_ADDRESS_SIZE(route->family), state);
136
137 siphash24_compress(&route->tos, sizeof(route->tos), state);
138 siphash24_compress(&route->priority, sizeof(route->priority), state);
139 siphash24_compress(&route->table, sizeof(route->table), state);
140 siphash24_compress(&route->protocol, sizeof(route->protocol), state);
141 siphash24_compress(&route->scope, sizeof(route->scope), state);
142 siphash24_compress(&route->type, sizeof(route->type), state);
143
144 siphash24_compress(&route->initcwnd, sizeof(route->initcwnd), state);
145 siphash24_compress(&route->initrwnd, sizeof(route->initrwnd), state);
146
147 siphash24_compress(&route->advmss, sizeof(route->advmss), state);
148 siphash24_compress(&route->nexthop_id, sizeof(route->nexthop_id), state);
149
150 break;
151 default:
152 /* treat any other address family as AF_UNSPEC */
153 break;
154 }
155 }
156
157 static int route_compare_func(const Route *a, const Route *b) {
158 int r;
159
160 r = CMP(a->family, b->family);
161 if (r != 0)
162 return r;
163
164 switch (a->family) {
165 case AF_INET:
166 case AF_INET6:
167 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
168 if (r != 0)
169 return r;
170
171 r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
172 if (r != 0)
173 return r;
174
175 r = CMP(a->src_prefixlen, b->src_prefixlen);
176 if (r != 0)
177 return r;
178
179 r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
180 if (r != 0)
181 return r;
182
183 r = CMP(a->gw_family, b->gw_family);
184 if (r != 0)
185 return r;
186
187 if (IN_SET(a->gw_family, AF_INET, AF_INET6)) {
188 r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
189 if (r != 0)
190 return r;
191
192 r = CMP(a->gw_weight, b->gw_weight);
193 if (r != 0)
194 return r;
195 }
196
197 r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
198 if (r != 0)
199 return r;
200
201 r = CMP(a->tos, b->tos);
202 if (r != 0)
203 return r;
204
205 r = CMP(a->priority, b->priority);
206 if (r != 0)
207 return r;
208
209 r = CMP(a->table, b->table);
210 if (r != 0)
211 return r;
212
213 r = CMP(a->protocol, b->protocol);
214 if (r != 0)
215 return r;
216
217 r = CMP(a->scope, b->scope);
218 if (r != 0)
219 return r;
220
221 r = CMP(a->type, b->type);
222 if (r != 0)
223 return r;
224
225 r = CMP(a->initcwnd, b->initcwnd);
226 if (r != 0)
227 return r;
228
229 r = CMP(a->initrwnd, b->initrwnd);
230 if (r != 0)
231 return r;
232
233 r = CMP(a->advmss, b->advmss);
234 if (r != 0)
235 return r;
236
237 r = CMP(a->nexthop_id, b->nexthop_id);
238 if (r != 0)
239 return r;
240
241 return 0;
242 default:
243 /* treat any other address family as AF_UNSPEC */
244 return 0;
245 }
246 }
247
248 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
249 route_hash_ops,
250 Route,
251 route_hash_func,
252 route_compare_func,
253 route_free);
254
255 static bool route_type_is_reject(const Route *route) {
256 assert(route);
257
258 return IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW);
259 }
260
261 static bool route_needs_convert(const Route *route) {
262 assert(route);
263
264 return route->nexthop_id > 0 || !ordered_set_isempty(route->multipath_routes);
265 }
266
267 static int route_add(Manager *manager, Link *link, Route *route) {
268 int r;
269
270 assert(route);
271
272 if (route_type_is_reject(route)) {
273 assert(manager);
274
275 r = set_ensure_put(&manager->routes, &route_hash_ops, route);
276 if (r < 0)
277 return r;
278 if (r == 0)
279 return -EEXIST;
280
281 route->manager = manager;
282 } else {
283 assert(link);
284
285 r = set_ensure_put(&link->routes, &route_hash_ops, route);
286 if (r < 0)
287 return r;
288 if (r == 0)
289 return -EEXIST;
290
291 route->link = link;
292 }
293
294 return 0;
295 }
296
297 int route_get(Manager *manager, Link *link, const Route *in, Route **ret) {
298 Route *route;
299
300 assert(in);
301
302 if (route_type_is_reject(in)) {
303 if (!manager)
304 return -ENOENT;
305
306 route = set_get(manager->routes, in);
307 } else {
308 if (!link)
309 return -ENOENT;
310
311 route = set_get(link->routes, in);
312 }
313 if (!route)
314 return -ENOENT;
315
316 if (ret)
317 *ret = route;
318
319 return 0;
320 }
321
322 int route_dup(const Route *src, Route **ret) {
323 _cleanup_(route_freep) Route *dest = NULL;
324 int r;
325
326 /* This does not copy mulipath routes. */
327
328 assert(src);
329 assert(ret);
330
331 dest = newdup(Route, src, 1);
332 if (!dest)
333 return -ENOMEM;
334
335 /* Unset all pointers */
336 dest->network = NULL;
337 dest->section = NULL;
338 dest->link = NULL;
339 dest->manager = NULL;
340 dest->multipath_routes = NULL;
341 dest->expire = NULL;
342 dest->tcp_congestion_control_algo = NULL;
343
344 r = free_and_strdup(&dest->tcp_congestion_control_algo, src->tcp_congestion_control_algo);
345 if (r < 0)
346 return r;
347
348 *ret = TAKE_PTR(dest);
349 return 0;
350 }
351
352 static void route_apply_nexthop(Route *route, const NextHop *nh, uint8_t nh_weight) {
353 assert(route);
354 assert(nh);
355 assert(hashmap_isempty(nh->group));
356
357 route->gw_family = nh->family;
358 route->gw = nh->gw;
359
360 if (nh_weight != UINT8_MAX)
361 route->gw_weight = nh_weight;
362
363 if (nh->blackhole)
364 route->type = RTN_BLACKHOLE;
365 }
366
367 static void route_apply_multipath_route(Route *route, const MultipathRoute *m) {
368 assert(route);
369 assert(m);
370
371 route->gw_family = m->gateway.family;
372 route->gw = m->gateway.address;
373 route->gw_weight = m->weight;
374 }
375
376 static int multipath_route_get_link(Manager *manager, const MultipathRoute *m, Link **ret) {
377 int r;
378
379 assert(manager);
380 assert(m);
381
382 if (m->ifname) {
383 r = link_get_by_name(manager, m->ifname, ret);
384 return r < 0 ? r : 1;
385
386 } else if (m->ifindex > 0) { /* Always ignore ifindex if ifname is set. */
387 r = link_get_by_index(manager, m->ifindex, ret);
388 return r < 0 ? r : 1;
389 }
390
391 if (ret)
392 *ret = NULL;
393 return 0;
394 }
395
396 typedef struct ConvertedRoutes {
397 size_t n;
398 Route **routes;
399 Link **links;
400 } ConvertedRoutes;
401
402 static ConvertedRoutes *converted_routes_free(ConvertedRoutes *c) {
403 if (!c)
404 return NULL;
405
406 for (size_t i = 0; i < c->n; i++)
407 route_free(c->routes[i]);
408
409 free(c->routes);
410 free(c->links);
411
412 return mfree(c);
413 }
414
415 DEFINE_TRIVIAL_CLEANUP_FUNC(ConvertedRoutes*, converted_routes_free);
416
417 static int converted_routes_new(size_t n, ConvertedRoutes **ret) {
418 _cleanup_(converted_routes_freep) ConvertedRoutes *c = NULL;
419 _cleanup_free_ Route **routes = NULL;
420 _cleanup_free_ Link **links = NULL;
421
422 assert(n > 0);
423 assert(ret);
424
425 routes = new0(Route*, n);
426 if (!routes)
427 return -ENOMEM;
428
429 links = new0(Link*, n);
430 if (!links)
431 return -ENOMEM;
432
433 c = new(ConvertedRoutes, 1);
434 if (!c)
435 return -ENOMEM;
436
437 *c = (ConvertedRoutes) {
438 .n = n,
439 .routes = TAKE_PTR(routes),
440 .links = TAKE_PTR(links),
441 };
442
443 *ret = TAKE_PTR(c);
444 return 0;
445 }
446
447 static int route_convert(Manager *manager, const Route *route, ConvertedRoutes **ret) {
448 _cleanup_(converted_routes_freep) ConvertedRoutes *c = NULL;
449 int r;
450
451 assert(manager);
452 assert(route);
453 assert(ret);
454
455 if (!route_needs_convert(route)) {
456 *ret = NULL;
457 return 0;
458 }
459
460 if (route->nexthop_id > 0) {
461 struct nexthop_grp *nhg;
462 NextHop *nh;
463
464 r = nexthop_get_by_id(manager, route->nexthop_id, &nh);
465 if (r < 0)
466 return r;
467
468 if (hashmap_isempty(nh->group)) {
469 r = converted_routes_new(1, &c);
470 if (r < 0)
471 return r;
472
473 r = route_dup(route, &c->routes[0]);
474 if (r < 0)
475 return r;
476
477 route_apply_nexthop(c->routes[0], nh, UINT8_MAX);
478 (void) link_get_by_index(manager, nh->ifindex, c->links);
479
480 *ret = TAKE_PTR(c);
481 return 1;
482 }
483
484 r = converted_routes_new(hashmap_size(nh->group), &c);
485 if (r < 0)
486 return r;
487
488 size_t i = 0;
489 HASHMAP_FOREACH(nhg, nh->group) {
490 NextHop *h;
491
492 r = nexthop_get_by_id(manager, nhg->id, &h);
493 if (r < 0)
494 return r;
495
496 r = route_dup(route, &c->routes[i]);
497 if (r < 0)
498 return r;
499
500 route_apply_nexthop(c->routes[i], h, nhg->weight);
501 (void) link_get_by_index(manager, h->ifindex, c->links + i);
502
503 i++;
504 }
505
506 *ret = TAKE_PTR(c);
507 return 1;
508
509 }
510
511 assert(!ordered_set_isempty(route->multipath_routes));
512
513 r = converted_routes_new(ordered_set_size(route->multipath_routes), &c);
514 if (r < 0)
515 return r;
516
517 size_t i = 0;
518 MultipathRoute *m;
519 ORDERED_SET_FOREACH(m, route->multipath_routes) {
520 r = route_dup(route, &c->routes[i]);
521 if (r < 0)
522 return r;
523
524 route_apply_multipath_route(c->routes[i], m);
525
526 r = multipath_route_get_link(manager, m, &c->links[i]);
527 if (r < 0)
528 return r;
529
530 i++;
531 }
532
533 *ret = TAKE_PTR(c);
534 return 1;
535 }
536
537 void link_mark_routes(Link *link, NetworkConfigSource source) {
538 Route *route;
539
540 assert(link);
541
542 SET_FOREACH(route, link->routes) {
543 if (route->source != source)
544 continue;
545
546 route_mark(route);
547 }
548 }
549
550 static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *manager) {
551 _cleanup_free_ char *state = NULL, *gw_alloc = NULL, *prefsrc = NULL,
552 *table = NULL, *scope = NULL, *proto = NULL, *flags = NULL;
553 const char *gw = NULL, *dst, *src;
554
555 assert(route);
556 assert(str);
557 assert(manager);
558
559 /* link may be NULL. */
560
561 if (!DEBUG_LOGGING)
562 return;
563
564 (void) network_config_state_to_string_alloc(route->state, &state);
565
566 dst = in_addr_is_set(route->family, &route->dst) || route->dst_prefixlen > 0 ?
567 IN_ADDR_PREFIX_TO_STRING(route->family, &route->dst, route->dst_prefixlen) : NULL;
568 src = in_addr_is_set(route->family, &route->src) || route->src_prefixlen > 0 ?
569 IN_ADDR_PREFIX_TO_STRING(route->family, &route->src, route->src_prefixlen) : NULL;
570
571 if (in_addr_is_set(route->gw_family, &route->gw)) {
572 (void) in_addr_to_string(route->gw_family, &route->gw, &gw_alloc);
573 gw = gw_alloc;
574 } else if (route->gateway_from_dhcp_or_ra) {
575 if (route->gw_family == AF_INET)
576 gw = "_dhcp4";
577 else if (route->gw_family == AF_INET6)
578 gw = "_ipv6ra";
579 } else {
580 MultipathRoute *m;
581
582 ORDERED_SET_FOREACH(m, route->multipath_routes) {
583 _cleanup_free_ char *buf = NULL;
584 union in_addr_union a = m->gateway.address;
585
586 (void) in_addr_to_string(m->gateway.family, &a, &buf);
587 (void) strextend_with_separator(&gw_alloc, ",", strna(buf));
588 if (m->ifname)
589 (void) strextend(&gw_alloc, "@", m->ifname);
590 else if (m->ifindex > 0)
591 (void) strextendf(&gw_alloc, "@%i", m->ifindex);
592 /* See comments in config_parse_multipath_route(). */
593 (void) strextendf(&gw_alloc, ":%"PRIu32, m->weight + 1);
594 }
595 gw = gw_alloc;
596 }
597 if (in_addr_is_set(route->family, &route->prefsrc))
598 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
599 (void) route_scope_to_string_alloc(route->scope, &scope);
600 (void) manager_get_route_table_to_string(manager, route->table, /* append_num = */ true, &table);
601 (void) route_protocol_full_to_string_alloc(route->protocol, &proto);
602 (void) route_flags_to_string_alloc(route->flags, &flags);
603
604 log_link_debug(link,
605 "%s %s route (%s): dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, "
606 "proto: %s, type: %s, nexthop: %"PRIu32", priority: %"PRIu32", flags: %s",
607 str, strna(network_config_source_to_string(route->source)), strna(state),
608 strna(dst), strna(src), strna(gw), strna(prefsrc),
609 strna(scope), strna(table), strna(proto),
610 strna(route_type_to_string(route->type)),
611 route->nexthop_id, route->priority, strna(flags));
612 }
613
614 static int route_set_netlink_message(const Route *route, sd_netlink_message *req, Link *link) {
615 int r;
616
617 assert(route);
618 assert(req);
619
620 /* link may be NULL */
621
622 if (in_addr_is_set(route->gw_family, &route->gw) && route->nexthop_id == 0) {
623 if (route->gw_family == route->family) {
624 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->gw_family, &route->gw);
625 if (r < 0)
626 return r;
627 } else {
628 RouteVia rtvia = {
629 .family = route->gw_family,
630 .address = route->gw,
631 };
632
633 r = sd_netlink_message_append_data(req, RTA_VIA, &rtvia, sizeof(rtvia));
634 if (r < 0)
635 return r;
636 }
637 }
638
639 if (route->dst_prefixlen > 0) {
640 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
641 if (r < 0)
642 return r;
643
644 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
645 if (r < 0)
646 return r;
647 }
648
649 if (route->src_prefixlen > 0) {
650 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
651 if (r < 0)
652 return r;
653
654 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
655 if (r < 0)
656 return r;
657 }
658
659 if (in_addr_is_set(route->family, &route->prefsrc)) {
660 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
661 if (r < 0)
662 return r;
663 }
664
665 r = sd_rtnl_message_route_set_scope(req, route->scope);
666 if (r < 0)
667 return r;
668
669 r = sd_rtnl_message_route_set_flags(req, route->flags & RTNH_F_ONLINK);
670 if (r < 0)
671 return r;
672
673 if (route->table < 256) {
674 r = sd_rtnl_message_route_set_table(req, route->table);
675 if (r < 0)
676 return r;
677 } else {
678 r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
679 if (r < 0)
680 return r;
681
682 /* Table attribute to allow more than 256. */
683 r = sd_netlink_message_append_u32(req, RTA_TABLE, route->table);
684 if (r < 0)
685 return r;
686 }
687
688 if (!route_type_is_reject(route) &&
689 route->nexthop_id == 0 &&
690 ordered_set_isempty(route->multipath_routes)) {
691 assert(link); /* Those routes must be attached to a specific link */
692
693 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
694 if (r < 0)
695 return r;
696 }
697
698 if (route->nexthop_id > 0) {
699 r = sd_netlink_message_append_u32(req, RTA_NH_ID, route->nexthop_id);
700 if (r < 0)
701 return r;
702 }
703
704 r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
705 if (r < 0)
706 return r;
707
708 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
709 if (r < 0)
710 return r;
711
712 return 0;
713 }
714
715 static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
716 int r;
717
718 assert(m);
719
720 /* link may be NULL. */
721
722 if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
723 return 0;
724
725 r = sd_netlink_message_get_errno(m);
726 if (r < 0 && r != -ESRCH)
727 log_link_message_warning_errno(link, m, r, "Could not drop route, ignoring");
728
729 return 1;
730 }
731
732 int route_remove(Route *route) {
733 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
734 unsigned char type;
735 Manager *manager;
736 Link *link;
737 int r;
738
739 assert(route);
740 assert(route->manager || (route->link && route->link->manager));
741 assert(IN_SET(route->family, AF_INET, AF_INET6));
742
743 link = route->link;
744 manager = route->manager ?: link->manager;
745
746 log_route_debug(route, "Removing", link, manager);
747
748 r = sd_rtnl_message_new_route(manager->rtnl, &req,
749 RTM_DELROUTE, route->family,
750 route->protocol);
751 if (r < 0)
752 return log_link_error_errno(link, r, "Could not create netlink message: %m");
753
754 if (route->family == AF_INET && route->nexthop_id > 0 && route->type == RTN_BLACKHOLE)
755 /* When IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel
756 * sends RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type
757 * fib_rt_info::type may not be blackhole. Thus, we cannot know the internal value.
758 * Moreover, on route removal, the matching is done with the hidden value if we set
759 * non-zero type in RTM_DELROUTE message. Note, sd_rtnl_message_new_route() sets
760 * RTN_UNICAST by default. So, we need to clear the type here. */
761 type = RTN_UNSPEC;
762 else
763 type = route->type;
764
765 r = sd_rtnl_message_route_set_type(req, type);
766 if (r < 0)
767 return log_link_error_errno(link, r, "Could not set route type: %m");
768
769 r = route_set_netlink_message(route, req, link);
770 if (r < 0)
771 return log_error_errno(r, "Could not fill netlink message: %m");
772
773 r = netlink_call_async(manager->rtnl, NULL, req, route_remove_handler,
774 link ? link_netlink_destroy_callback : NULL, link);
775 if (r < 0)
776 return log_link_error_errno(link, r, "Could not send netlink message: %m");
777
778 link_ref(link);
779
780 route_enter_removing(route);
781 return 0;
782 }
783
784 int route_remove_and_drop(Route *route) {
785 if (!route)
786 return 0;
787
788 route_cancel_request(route, NULL);
789
790 if (route_exists(route))
791 return route_remove(route);
792
793 if (route->state == 0)
794 route_free(route);
795
796 return 0;
797 }
798
799 static void manager_mark_routes(Manager *manager, bool foreign, const Link *except) {
800 Route *route;
801 Link *link;
802 int r;
803
804 assert(manager);
805
806 /* First, mark all routes. */
807 SET_FOREACH(route, manager->routes) {
808 /* Do not touch routes managed by the kernel. */
809 if (route->protocol == RTPROT_KERNEL)
810 continue;
811
812 /* When 'foreign' is true, mark only foreign routes, and vice versa. */
813 if (foreign != (route->source == NETWORK_CONFIG_SOURCE_FOREIGN))
814 continue;
815
816 /* Do not touch dynamic routes. They will removed by dhcp_pd_prefix_lost() */
817 if (IN_SET(route->source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6))
818 continue;
819
820 /* Ignore routes not assigned yet or already removed. */
821 if (!route_exists(route))
822 continue;
823
824 route_mark(route);
825 }
826
827 /* Then, unmark all routes requested by active links. */
828 HASHMAP_FOREACH(link, manager->links_by_index) {
829 if (link == except)
830 continue;
831
832 if (!link->network)
833 continue;
834
835 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
836 continue;
837
838 HASHMAP_FOREACH(route, link->network->routes_by_section) {
839 _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
840 Route *existing;
841
842 r = route_convert(manager, route, &converted);
843 if (r < 0)
844 continue;
845 if (r == 0) {
846 if (route_get(manager, NULL, route, &existing) >= 0)
847 route_unmark(existing);
848 continue;
849 }
850
851 for (size_t i = 0; i < converted->n; i++)
852 if (route_get(manager, NULL, converted->routes[i], &existing) >= 0)
853 route_unmark(existing);
854 }
855 }
856 }
857
858 static int manager_drop_marked_routes(Manager *manager) {
859 Route *route;
860 int r = 0;
861
862 assert(manager);
863
864 SET_FOREACH(route, manager->routes) {
865 if (!route_is_marked(route))
866 continue;
867
868 RET_GATHER(r, route_remove(route));
869 }
870
871 return r;
872 }
873
874 static bool route_by_kernel(const Route *route) {
875 assert(route);
876
877 if (route->protocol == RTPROT_KERNEL)
878 return true;
879
880 /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
881 * multicast with RTPROT_BOOT. Do not touch it. */
882 if (route->protocol == RTPROT_BOOT &&
883 route->family == AF_INET6 &&
884 route->dst_prefixlen == 8 &&
885 in6_addr_equal(&route->dst.in6, & (struct in6_addr) {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}}))
886 return true;
887
888 return false;
889 }
890
891 static void link_unmark_wireguard_routes(Link *link) {
892 assert(link);
893
894 if (!link->netdev || link->netdev->kind != NETDEV_KIND_WIREGUARD)
895 return;
896
897 Route *route, *existing;
898 Wireguard *w = WIREGUARD(link->netdev);
899
900 SET_FOREACH(route, w->routes)
901 if (route_get(NULL, link, route, &existing) >= 0)
902 route_unmark(existing);
903 }
904
905 int link_drop_foreign_routes(Link *link) {
906 Route *route;
907 int r;
908
909 assert(link);
910 assert(link->manager);
911 assert(link->network);
912
913 SET_FOREACH(route, link->routes) {
914 /* do not touch routes managed by the kernel */
915 if (route_by_kernel(route))
916 continue;
917
918 /* Do not remove routes we configured. */
919 if (route->source != NETWORK_CONFIG_SOURCE_FOREIGN)
920 continue;
921
922 /* Ignore routes not assigned yet or already removed. */
923 if (!route_exists(route))
924 continue;
925
926 if (route->protocol == RTPROT_STATIC &&
927 FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
928 continue;
929
930 if (route->protocol == RTPROT_DHCP &&
931 FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
932 continue;
933
934 route_mark(route);
935 }
936
937 HASHMAP_FOREACH(route, link->network->routes_by_section) {
938 _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
939 Route *existing;
940
941 r = route_convert(link->manager, route, &converted);
942 if (r < 0)
943 continue;
944 if (r == 0) {
945 if (route_get(NULL, link, route, &existing) >= 0)
946 route_unmark(existing);
947 continue;
948 }
949
950 for (size_t i = 0; i < converted->n; i++)
951 if (route_get(NULL, link, converted->routes[i], &existing) >= 0)
952 route_unmark(existing);
953 }
954
955 link_unmark_wireguard_routes(link);
956
957 r = 0;
958 SET_FOREACH(route, link->routes) {
959 if (!route_is_marked(route))
960 continue;
961
962 RET_GATHER(r, route_remove(route));
963 }
964
965 manager_mark_routes(link->manager, /* foreign = */ true, NULL);
966
967 return RET_GATHER(r, manager_drop_marked_routes(link->manager));
968 }
969
970 int link_drop_managed_routes(Link *link) {
971 Route *route;
972 int r = 0;
973
974 assert(link);
975
976 SET_FOREACH(route, link->routes) {
977 /* do not touch routes managed by the kernel */
978 if (route_by_kernel(route))
979 continue;
980
981 /* Do not touch routes managed by kernel or other tools. */
982 if (route->source == NETWORK_CONFIG_SOURCE_FOREIGN)
983 continue;
984
985 if (!route_exists(route))
986 continue;
987
988 RET_GATHER(r, route_remove(route));
989 }
990
991 manager_mark_routes(link->manager, /* foreign = */ false, link);
992
993 return RET_GATHER(r, manager_drop_marked_routes(link->manager));
994 }
995
996 void link_foreignize_routes(Link *link) {
997 Route *route;
998
999 assert(link);
1000
1001 SET_FOREACH(route, link->routes)
1002 route->source = NETWORK_CONFIG_SOURCE_FOREIGN;
1003
1004 manager_mark_routes(link->manager, /* foreign = */ false, link);
1005
1006 SET_FOREACH(route, link->manager->routes) {
1007 if (!route_is_marked(route))
1008 continue;
1009
1010 route->source = NETWORK_CONFIG_SOURCE_FOREIGN;
1011 }
1012 }
1013
1014 static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
1015 Route *route = ASSERT_PTR(userdata);
1016 Link *link;
1017 int r;
1018
1019 assert(route->manager || (route->link && route->link->manager));
1020
1021 link = route->link; /* This may be NULL. */
1022
1023 r = route_remove(route);
1024 if (r < 0) {
1025 log_link_warning_errno(link, r, "Could not remove route: %m");
1026 if (link)
1027 link_enter_failed(link);
1028 }
1029
1030 return 1;
1031 }
1032
1033 static int route_setup_timer(Route *route, const struct rta_cacheinfo *cacheinfo) {
1034 Manager *manager;
1035 int r;
1036
1037 assert(route);
1038 assert(route->manager || (route->link && route->link->manager));
1039
1040 manager = route->manager ?: route->link->manager;
1041
1042 if (route->lifetime_usec == USEC_INFINITY)
1043 return 0;
1044
1045 if (cacheinfo && cacheinfo->rta_expires != 0)
1046 /* Assume that non-zero rta_expires means kernel will handle the route expiration. */
1047 return 0;
1048
1049 r = event_reset_time(manager->event, &route->expire, CLOCK_BOOTTIME,
1050 route->lifetime_usec, 0, route_expire_handler, route, 0, "route-expiration", true);
1051 if (r < 0)
1052 return r;
1053
1054 return 1;
1055 }
1056
1057 static int append_nexthop_one(const Link *link, const Route *route, const MultipathRoute *m, struct rtattr **rta, size_t offset) {
1058 struct rtnexthop *rtnh;
1059 struct rtattr *new_rta;
1060 int r;
1061
1062 assert(route);
1063 assert(m);
1064 assert(rta);
1065 assert(*rta);
1066
1067 new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
1068 if (!new_rta)
1069 return -ENOMEM;
1070 *rta = new_rta;
1071
1072 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
1073 *rtnh = (struct rtnexthop) {
1074 .rtnh_len = sizeof(*rtnh),
1075 .rtnh_ifindex = m->ifindex > 0 ? m->ifindex : link->ifindex,
1076 .rtnh_hops = m->weight,
1077 };
1078
1079 (*rta)->rta_len += sizeof(struct rtnexthop);
1080
1081 if (route->family == m->gateway.family) {
1082 r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
1083 if (r < 0)
1084 goto clear;
1085 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
1086 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
1087 } else {
1088 r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
1089 if (r < 0)
1090 goto clear;
1091 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
1092 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
1093 }
1094
1095 return 0;
1096
1097 clear:
1098 (*rta)->rta_len -= sizeof(struct rtnexthop);
1099 return r;
1100 }
1101
1102 static int append_nexthops(const Link *link, const Route *route, sd_netlink_message *req) {
1103 _cleanup_free_ struct rtattr *rta = NULL;
1104 struct rtnexthop *rtnh;
1105 MultipathRoute *m;
1106 size_t offset;
1107 int r;
1108
1109 assert(link);
1110 assert(route);
1111 assert(req);
1112
1113 if (ordered_set_isempty(route->multipath_routes))
1114 return 0;
1115
1116 rta = new(struct rtattr, 1);
1117 if (!rta)
1118 return -ENOMEM;
1119
1120 *rta = (struct rtattr) {
1121 .rta_type = RTA_MULTIPATH,
1122 .rta_len = RTA_LENGTH(0),
1123 };
1124 offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
1125
1126 ORDERED_SET_FOREACH(m, route->multipath_routes) {
1127 r = append_nexthop_one(link, route, m, &rta, offset);
1128 if (r < 0)
1129 return r;
1130
1131 rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
1132 offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
1133 }
1134
1135 r = sd_netlink_message_append_data(req, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
1136 if (r < 0)
1137 return r;
1138
1139 return 0;
1140 }
1141
1142 int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) {
1143 int r;
1144
1145 assert(m);
1146 assert(link);
1147 assert(error_msg);
1148
1149 r = sd_netlink_message_get_errno(m);
1150 if (r < 0 && r != -EEXIST) {
1151 log_link_message_warning_errno(link, m, r, "Could not set route");
1152 link_enter_failed(link);
1153 return 0;
1154 }
1155
1156 return 1;
1157 }
1158
1159 static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link, Request *req) {
1160 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
1161 int r;
1162
1163 assert(route);
1164 assert(IN_SET(route->family, AF_INET, AF_INET6));
1165 assert(link);
1166 assert(link->manager);
1167 assert(link->manager->rtnl);
1168 assert(link->ifindex > 0);
1169 assert(req);
1170
1171 log_route_debug(route, "Configuring", link, link->manager);
1172
1173 r = sd_rtnl_message_new_route(link->manager->rtnl, &m, RTM_NEWROUTE, route->family, route->protocol);
1174 if (r < 0)
1175 return r;
1176
1177 r = sd_rtnl_message_route_set_type(m, route->type);
1178 if (r < 0)
1179 return r;
1180
1181 r = route_set_netlink_message(route, m, link);
1182 if (r < 0)
1183 return r;
1184
1185 if (lifetime_sec != UINT32_MAX) {
1186 r = sd_netlink_message_append_u32(m, RTA_EXPIRES, lifetime_sec);
1187 if (r < 0)
1188 return r;
1189 }
1190
1191 if (route->ttl_propagate >= 0) {
1192 r = sd_netlink_message_append_u8(m, RTA_TTL_PROPAGATE, route->ttl_propagate);
1193 if (r < 0)
1194 return r;
1195 }
1196
1197 r = sd_netlink_message_open_container(m, RTA_METRICS);
1198 if (r < 0)
1199 return r;
1200
1201 if (route->mtu > 0) {
1202 r = sd_netlink_message_append_u32(m, RTAX_MTU, route->mtu);
1203 if (r < 0)
1204 return r;
1205 }
1206
1207 if (route->initcwnd > 0) {
1208 r = sd_netlink_message_append_u32(m, RTAX_INITCWND, route->initcwnd);
1209 if (r < 0)
1210 return r;
1211 }
1212
1213 if (route->initrwnd > 0) {
1214 r = sd_netlink_message_append_u32(m, RTAX_INITRWND, route->initrwnd);
1215 if (r < 0)
1216 return r;
1217 }
1218
1219 if (route->quickack >= 0) {
1220 r = sd_netlink_message_append_u32(m, RTAX_QUICKACK, route->quickack);
1221 if (r < 0)
1222 return r;
1223 }
1224
1225 if (route->fast_open_no_cookie >= 0) {
1226 r = sd_netlink_message_append_u32(m, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
1227 if (r < 0)
1228 return r;
1229 }
1230
1231 if (route->advmss > 0) {
1232 r = sd_netlink_message_append_u32(m, RTAX_ADVMSS, route->advmss);
1233 if (r < 0)
1234 return r;
1235 }
1236
1237 if (!isempty(route->tcp_congestion_control_algo)) {
1238 r = sd_netlink_message_append_string(m, RTAX_CC_ALGO, route->tcp_congestion_control_algo);
1239 if (r < 0)
1240 return r;
1241 }
1242
1243 if (route->hop_limit > 0) {
1244 r = sd_netlink_message_append_u32(m, RTAX_HOPLIMIT, route->hop_limit);
1245 if (r < 0)
1246 return r;
1247 }
1248
1249 if (route->tcp_rto_usec > 0) {
1250 r = sd_netlink_message_append_u32(m, RTAX_RTO_MIN, DIV_ROUND_UP(route->tcp_rto_usec, USEC_PER_MSEC));
1251 if (r < 0)
1252 return r;
1253 }
1254
1255 r = sd_netlink_message_close_container(m);
1256 if (r < 0)
1257 return r;
1258
1259 if (!ordered_set_isempty(route->multipath_routes)) {
1260 assert(route->nexthop_id == 0);
1261 assert(!in_addr_is_set(route->gw_family, &route->gw));
1262
1263 r = append_nexthops(link, route, m);
1264 if (r < 0)
1265 return r;
1266 }
1267
1268 return request_call_netlink_async(link->manager->rtnl, m, req);
1269 }
1270
1271 static int route_is_ready_to_configure(const Route *route, Link *link) {
1272 int r;
1273
1274 assert(route);
1275 assert(link);
1276
1277 if (!link_is_ready_to_configure(link, false))
1278 return false;
1279
1280 if (set_size(link->routes) >= routes_max())
1281 return false;
1282
1283 if (route->nexthop_id > 0) {
1284 struct nexthop_grp *nhg;
1285 NextHop *nh;
1286
1287 if (nexthop_get_by_id(link->manager, route->nexthop_id, &nh) < 0)
1288 return false;
1289
1290 if (!nexthop_exists(nh))
1291 return false;
1292
1293 HASHMAP_FOREACH(nhg, nh->group) {
1294 NextHop *g;
1295
1296 if (nexthop_get_by_id(link->manager, nhg->id, &g) < 0)
1297 return false;
1298
1299 if (!nexthop_exists(g))
1300 return false;
1301 }
1302 }
1303
1304 if (in_addr_is_set(route->family, &route->prefsrc) > 0) {
1305 r = manager_has_address(link->manager, route->family, &route->prefsrc, route->family == AF_INET6);
1306 if (r <= 0)
1307 return r;
1308 }
1309
1310 if (!gateway_is_ready(link, FLAGS_SET(route->flags, RTNH_F_ONLINK), route->gw_family, &route->gw))
1311 return false;
1312
1313 MultipathRoute *m;
1314 ORDERED_SET_FOREACH(m, route->multipath_routes) {
1315 union in_addr_union a = m->gateway.address;
1316 Link *l = NULL;
1317
1318 r = multipath_route_get_link(link->manager, m, &l);
1319 if (r < 0)
1320 return false;
1321 if (r > 0) {
1322 if (!link_is_ready_to_configure(l, /* allow_unmanaged = */ true) ||
1323 !link_has_carrier(l))
1324 return false;
1325
1326 m->ifindex = l->ifindex;
1327 }
1328
1329 if (!gateway_is_ready(l ?: link, FLAGS_SET(route->flags, RTNH_F_ONLINK), m->gateway.family, &a))
1330 return false;
1331 }
1332
1333 return true;
1334 }
1335
1336 static int route_process_request(Request *req, Link *link, Route *route) {
1337 _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
1338 int r;
1339
1340 assert(req);
1341 assert(link);
1342 assert(link->manager);
1343 assert(route);
1344
1345 r = route_is_ready_to_configure(route, link);
1346 if (r < 0)
1347 return log_link_warning_errno(link, r, "Failed to check if route is ready to configure: %m");
1348 if (r == 0)
1349 return 0;
1350
1351 if (route_needs_convert(route)) {
1352 r = route_convert(link->manager, route, &converted);
1353 if (r < 0)
1354 return log_link_warning_errno(link, r, "Failed to convert route: %m");
1355
1356 assert(r > 0);
1357 assert(converted);
1358
1359 for (size_t i = 0; i < converted->n; i++) {
1360 Route *existing;
1361
1362 if (route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) < 0) {
1363 _cleanup_(route_freep) Route *tmp = NULL;
1364
1365 r = route_dup(converted->routes[i], &tmp);
1366 if (r < 0)
1367 return log_oom();
1368
1369 r = route_add(link->manager, converted->links[i] ?: link, tmp);
1370 if (r < 0)
1371 return log_link_warning_errno(link, r, "Failed to add route: %m");
1372
1373 TAKE_PTR(tmp);
1374 } else {
1375 existing->source = converted->routes[i]->source;
1376 existing->provider = converted->routes[i]->provider;
1377 }
1378 }
1379 }
1380
1381 usec_t now_usec;
1382 assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
1383 uint32_t sec = usec_to_sec(route->lifetime_usec, now_usec);
1384 if (sec == 0) {
1385 log_link_debug(link, "Refuse to configure %s route with zero lifetime.",
1386 network_config_source_to_string(route->source));
1387
1388 if (converted)
1389 for (size_t i = 0; i < converted->n; i++) {
1390 Route *existing;
1391
1392 assert_se(route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) >= 0);
1393 route_cancel_requesting(existing);
1394 }
1395 else
1396 route_cancel_requesting(route);
1397
1398 return 1;
1399 }
1400
1401 r = route_configure(route, sec, link, req);
1402 if (r < 0)
1403 return log_link_warning_errno(link, r, "Failed to configure route: %m");
1404
1405 if (converted)
1406 for (size_t i = 0; i < converted->n; i++) {
1407 Route *existing;
1408
1409 assert_se(route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) >= 0);
1410 route_enter_configuring(existing);
1411 }
1412 else
1413 route_enter_configuring(route);
1414
1415 return 1;
1416 }
1417
1418 int link_request_route(
1419 Link *link,
1420 Route *route,
1421 bool consume_object,
1422 unsigned *message_counter,
1423 route_netlink_handler_t netlink_handler,
1424 Request **ret) {
1425
1426 Route *existing = NULL;
1427 int r;
1428
1429 assert(link);
1430 assert(link->manager);
1431 assert(route);
1432 assert(route->source != NETWORK_CONFIG_SOURCE_FOREIGN);
1433 assert(!route_needs_convert(route));
1434
1435 (void) route_get(link->manager, link, route, &existing);
1436
1437 if (route->lifetime_usec == 0) {
1438 if (consume_object)
1439 route_free(route);
1440
1441 /* The requested route is outdated. Let's remove it. */
1442 return route_remove_and_drop(existing);
1443 }
1444
1445 if (!existing) {
1446 _cleanup_(route_freep) Route *tmp = NULL;
1447
1448 if (consume_object)
1449 tmp = route;
1450 else {
1451 r = route_dup(route, &tmp);
1452 if (r < 0)
1453 return r;
1454 }
1455
1456 r = route_add(link->manager, link, tmp);
1457 if (r < 0)
1458 return r;
1459
1460 existing = TAKE_PTR(tmp);
1461 } else {
1462 existing->source = route->source;
1463 existing->provider = route->provider;
1464 existing->lifetime_usec = route->lifetime_usec;
1465 if (consume_object)
1466 route_free(route);
1467
1468 if (existing->expire) {
1469 /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE
1470 * message, so we need to update the timer here. */
1471 r = route_setup_timer(existing, NULL);
1472 if (r < 0)
1473 log_link_warning_errno(link, r, "Failed to update expiration timer for route, ignoring: %m");
1474 if (r > 0)
1475 log_route_debug(existing, "Updated expiration timer for", link, link->manager);
1476 }
1477 }
1478
1479 log_route_debug(existing, "Requesting", link, link->manager);
1480 r = link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
1481 existing, NULL,
1482 route_hash_func,
1483 route_compare_func,
1484 route_process_request,
1485 message_counter, netlink_handler, ret);
1486 if (r <= 0)
1487 return r;
1488
1489 route_enter_requesting(existing);
1490 return 1;
1491 }
1492
1493 static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
1494 int r;
1495
1496 assert(link);
1497
1498 r = route_configure_handler_internal(rtnl, m, link, "Could not set route");
1499 if (r <= 0)
1500 return r;
1501
1502 if (link->static_route_messages == 0) {
1503 log_link_debug(link, "Routes set");
1504 link->static_routes_configured = true;
1505 link_check_ready(link);
1506 }
1507
1508 return 1;
1509 }
1510
1511 static int link_request_static_route(Link *link, Route *route) {
1512 assert(link);
1513 assert(link->manager);
1514 assert(route);
1515
1516 if (!route_needs_convert(route))
1517 return link_request_route(link, route, false, &link->static_route_messages,
1518 static_route_handler, NULL);
1519
1520 log_route_debug(route, "Requesting", link, link->manager);
1521 return link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
1522 route, NULL, route_hash_func, route_compare_func,
1523 route_process_request,
1524 &link->static_route_messages, static_route_handler, NULL);
1525 }
1526
1527 static int link_request_wireguard_routes(Link *link, bool only_ipv4) {
1528 NetDev *netdev;
1529 Route *route;
1530 int r;
1531
1532 assert(link);
1533
1534 if (!streq_ptr(link->kind, "wireguard"))
1535 return 0;
1536
1537 if (netdev_get(link->manager, link->ifname, &netdev) < 0)
1538 return 0;
1539
1540 Wireguard *w = WIREGUARD(netdev);
1541
1542 SET_FOREACH(route, w->routes) {
1543 if (only_ipv4 && route->family != AF_INET)
1544 continue;
1545
1546 r = link_request_static_route(link, route);
1547 if (r < 0)
1548 return r;
1549 }
1550
1551 return 0;
1552 }
1553
1554 int link_request_static_routes(Link *link, bool only_ipv4) {
1555 Route *route;
1556 int r;
1557
1558 assert(link);
1559 assert(link->network);
1560
1561 link->static_routes_configured = false;
1562
1563 HASHMAP_FOREACH(route, link->network->routes_by_section) {
1564 if (route->gateway_from_dhcp_or_ra)
1565 continue;
1566
1567 if (only_ipv4 && route->family != AF_INET)
1568 continue;
1569
1570 r = link_request_static_route(link, route);
1571 if (r < 0)
1572 return r;
1573 }
1574
1575 r = link_request_wireguard_routes(link, only_ipv4);
1576 if (r < 0)
1577 return r;
1578
1579 if (link->static_route_messages == 0) {
1580 link->static_routes_configured = true;
1581 link_check_ready(link);
1582 } else {
1583 log_link_debug(link, "Requesting routes");
1584 link_set_state(link, LINK_STATE_CONFIGURING);
1585 }
1586
1587 return 0;
1588 }
1589
1590 void route_cancel_request(Route *route, Link *link) {
1591 Request req;
1592
1593 assert(route);
1594
1595 link = route->link ?: link;
1596
1597 assert(link);
1598
1599 if (!route_is_requesting(route))
1600 return;
1601
1602 req = (Request) {
1603 .link = link,
1604 .type = REQUEST_TYPE_ROUTE,
1605 .userdata = route,
1606 .hash_func = (hash_func_t) route_hash_func,
1607 .compare_func = (compare_func_t) route_compare_func,
1608 };
1609
1610 request_detach(link->manager, &req);
1611 route_cancel_requesting(route);
1612 }
1613
1614 static int process_route_one(
1615 Manager *manager,
1616 Link *link,
1617 uint16_t type,
1618 Route *in,
1619 const struct rta_cacheinfo *cacheinfo) {
1620
1621 _cleanup_(route_freep) Route *tmp = in;
1622 Route *route = NULL;
1623 bool update_dhcp4;
1624 int r;
1625
1626 assert(manager);
1627 assert(tmp);
1628 assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE));
1629
1630 /* link may be NULL. This consumes 'in'. */
1631
1632 update_dhcp4 = link && tmp->family == AF_INET6 && tmp->dst_prefixlen == 0;
1633
1634 (void) route_get(manager, link, tmp, &route);
1635
1636 switch (type) {
1637 case RTM_NEWROUTE:
1638 if (route) {
1639 route->flags = tmp->flags;
1640 route_enter_configured(route);
1641 log_route_debug(route, "Received remembered", link, manager);
1642
1643 r = route_setup_timer(route, cacheinfo);
1644 if (r < 0)
1645 log_link_warning_errno(link, r, "Failed to configure expiration timer for route, ignoring: %m");
1646 if (r > 0)
1647 log_route_debug(route, "Configured expiration timer for", link, manager);
1648
1649 } else if (!manager->manage_foreign_routes) {
1650 route_enter_configured(tmp);
1651 log_route_debug(tmp, "Ignoring received", link, manager);
1652
1653 } else {
1654 /* A route appeared that we did not request */
1655 route_enter_configured(tmp);
1656 log_route_debug(tmp, "Received new", link, manager);
1657 r = route_add(manager, link, tmp);
1658 if (r < 0) {
1659 log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
1660 return 0;
1661 }
1662 TAKE_PTR(tmp);
1663 }
1664
1665 break;
1666
1667 case RTM_DELROUTE:
1668 if (route) {
1669 route_enter_removed(route);
1670 if (route->state == 0) {
1671 log_route_debug(route, "Forgetting", link, manager);
1672 route_free(route);
1673 } else
1674 log_route_debug(route, "Removed", link, manager);
1675 } else
1676 log_route_debug(tmp,
1677 manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received",
1678 link, manager);
1679
1680 break;
1681
1682 default:
1683 assert_not_reached();
1684 }
1685
1686 if (update_dhcp4) {
1687 r = dhcp4_update_ipv6_connectivity(link);
1688 if (r < 0) {
1689 log_link_warning_errno(link, r, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");
1690 link_enter_failed(link);
1691 }
1692 }
1693
1694 return 1;
1695 }
1696
1697 int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
1698 _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
1699 _cleanup_(route_freep) Route *tmp = NULL;
1700 _cleanup_free_ void *rta_multipath = NULL;
1701 struct rta_cacheinfo cacheinfo;
1702 bool has_cacheinfo;
1703 Link *link = NULL;
1704 uint32_t ifindex;
1705 uint16_t type;
1706 size_t rta_len;
1707 int r;
1708
1709 assert(rtnl);
1710 assert(message);
1711 assert(m);
1712
1713 if (sd_netlink_message_is_error(message)) {
1714 r = sd_netlink_message_get_errno(message);
1715 if (r < 0)
1716 log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
1717
1718 return 0;
1719 }
1720
1721 r = sd_netlink_message_get_type(message, &type);
1722 if (r < 0) {
1723 log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
1724 return 0;
1725 } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
1726 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
1727 return 0;
1728 }
1729
1730 r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
1731 if (r < 0 && r != -ENODATA) {
1732 log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
1733 return 0;
1734 } else if (r >= 0) {
1735 if (ifindex <= 0) {
1736 log_warning("rtnl: received route message with invalid ifindex %u, ignoring.", ifindex);
1737 return 0;
1738 }
1739
1740 r = link_get_by_index(m, ifindex, &link);
1741 if (r < 0) {
1742 /* when enumerating we might be out of sync, but we will
1743 * get the route again, so just ignore it */
1744 if (!m->enumerating)
1745 log_warning("rtnl: received route message for link (%u) we do not know about, ignoring", ifindex);
1746 return 0;
1747 }
1748 }
1749
1750 r = route_new(&tmp);
1751 if (r < 0)
1752 return log_oom();
1753
1754 r = sd_rtnl_message_route_get_family(message, &tmp->family);
1755 if (r < 0) {
1756 log_link_warning(link, "rtnl: received route message without family, ignoring");
1757 return 0;
1758 } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
1759 log_link_debug(link, "rtnl: received route message with invalid family '%i', ignoring", tmp->family);
1760 return 0;
1761 }
1762
1763 r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
1764 if (r < 0) {
1765 log_warning_errno(r, "rtnl: received route message without route protocol, ignoring: %m");
1766 return 0;
1767 }
1768
1769 r = sd_rtnl_message_route_get_flags(message, &tmp->flags);
1770 if (r < 0) {
1771 log_warning_errno(r, "rtnl: received route message without route flags, ignoring: %m");
1772 return 0;
1773 }
1774
1775 r = netlink_message_read_in_addr_union(message, RTA_DST, tmp->family, &tmp->dst);
1776 if (r < 0 && r != -ENODATA) {
1777 log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
1778 return 0;
1779 }
1780
1781 r = netlink_message_read_in_addr_union(message, RTA_GATEWAY, tmp->family, &tmp->gw);
1782 if (r < 0 && r != -ENODATA) {
1783 log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
1784 return 0;
1785 } else if (r >= 0)
1786 tmp->gw_family = tmp->family;
1787 else if (tmp->family == AF_INET) {
1788 RouteVia via;
1789
1790 r = sd_netlink_message_read(message, RTA_VIA, sizeof(via), &via);
1791 if (r < 0 && r != -ENODATA) {
1792 log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
1793 return 0;
1794 } else if (r >= 0) {
1795 tmp->gw_family = via.family;
1796 tmp->gw = via.address;
1797 }
1798 }
1799
1800 r = netlink_message_read_in_addr_union(message, RTA_SRC, tmp->family, &tmp->src);
1801 if (r < 0 && r != -ENODATA) {
1802 log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
1803 return 0;
1804 }
1805
1806 r = netlink_message_read_in_addr_union(message, RTA_PREFSRC, tmp->family, &tmp->prefsrc);
1807 if (r < 0 && r != -ENODATA) {
1808 log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
1809 return 0;
1810 }
1811
1812 r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
1813 if (r < 0) {
1814 log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1815 return 0;
1816 }
1817
1818 r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
1819 if (r < 0) {
1820 log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1821 return 0;
1822 }
1823
1824 r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
1825 if (r < 0) {
1826 log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m");
1827 return 0;
1828 }
1829
1830 r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
1831 if (r < 0) {
1832 log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m");
1833 return 0;
1834 }
1835
1836 r = sd_rtnl_message_route_get_type(message, &tmp->type);
1837 if (r < 0) {
1838 log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m");
1839 return 0;
1840 }
1841
1842 r = sd_netlink_message_read_u32(message, RTA_TABLE, &tmp->table);
1843 if (r == -ENODATA) {
1844 unsigned char table;
1845
1846 r = sd_rtnl_message_route_get_table(message, &table);
1847 if (r >= 0)
1848 tmp->table = table;
1849 }
1850 if (r < 0) {
1851 log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m");
1852 return 0;
1853 }
1854
1855 r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
1856 if (r < 0 && r != -ENODATA) {
1857 log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
1858 return 0;
1859 }
1860
1861 r = sd_netlink_message_read_u32(message, RTA_NH_ID, &tmp->nexthop_id);
1862 if (r < 0 && r != -ENODATA) {
1863 log_link_warning_errno(link, r, "rtnl: received route message with invalid nexthop id, ignoring: %m");
1864 return 0;
1865 }
1866
1867 r = sd_netlink_message_enter_container(message, RTA_METRICS);
1868 if (r < 0 && r != -ENODATA) {
1869 log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container, ignoring: %m");
1870 return 0;
1871 }
1872 if (r >= 0) {
1873 r = sd_netlink_message_read_u32(message, RTAX_INITCWND, &tmp->initcwnd);
1874 if (r < 0 && r != -ENODATA) {
1875 log_link_warning_errno(link, r, "rtnl: received route message with invalid initcwnd, ignoring: %m");
1876 return 0;
1877 }
1878
1879 r = sd_netlink_message_read_u32(message, RTAX_INITRWND, &tmp->initrwnd);
1880 if (r < 0 && r != -ENODATA) {
1881 log_link_warning_errno(link, r, "rtnl: received route message with invalid initrwnd, ignoring: %m");
1882 return 0;
1883 }
1884
1885 r = sd_netlink_message_read_u32(message, RTAX_ADVMSS, &tmp->advmss);
1886 if (r < 0 && r != -ENODATA) {
1887 log_link_warning_errno(link, r, "rtnl: received route message with invalid advmss, ignoring: %m");
1888 return 0;
1889 }
1890
1891 r = sd_netlink_message_exit_container(message);
1892 if (r < 0) {
1893 log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container, ignoring: %m");
1894 return 0;
1895 }
1896 }
1897
1898 r = sd_netlink_message_read_data(message, RTA_MULTIPATH, &rta_len, &rta_multipath);
1899 if (r < 0 && r != -ENODATA) {
1900 log_link_warning_errno(link, r, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
1901 return 0;
1902 } else if (r >= 0) {
1903 r = rtattr_read_nexthop(rta_multipath, rta_len, tmp->family, &tmp->multipath_routes);
1904 if (r < 0) {
1905 log_link_warning_errno(link, r, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
1906 return 0;
1907 }
1908 }
1909
1910 r = sd_netlink_message_read(message, RTA_CACHEINFO, sizeof(cacheinfo), &cacheinfo);
1911 if (r < 0 && r != -ENODATA) {
1912 log_link_warning_errno(link, r, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1913 return 0;
1914 }
1915 has_cacheinfo = r >= 0;
1916
1917 /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
1918 * fib6_nh_init() in net/ipv6/route.c. However, we'd like to manage them by Manager. Hence, set
1919 * link to NULL here. */
1920 if (route_type_is_reject(tmp))
1921 link = NULL;
1922
1923 if (!route_needs_convert(tmp))
1924 return process_route_one(m, link, type, TAKE_PTR(tmp), has_cacheinfo ? &cacheinfo : NULL);
1925
1926 r = route_convert(m, tmp, &converted);
1927 if (r < 0) {
1928 log_link_warning_errno(link, r, "rtnl: failed to convert received route, ignoring: %m");
1929 return 0;
1930 }
1931
1932 assert(r > 0);
1933 assert(converted);
1934
1935 for (size_t i = 0; i < converted->n; i++)
1936 (void) process_route_one(m,
1937 converted->links[i] ?: link,
1938 type,
1939 TAKE_PTR(converted->routes[i]),
1940 has_cacheinfo ? &cacheinfo : NULL);
1941
1942 return 1;
1943 }
1944
1945 int network_add_ipv4ll_route(Network *network) {
1946 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1947 unsigned section_line;
1948 int r;
1949
1950 assert(network);
1951
1952 if (!network->ipv4ll_route)
1953 return 0;
1954
1955 r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
1956 if (r < 0)
1957 return r;
1958
1959 /* IPv4LLRoute= is in [Network] section. */
1960 r = route_new_static(network, network->filename, section_line, &n);
1961 if (r < 0)
1962 return r;
1963
1964 r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
1965 if (r < 0)
1966 return r;
1967
1968 n->family = AF_INET;
1969 n->dst_prefixlen = 16;
1970 n->scope = RT_SCOPE_LINK;
1971 n->scope_set = true;
1972 n->table_set = true;
1973 n->priority = IPV4LL_ROUTE_METRIC;
1974 n->protocol = RTPROT_STATIC;
1975
1976 TAKE_PTR(n);
1977 return 0;
1978 }
1979
1980 int network_add_default_route_on_device(Network *network) {
1981 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1982 unsigned section_line;
1983 int r;
1984
1985 assert(network);
1986
1987 if (!network->default_route_on_device)
1988 return 0;
1989
1990 r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
1991 if (r < 0)
1992 return r;
1993
1994 /* DefaultRouteOnDevice= is in [Network] section. */
1995 r = route_new_static(network, network->filename, section_line, &n);
1996 if (r < 0)
1997 return r;
1998
1999 n->family = AF_INET;
2000 n->scope = RT_SCOPE_LINK;
2001 n->scope_set = true;
2002 n->protocol = RTPROT_STATIC;
2003
2004 TAKE_PTR(n);
2005 return 0;
2006 }
2007
2008 int config_parse_gateway(
2009 const char *unit,
2010 const char *filename,
2011 unsigned line,
2012 const char *section,
2013 unsigned section_line,
2014 const char *lvalue,
2015 int ltype,
2016 const char *rvalue,
2017 void *data,
2018 void *userdata) {
2019
2020 Network *network = userdata;
2021 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2022 int r;
2023
2024 assert(filename);
2025 assert(section);
2026 assert(lvalue);
2027 assert(rvalue);
2028 assert(data);
2029
2030 if (streq(section, "Network")) {
2031 /* we are not in an Route section, so use line number instead */
2032 r = route_new_static(network, filename, line, &n);
2033 if (r == -ENOMEM)
2034 return log_oom();
2035 if (r < 0) {
2036 log_syntax(unit, LOG_WARNING, filename, line, r,
2037 "Failed to allocate route, ignoring assignment: %m");
2038 return 0;
2039 }
2040 } else {
2041 r = route_new_static(network, filename, section_line, &n);
2042 if (r == -ENOMEM)
2043 return log_oom();
2044 if (r < 0) {
2045 log_syntax(unit, LOG_WARNING, filename, line, r,
2046 "Failed to allocate route, ignoring assignment: %m");
2047 return 0;
2048 }
2049
2050 if (isempty(rvalue)) {
2051 n->gateway_from_dhcp_or_ra = false;
2052 n->gw_family = AF_UNSPEC;
2053 n->gw = IN_ADDR_NULL;
2054 TAKE_PTR(n);
2055 return 0;
2056 }
2057
2058 if (streq(rvalue, "_dhcp")) {
2059 n->gateway_from_dhcp_or_ra = true;
2060 TAKE_PTR(n);
2061 return 0;
2062 }
2063
2064 if (streq(rvalue, "_dhcp4")) {
2065 n->gw_family = AF_INET;
2066 n->gateway_from_dhcp_or_ra = true;
2067 TAKE_PTR(n);
2068 return 0;
2069 }
2070
2071 if (streq(rvalue, "_ipv6ra")) {
2072 n->gw_family = AF_INET6;
2073 n->gateway_from_dhcp_or_ra = true;
2074 TAKE_PTR(n);
2075 return 0;
2076 }
2077 }
2078
2079 r = in_addr_from_string_auto(rvalue, &n->gw_family, &n->gw);
2080 if (r < 0) {
2081 log_syntax(unit, LOG_WARNING, filename, line, r,
2082 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
2083 return 0;
2084 }
2085
2086 n->gateway_from_dhcp_or_ra = false;
2087 TAKE_PTR(n);
2088 return 0;
2089 }
2090
2091 int config_parse_preferred_src(
2092 const char *unit,
2093 const char *filename,
2094 unsigned line,
2095 const char *section,
2096 unsigned section_line,
2097 const char *lvalue,
2098 int ltype,
2099 const char *rvalue,
2100 void *data,
2101 void *userdata) {
2102
2103 Network *network = userdata;
2104 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2105 int r;
2106
2107 assert(filename);
2108 assert(section);
2109 assert(lvalue);
2110 assert(rvalue);
2111 assert(data);
2112
2113 r = route_new_static(network, filename, section_line, &n);
2114 if (r == -ENOMEM)
2115 return log_oom();
2116 if (r < 0) {
2117 log_syntax(unit, LOG_WARNING, filename, line, r,
2118 "Failed to allocate route, ignoring assignment: %m");
2119 return 0;
2120 }
2121
2122 if (n->family == AF_UNSPEC)
2123 r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
2124 else
2125 r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
2126 if (r < 0) {
2127 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
2128 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
2129 return 0;
2130 }
2131
2132 TAKE_PTR(n);
2133 return 0;
2134 }
2135
2136 int config_parse_destination(
2137 const char *unit,
2138 const char *filename,
2139 unsigned line,
2140 const char *section,
2141 unsigned section_line,
2142 const char *lvalue,
2143 int ltype,
2144 const char *rvalue,
2145 void *data,
2146 void *userdata) {
2147
2148 Network *network = userdata;
2149 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2150 union in_addr_union *buffer;
2151 unsigned char *prefixlen;
2152 int r;
2153
2154 assert(filename);
2155 assert(section);
2156 assert(lvalue);
2157 assert(rvalue);
2158 assert(data);
2159
2160 r = route_new_static(network, filename, section_line, &n);
2161 if (r == -ENOMEM)
2162 return log_oom();
2163 if (r < 0) {
2164 log_syntax(unit, LOG_WARNING, filename, line, r,
2165 "Failed to allocate route, ignoring assignment: %m");
2166 return 0;
2167 }
2168
2169 if (streq(lvalue, "Destination")) {
2170 buffer = &n->dst;
2171 prefixlen = &n->dst_prefixlen;
2172 } else if (streq(lvalue, "Source")) {
2173 buffer = &n->src;
2174 prefixlen = &n->src_prefixlen;
2175 } else
2176 assert_not_reached();
2177
2178 if (n->family == AF_UNSPEC)
2179 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
2180 else
2181 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
2182 if (r < 0) {
2183 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
2184 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
2185 return 0;
2186 }
2187
2188 (void) in_addr_mask(n->family, buffer, *prefixlen);
2189
2190 TAKE_PTR(n);
2191 return 0;
2192 }
2193
2194 int config_parse_route_priority(
2195 const char *unit,
2196 const char *filename,
2197 unsigned line,
2198 const char *section,
2199 unsigned section_line,
2200 const char *lvalue,
2201 int ltype,
2202 const char *rvalue,
2203 void *data,
2204 void *userdata) {
2205
2206 Network *network = userdata;
2207 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2208 int r;
2209
2210 assert(filename);
2211 assert(section);
2212 assert(lvalue);
2213 assert(rvalue);
2214 assert(data);
2215
2216 r = route_new_static(network, filename, section_line, &n);
2217 if (r == -ENOMEM)
2218 return log_oom();
2219 if (r < 0) {
2220 log_syntax(unit, LOG_WARNING, filename, line, r,
2221 "Failed to allocate route, ignoring assignment: %m");
2222 return 0;
2223 }
2224
2225 r = safe_atou32(rvalue, &n->priority);
2226 if (r < 0) {
2227 log_syntax(unit, LOG_WARNING, filename, line, r,
2228 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
2229 return 0;
2230 }
2231
2232 n->priority_set = true;
2233 TAKE_PTR(n);
2234 return 0;
2235 }
2236
2237 int config_parse_route_scope(
2238 const char *unit,
2239 const char *filename,
2240 unsigned line,
2241 const char *section,
2242 unsigned section_line,
2243 const char *lvalue,
2244 int ltype,
2245 const char *rvalue,
2246 void *data,
2247 void *userdata) {
2248
2249 Network *network = userdata;
2250 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2251 int r;
2252
2253 assert(filename);
2254 assert(section);
2255 assert(lvalue);
2256 assert(rvalue);
2257 assert(data);
2258
2259 r = route_new_static(network, filename, section_line, &n);
2260 if (r == -ENOMEM)
2261 return log_oom();
2262 if (r < 0) {
2263 log_syntax(unit, LOG_WARNING, filename, line, r,
2264 "Failed to allocate route, ignoring assignment: %m");
2265 return 0;
2266 }
2267
2268 r = route_scope_from_string(rvalue);
2269 if (r < 0) {
2270 log_syntax(unit, LOG_WARNING, filename, line, r, "Unknown route scope: %s", rvalue);
2271 return 0;
2272 }
2273
2274 n->scope = r;
2275 n->scope_set = true;
2276 TAKE_PTR(n);
2277 return 0;
2278 }
2279
2280 int config_parse_route_nexthop(
2281 const char *unit,
2282 const char *filename,
2283 unsigned line,
2284 const char *section,
2285 unsigned section_line,
2286 const char *lvalue,
2287 int ltype,
2288 const char *rvalue,
2289 void *data,
2290 void *userdata) {
2291
2292 Network *network = userdata;
2293 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2294 uint32_t id;
2295 int r;
2296
2297 assert(filename);
2298 assert(section);
2299 assert(lvalue);
2300 assert(rvalue);
2301 assert(data);
2302
2303 r = route_new_static(network, filename, section_line, &n);
2304 if (r == -ENOMEM)
2305 return log_oom();
2306 if (r < 0) {
2307 log_syntax(unit, LOG_WARNING, filename, line, r,
2308 "Failed to allocate route, ignoring assignment: %m");
2309 return 0;
2310 }
2311
2312 if (isempty(rvalue)) {
2313 n->nexthop_id = 0;
2314 TAKE_PTR(n);
2315 return 0;
2316 }
2317
2318 r = safe_atou32(rvalue, &id);
2319 if (r < 0) {
2320 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue);
2321 return 0;
2322 }
2323 if (id == 0) {
2324 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue);
2325 return 0;
2326 }
2327
2328 n->nexthop_id = id;
2329 TAKE_PTR(n);
2330 return 0;
2331 }
2332
2333 int config_parse_route_table(
2334 const char *unit,
2335 const char *filename,
2336 unsigned line,
2337 const char *section,
2338 unsigned section_line,
2339 const char *lvalue,
2340 int ltype,
2341 const char *rvalue,
2342 void *data,
2343 void *userdata) {
2344
2345 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2346 Network *network = userdata;
2347 int r;
2348
2349 assert(filename);
2350 assert(section);
2351 assert(lvalue);
2352 assert(rvalue);
2353 assert(data);
2354
2355 r = route_new_static(network, filename, section_line, &n);
2356 if (r == -ENOMEM)
2357 return log_oom();
2358 if (r < 0) {
2359 log_syntax(unit, LOG_WARNING, filename, line, r,
2360 "Failed to allocate route, ignoring assignment: %m");
2361 return 0;
2362 }
2363
2364 r = manager_get_route_table_from_string(network->manager, rvalue, &n->table);
2365 if (r < 0) {
2366 log_syntax(unit, LOG_WARNING, filename, line, r,
2367 "Could not parse route table \"%s\", ignoring assignment: %m", rvalue);
2368 return 0;
2369 }
2370
2371 n->table_set = true;
2372 TAKE_PTR(n);
2373 return 0;
2374 }
2375
2376 int config_parse_route_boolean(
2377 const char *unit,
2378 const char *filename,
2379 unsigned line,
2380 const char *section,
2381 unsigned section_line,
2382 const char *lvalue,
2383 int ltype,
2384 const char *rvalue,
2385 void *data,
2386 void *userdata) {
2387
2388 Network *network = userdata;
2389 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2390 int r;
2391
2392 assert(filename);
2393 assert(section);
2394 assert(lvalue);
2395 assert(rvalue);
2396 assert(data);
2397
2398 r = route_new_static(network, filename, section_line, &n);
2399 if (r == -ENOMEM)
2400 return log_oom();
2401 if (r < 0) {
2402 log_syntax(unit, LOG_WARNING, filename, line, r,
2403 "Failed to allocate route, ignoring assignment: %m");
2404 return 0;
2405 }
2406
2407 r = parse_boolean(rvalue);
2408 if (r < 0) {
2409 log_syntax(unit, LOG_WARNING, filename, line, r,
2410 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
2411 return 0;
2412 }
2413
2414 if (STR_IN_SET(lvalue, "GatewayOnLink", "GatewayOnlink"))
2415 n->gateway_onlink = r;
2416 else if (streq(lvalue, "QuickAck"))
2417 n->quickack = r;
2418 else if (streq(lvalue, "FastOpenNoCookie"))
2419 n->fast_open_no_cookie = r;
2420 else if (streq(lvalue, "TTLPropagate"))
2421 n->ttl_propagate = r;
2422 else
2423 assert_not_reached();
2424
2425 TAKE_PTR(n);
2426 return 0;
2427 }
2428
2429 int config_parse_ipv6_route_preference(
2430 const char *unit,
2431 const char *filename,
2432 unsigned line,
2433 const char *section,
2434 unsigned section_line,
2435 const char *lvalue,
2436 int ltype,
2437 const char *rvalue,
2438 void *data,
2439 void *userdata) {
2440
2441 Network *network = userdata;
2442 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2443 int r;
2444
2445 r = route_new_static(network, filename, section_line, &n);
2446 if (r == -ENOMEM)
2447 return log_oom();
2448 if (r < 0) {
2449 log_syntax(unit, LOG_WARNING, filename, line, r,
2450 "Failed to allocate route, ignoring assignment: %m");
2451 return 0;
2452 }
2453
2454 if (streq(rvalue, "low"))
2455 n->pref = ICMPV6_ROUTER_PREF_LOW;
2456 else if (streq(rvalue, "medium"))
2457 n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
2458 else if (streq(rvalue, "high"))
2459 n->pref = ICMPV6_ROUTER_PREF_HIGH;
2460 else {
2461 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route preference: %s", rvalue);
2462 return 0;
2463 }
2464
2465 n->pref_set = true;
2466 TAKE_PTR(n);
2467 return 0;
2468 }
2469
2470 int config_parse_route_protocol(
2471 const char *unit,
2472 const char *filename,
2473 unsigned line,
2474 const char *section,
2475 unsigned section_line,
2476 const char *lvalue,
2477 int ltype,
2478 const char *rvalue,
2479 void *data,
2480 void *userdata) {
2481
2482 Network *network = userdata;
2483 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2484 int r;
2485
2486 r = route_new_static(network, filename, section_line, &n);
2487 if (r == -ENOMEM)
2488 return log_oom();
2489 if (r < 0) {
2490 log_syntax(unit, LOG_WARNING, filename, line, r,
2491 "Failed to allocate route, ignoring assignment: %m");
2492 return 0;
2493 }
2494
2495 r = route_protocol_from_string(rvalue);
2496 if (r < 0) {
2497 log_syntax(unit, LOG_WARNING, filename, line, r,
2498 "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue);
2499 return 0;
2500 }
2501
2502 n->protocol = r;
2503
2504 TAKE_PTR(n);
2505 return 0;
2506 }
2507
2508 int config_parse_route_type(
2509 const char *unit,
2510 const char *filename,
2511 unsigned line,
2512 const char *section,
2513 unsigned section_line,
2514 const char *lvalue,
2515 int ltype,
2516 const char *rvalue,
2517 void *data,
2518 void *userdata) {
2519
2520 Network *network = userdata;
2521 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2522 int t, r;
2523
2524 r = route_new_static(network, filename, section_line, &n);
2525 if (r == -ENOMEM)
2526 return log_oom();
2527 if (r < 0) {
2528 log_syntax(unit, LOG_WARNING, filename, line, r,
2529 "Failed to allocate route, ignoring assignment: %m");
2530 return 0;
2531 }
2532
2533 t = route_type_from_string(rvalue);
2534 if (t < 0) {
2535 log_syntax(unit, LOG_WARNING, filename, line, r,
2536 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
2537 return 0;
2538 }
2539
2540 n->type = (unsigned char) t;
2541
2542 TAKE_PTR(n);
2543 return 0;
2544 }
2545
2546 int config_parse_route_hop_limit(
2547 const char *unit,
2548 const char *filename,
2549 unsigned line,
2550 const char *section,
2551 unsigned section_line,
2552 const char *lvalue,
2553 int ltype,
2554 const char *rvalue,
2555 void *data,
2556 void *userdata) {
2557
2558 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2559 Network *network = userdata;
2560 uint32_t k;
2561 int r;
2562
2563 assert(filename);
2564 assert(section);
2565 assert(lvalue);
2566 assert(rvalue);
2567 assert(data);
2568
2569 r = route_new_static(network, filename, section_line, &n);
2570 if (r == -ENOMEM)
2571 return log_oom();
2572 if (r < 0) {
2573 log_syntax(unit, LOG_WARNING, filename, line, r,
2574 "Failed to allocate route, ignoring assignment: %m");
2575 return 0;
2576 }
2577
2578 if (isempty(rvalue)) {
2579 n->hop_limit = 0;
2580 TAKE_PTR(n);
2581 return 0;
2582 }
2583
2584 r = safe_atou32(rvalue, &k);
2585 if (r < 0) {
2586 log_syntax(unit, LOG_WARNING, filename, line, r,
2587 "Could not parse per route hop limit, ignoring assignment: %s", rvalue);
2588 return 0;
2589 }
2590 if (k > 255) {
2591 log_syntax(unit, LOG_WARNING, filename, line, 0,
2592 "Specified per route hop limit \"%s\" is too large, ignoring assignment: %m", rvalue);
2593 return 0;
2594 }
2595 if (k == 0) {
2596 log_syntax(unit, LOG_WARNING, filename, line, 0,
2597 "Invalid per route hop limit \"%s\", ignoring assignment: %m", rvalue);
2598 return 0;
2599 }
2600
2601 n->hop_limit = k;
2602
2603 TAKE_PTR(n);
2604 return 0;
2605 }
2606
2607 int config_parse_tcp_congestion(
2608 const char *unit,
2609 const char *filename,
2610 unsigned line,
2611 const char *section,
2612 unsigned section_line,
2613 const char *lvalue,
2614 int ltype,
2615 const char *rvalue,
2616 void *data,
2617 void *userdata) {
2618
2619 Network *network = userdata;
2620 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2621 int r;
2622
2623 assert(filename);
2624 assert(section);
2625 assert(lvalue);
2626 assert(rvalue);
2627 assert(data);
2628
2629 r = route_new_static(network, filename, section_line, &n);
2630 if (r == -ENOMEM)
2631 return log_oom();
2632 if (r < 0) {
2633 log_syntax(unit, LOG_WARNING, filename, line, r,
2634 "Failed to allocate route, ignoring assignment: %m");
2635 return 0;
2636 }
2637
2638 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
2639 rvalue, &n->tcp_congestion_control_algo, userdata);
2640 if (r < 0)
2641 return r;
2642
2643 TAKE_PTR(n);
2644 return 0;
2645 }
2646
2647 int config_parse_tcp_advmss(
2648 const char *unit,
2649 const char *filename,
2650 unsigned line,
2651 const char *section,
2652 unsigned section_line,
2653 const char *lvalue,
2654 int ltype,
2655 const char *rvalue,
2656 void *data,
2657 void *userdata) {
2658
2659 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2660 Network *network = userdata;
2661 uint64_t u;
2662 int r;
2663
2664 assert(filename);
2665 assert(section);
2666 assert(lvalue);
2667 assert(rvalue);
2668 assert(data);
2669
2670 r = route_new_static(network, filename, section_line, &n);
2671 if (r == -ENOMEM)
2672 return log_oom();
2673 if (r < 0) {
2674 log_syntax(unit, LOG_WARNING, filename, line, r,
2675 "Failed to allocate route, ignoring assignment: %m");
2676 return 0;
2677 }
2678
2679 if (isempty(rvalue)) {
2680 n->advmss = 0;
2681 TAKE_PTR(n);
2682 return 0;
2683 }
2684
2685 r = parse_size(rvalue, 1024, &u);
2686 if (r < 0) {
2687 log_syntax(unit, LOG_WARNING, filename, line, r,
2688 "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue);
2689 return 0;
2690 }
2691
2692 if (u == 0 || u > UINT32_MAX) {
2693 log_syntax(unit, LOG_WARNING, filename, line, 0,
2694 "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue);
2695 return 0;
2696 }
2697
2698 n->advmss = u;
2699
2700 TAKE_PTR(n);
2701 return 0;
2702 }
2703
2704 int config_parse_tcp_window(
2705 const char *unit,
2706 const char *filename,
2707 unsigned line,
2708 const char *section,
2709 unsigned section_line,
2710 const char *lvalue,
2711 int ltype,
2712 const char *rvalue,
2713 void *data,
2714 void *userdata) {
2715
2716 uint32_t *window = ASSERT_PTR(data);
2717 uint32_t k;
2718 int r;
2719
2720 assert(filename);
2721 assert(section);
2722 assert(lvalue);
2723 assert(rvalue);
2724 assert(data);
2725
2726 r = safe_atou32(rvalue, &k);
2727 if (r < 0) {
2728 log_syntax(unit, LOG_WARNING, filename, line, r,
2729 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
2730 return 0;
2731 }
2732 if (k >= 1024) {
2733 log_syntax(unit, LOG_WARNING, filename, line, 0,
2734 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
2735 return 0;
2736 }
2737 if (k == 0) {
2738 log_syntax(unit, LOG_WARNING, filename, line, 0,
2739 "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
2740 return 0;
2741 }
2742
2743 *window = k;
2744 return 0;
2745 }
2746
2747 int config_parse_route_tcp_window(
2748 const char *unit,
2749 const char *filename,
2750 unsigned line,
2751 const char *section,
2752 unsigned section_line,
2753 const char *lvalue,
2754 int ltype,
2755 const char *rvalue,
2756 void *data,
2757 void *userdata) {
2758
2759 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2760 Network *network = userdata;
2761 uint32_t *d;
2762 int r;
2763
2764 assert(filename);
2765 assert(section);
2766 assert(lvalue);
2767 assert(rvalue);
2768 assert(data);
2769
2770 r = route_new_static(network, filename, section_line, &n);
2771 if (r == -ENOMEM)
2772 return log_oom();
2773 if (r < 0) {
2774 log_syntax(unit, LOG_WARNING, filename, line, r,
2775 "Failed to allocate route, ignoring assignment: %m");
2776 return 0;
2777 }
2778
2779 if (streq(lvalue, "InitialCongestionWindow"))
2780 d = &n->initcwnd;
2781 else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
2782 d = &n->initrwnd;
2783 else
2784 assert_not_reached();
2785
2786 r = config_parse_tcp_window(unit, filename, line, section, section_line, lvalue, ltype, rvalue, d, userdata);
2787 if (r < 0)
2788 return r;
2789
2790 TAKE_PTR(n);
2791 return 0;
2792 }
2793
2794 int config_parse_route_mtu(
2795 const char *unit,
2796 const char *filename,
2797 unsigned line,
2798 const char *section,
2799 unsigned section_line,
2800 const char *lvalue,
2801 int ltype,
2802 const char *rvalue,
2803 void *data,
2804 void *userdata) {
2805
2806 Network *network = userdata;
2807 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2808 int r;
2809
2810 assert(filename);
2811 assert(section);
2812 assert(lvalue);
2813 assert(rvalue);
2814 assert(data);
2815
2816 r = route_new_static(network, filename, section_line, &n);
2817 if (r == -ENOMEM)
2818 return log_oom();
2819 if (r < 0) {
2820 log_syntax(unit, LOG_WARNING, filename, line, r,
2821 "Failed to allocate route, ignoring assignment: %m");
2822 return 0;
2823 }
2824
2825 r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &n->mtu, userdata);
2826 if (r < 0)
2827 return r;
2828
2829 TAKE_PTR(n);
2830 return 0;
2831 }
2832
2833 int config_parse_route_tcp_rto(
2834 const char *unit,
2835 const char *filename,
2836 unsigned line,
2837 const char *section,
2838 unsigned section_line,
2839 const char *lvalue,
2840 int ltype,
2841 const char *rvalue,
2842 void *data,
2843 void *userdata) {
2844
2845 Network *network = userdata;
2846 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2847 usec_t usec;
2848 int r;
2849
2850 assert(filename);
2851 assert(section);
2852 assert(lvalue);
2853 assert(rvalue);
2854 assert(data);
2855
2856 r = route_new_static(network, filename, section_line, &n);
2857 if (r == -ENOMEM)
2858 return log_oom();
2859 if (r < 0) {
2860 log_syntax(unit, LOG_WARNING, filename, line, r,
2861 "Failed to allocate route, ignoring assignment: %m");
2862 return 0;
2863 }
2864
2865 r = parse_sec(rvalue, &usec);
2866 if (r < 0) {
2867 log_syntax(unit, LOG_WARNING, filename, line, r,
2868 "Failed to parse route TCP retransmission timeout (RTO), ignoring assignment: %s", rvalue);
2869 return 0;
2870 }
2871
2872 if (IN_SET(usec, 0, USEC_INFINITY) ||
2873 DIV_ROUND_UP(usec, USEC_PER_MSEC) > UINT32_MAX) {
2874 log_syntax(unit, LOG_WARNING, filename, line, 0,
2875 "Route TCP retransmission timeout (RTO) must be in the range 0…%"PRIu32"ms, ignoring assignment: %s", UINT32_MAX, rvalue);
2876 return 0;
2877 }
2878
2879 n->tcp_rto_usec = usec;
2880
2881 TAKE_PTR(n);
2882 return 0;
2883 }
2884
2885 int config_parse_multipath_route(
2886 const char *unit,
2887 const char *filename,
2888 unsigned line,
2889 const char *section,
2890 unsigned section_line,
2891 const char *lvalue,
2892 int ltype,
2893 const char *rvalue,
2894 void *data,
2895 void *userdata) {
2896
2897 _cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
2898 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2899 _cleanup_free_ char *word = NULL;
2900 Network *network = userdata;
2901 union in_addr_union a;
2902 int family, r;
2903 const char *p;
2904 char *dev;
2905
2906 assert(filename);
2907 assert(section);
2908 assert(lvalue);
2909 assert(rvalue);
2910 assert(data);
2911
2912 r = route_new_static(network, filename, section_line, &n);
2913 if (r == -ENOMEM)
2914 return log_oom();
2915 if (r < 0) {
2916 log_syntax(unit, LOG_WARNING, filename, line, r,
2917 "Failed to allocate route, ignoring assignment: %m");
2918 return 0;
2919 }
2920
2921 if (isempty(rvalue)) {
2922 n->multipath_routes = ordered_set_free_with_destructor(n->multipath_routes, multipath_route_free);
2923 return 0;
2924 }
2925
2926 m = new0(MultipathRoute, 1);
2927 if (!m)
2928 return log_oom();
2929
2930 p = rvalue;
2931 r = extract_first_word(&p, &word, NULL, 0);
2932 if (r == -ENOMEM)
2933 return log_oom();
2934 if (r <= 0) {
2935 log_syntax(unit, LOG_WARNING, filename, line, r,
2936 "Invalid multipath route option, ignoring assignment: %s", rvalue);
2937 return 0;
2938 }
2939
2940 dev = strchr(word, '@');
2941 if (dev) {
2942 *dev++ = '\0';
2943
2944 r = parse_ifindex(dev);
2945 if (r > 0)
2946 m->ifindex = r;
2947 else {
2948 if (!ifname_valid_full(dev, IFNAME_VALID_ALTERNATIVE)) {
2949 log_syntax(unit, LOG_WARNING, filename, line, 0,
2950 "Invalid interface name '%s' in %s=, ignoring: %s", dev, lvalue, rvalue);
2951 return 0;
2952 }
2953
2954 m->ifname = strdup(dev);
2955 if (!m->ifname)
2956 return log_oom();
2957 }
2958 }
2959
2960 r = in_addr_from_string_auto(word, &family, &a);
2961 if (r < 0) {
2962 log_syntax(unit, LOG_WARNING, filename, line, r,
2963 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue);
2964 return 0;
2965 }
2966 m->gateway.address = a;
2967 m->gateway.family = family;
2968
2969 if (!isempty(p)) {
2970 r = safe_atou32(p, &m->weight);
2971 if (r < 0) {
2972 log_syntax(unit, LOG_WARNING, filename, line, r,
2973 "Invalid multipath route weight, ignoring assignment: %s", p);
2974 return 0;
2975 }
2976 /* ip command takes weight in the range 1…255, while kernel takes the value in the
2977 * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip
2978 * command uses, then networkd decreases by one and stores it to match the range which
2979 * kernel uses. */
2980 if (m->weight == 0 || m->weight > 256) {
2981 log_syntax(unit, LOG_WARNING, filename, line, 0,
2982 "Invalid multipath route weight, ignoring assignment: %s", p);
2983 return 0;
2984 }
2985 m->weight--;
2986 }
2987
2988 r = ordered_set_ensure_put(&n->multipath_routes, NULL, m);
2989 if (r == -ENOMEM)
2990 return log_oom();
2991 if (r < 0) {
2992 log_syntax(unit, LOG_WARNING, filename, line, r,
2993 "Failed to store multipath route, ignoring assignment: %m");
2994 return 0;
2995 }
2996
2997 TAKE_PTR(m);
2998 TAKE_PTR(n);
2999 return 0;
3000 }
3001
3002 static int route_section_verify(Route *route, Network *network) {
3003 if (section_is_invalid(route->section))
3004 return -EINVAL;
3005
3006 /* Currently, we do not support static route with finite lifetime. */
3007 assert(route->lifetime_usec == USEC_INFINITY);
3008
3009 if (route->gateway_from_dhcp_or_ra) {
3010 if (route->gw_family == AF_UNSPEC) {
3011 /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
3012 switch (route->family) {
3013 case AF_UNSPEC:
3014 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3015 "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
3016 route->section->filename, route->section->line);
3017 route->family = AF_INET;
3018 break;
3019 case AF_INET:
3020 case AF_INET6:
3021 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3022 "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
3023 route->section->filename, route->section->line, route->family == AF_INET ? "_dhcp4" : "_ipv6ra");
3024 break;
3025 default:
3026 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3027 "%s: Invalid route family. Ignoring [Route] section from line %u.",
3028 route->section->filename, route->section->line);
3029 }
3030 route->gw_family = route->family;
3031 }
3032
3033 if (route->gw_family == AF_INET && !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4))
3034 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3035 "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
3036 "Ignoring [Route] section from line %u.",
3037 route->section->filename, route->section->line);
3038
3039 if (route->gw_family == AF_INET6 && !network->ipv6_accept_ra)
3040 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3041 "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
3042 "Ignoring [Route] section from line %u.",
3043 route->section->filename, route->section->line);
3044 }
3045
3046 /* When only Gateway= is specified, assume the route family based on the Gateway address. */
3047 if (route->family == AF_UNSPEC)
3048 route->family = route->gw_family;
3049
3050 if (route->family == AF_UNSPEC) {
3051 assert(route->section);
3052
3053 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3054 "%s: Route section without Gateway=, Destination=, Source=, "
3055 "or PreferredSource= field configured. "
3056 "Ignoring [Route] section from line %u.",
3057 route->section->filename, route->section->line);
3058 }
3059
3060 if (route->family == AF_INET6 && route->gw_family == AF_INET)
3061 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3062 "%s: IPv4 gateway is configured for IPv6 route. "
3063 "Ignoring [Route] section from line %u.",
3064 route->section->filename, route->section->line);
3065
3066 if (!route->table_set && network->vrf) {
3067 route->table = VRF(network->vrf)->table;
3068 route->table_set = true;
3069 }
3070
3071 if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
3072 route->table = RT_TABLE_LOCAL;
3073
3074 if (!route->scope_set && route->family != AF_INET6) {
3075 if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
3076 route->scope = RT_SCOPE_HOST;
3077 else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
3078 route->scope = RT_SCOPE_LINK;
3079 else if (IN_SET(route->type, RTN_UNICAST, RTN_UNSPEC) &&
3080 !route->gateway_from_dhcp_or_ra &&
3081 !in_addr_is_set(route->gw_family, &route->gw) &&
3082 ordered_set_isempty(route->multipath_routes) &&
3083 route->nexthop_id == 0)
3084 route->scope = RT_SCOPE_LINK;
3085 }
3086
3087 if (route->scope != RT_SCOPE_UNIVERSE && route->family == AF_INET6) {
3088 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route->section->filename);
3089 route->scope = RT_SCOPE_UNIVERSE;
3090 }
3091
3092 if (route->family == AF_INET6 && route->priority == 0)
3093 route->priority = IP6_RT_PRIO_USER;
3094
3095 if (route->gateway_onlink < 0 && in_addr_is_set(route->gw_family, &route->gw) &&
3096 ordered_hashmap_isempty(network->addresses_by_section)) {
3097 /* If no address is configured, in most cases the gateway cannot be reachable.
3098 * TODO: we may need to improve the condition above. */
3099 log_warning("%s: Gateway= without static address configured. "
3100 "Enabling GatewayOnLink= option.",
3101 network->filename);
3102 route->gateway_onlink = true;
3103 }
3104
3105 if (route->gateway_onlink >= 0)
3106 SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
3107
3108 if (route->family == AF_INET6) {
3109 MultipathRoute *m;
3110
3111 ORDERED_SET_FOREACH(m, route->multipath_routes)
3112 if (m->gateway.family == AF_INET)
3113 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3114 "%s: IPv4 multipath route is specified for IPv6 route. "
3115 "Ignoring [Route] section from line %u.",
3116 route->section->filename, route->section->line);
3117 }
3118
3119 if ((route->gateway_from_dhcp_or_ra ||
3120 in_addr_is_set(route->gw_family, &route->gw)) &&
3121 !ordered_set_isempty(route->multipath_routes))
3122 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3123 "%s: Gateway= cannot be specified with MultiPathRoute=. "
3124 "Ignoring [Route] section from line %u.",
3125 route->section->filename, route->section->line);
3126
3127 if (route->nexthop_id > 0 &&
3128 (route->gateway_from_dhcp_or_ra ||
3129 in_addr_is_set(route->gw_family, &route->gw) ||
3130 !ordered_set_isempty(route->multipath_routes)))
3131 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3132 "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
3133 "Ignoring [Route] section from line %u.",
3134 route->section->filename, route->section->line);
3135
3136 return 0;
3137 }
3138
3139 void network_drop_invalid_routes(Network *network) {
3140 Route *route;
3141
3142 assert(network);
3143
3144 HASHMAP_FOREACH(route, network->routes_by_section)
3145 if (route_section_verify(route, network) < 0)
3146 route_free(route);
3147 }