]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-route.c
Merge pull request #31777 from keszybz/unit-retitling-and-comments
[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 static Route* route_detach_impl(Route *route) {
25 assert(route);
26 assert(!!route->network + !!route->manager + !!route->wireguard <= 1);
27
28 if (route->network) {
29 assert(route->section);
30 hashmap_remove(route->network->routes_by_section, route->section);
31 route->network = NULL;
32 return route;
33 }
34
35 if (route->manager) {
36 route_detach_from_nexthop(route);
37 set_remove(route->manager->routes, route);
38 route->manager = NULL;
39 return route;
40 }
41
42 if (route->wireguard) {
43 set_remove(route->wireguard->routes, route);
44 route->wireguard = NULL;
45 return route;
46 }
47
48 return NULL;
49 }
50
51 static void route_detach(Route *route) {
52 route_unref(route_detach_impl(route));
53 }
54
55 static Route* route_free(Route *route) {
56 if (!route)
57 return NULL;
58
59 route_detach_impl(route);
60
61 config_section_free(route->section);
62 route_nexthops_done(route);
63 route_metric_done(&route->metric);
64 sd_event_source_disable_unref(route->expire);
65
66 return mfree(route);
67 }
68
69 DEFINE_TRIVIAL_REF_UNREF_FUNC(Route, route, route_free);
70
71 static void route_hash_func(const Route *route, struct siphash *state) {
72 assert(route);
73
74 siphash24_compress_typesafe(route->family, state);
75
76 switch (route->family) {
77 case AF_INET:
78 /* First, the table, destination prefix, priority, and tos (dscp), are used to find routes.
79 * See fib_table_insert(), fib_find_node(), and fib_find_alias() in net/ipv4/fib_trie.c of the kernel. */
80 siphash24_compress_typesafe(route->table, state);
81 in_addr_hash_func(&route->dst, route->family, state);
82 siphash24_compress_typesafe(route->dst_prefixlen, state);
83 siphash24_compress_typesafe(route->priority, state);
84 siphash24_compress_typesafe(route->tos, state);
85
86 /* Then, protocol, scope, type, flags, prefsrc, metrics (RTAX_* attributes), and nexthops (gateways)
87 * are used to find routes. See fib_find_info() in net/ipv4/fib_semantics.c of the kernel. */
88 siphash24_compress_typesafe(route->protocol, state);
89 siphash24_compress_typesafe(route->scope, state);
90 siphash24_compress_typesafe(route->type, state);
91 unsigned flags = route->flags & ~RTNH_COMPARE_MASK;
92 siphash24_compress_typesafe(flags, state);
93 in_addr_hash_func(&route->prefsrc, route->family, state);
94
95 /* nexthops (id, number of nexthops, nexthop) */
96 route_nexthops_hash_func(route, state);
97
98 /* metrics */
99 route_metric_hash_func(&route->metric, state);
100 break;
101
102 case AF_INET6:
103 /* First, table and destination prefix are used for classifying routes.
104 * See fib6_add() and fib6_add_1() in net/ipv6/ip6_fib.c of the kernel. */
105 siphash24_compress_typesafe(route->table, state);
106 in_addr_hash_func(&route->dst, route->family, state);
107 siphash24_compress_typesafe(route->dst_prefixlen, state);
108
109 /* Then, source prefix is used. See fib6_add(). */
110 in_addr_hash_func(&route->src, route->family, state);
111 siphash24_compress_typesafe(route->src_prefixlen, state);
112
113 /* See fib6_add_rt2node(). */
114 siphash24_compress_typesafe(route->priority, state);
115
116 /* See rt6_duplicate_nexthop() in include/net/ip6_route.h of the kernel.
117 * Here, we hash nexthop in a similar way as the one for IPv4. */
118 route_nexthops_hash_func(route, state);
119
120 /* Unlike IPv4 routes, metrics are not taken into account. */
121 break;
122
123 default:
124 /* treat any other address family as AF_UNSPEC */
125 break;
126 }
127 }
128
129 static int route_compare_func(const Route *a, const Route *b) {
130 int r;
131
132 r = CMP(a->family, b->family);
133 if (r != 0)
134 return r;
135
136 switch (a->family) {
137 case AF_INET:
138 r = CMP(a->table, b->table);
139 if (r != 0)
140 return r;
141
142 r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
143 if (r != 0)
144 return r;
145
146 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
147 if (r != 0)
148 return r;
149
150 r = CMP(a->priority, b->priority);
151 if (r != 0)
152 return r;
153
154 r = CMP(a->tos, b->tos);
155 if (r != 0)
156 return r;
157
158 r = CMP(a->protocol, b->protocol);
159 if (r != 0)
160 return r;
161
162 r = CMP(a->scope, b->scope);
163 if (r != 0)
164 return r;
165
166 r = CMP(a->type, b->type);
167 if (r != 0)
168 return r;
169
170 r = CMP(a->flags & ~RTNH_COMPARE_MASK, b->flags & ~RTNH_COMPARE_MASK);
171 if (r != 0)
172 return r;
173
174 r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
175 if (r != 0)
176 return r;
177
178 r = route_nexthops_compare_func(a, b);
179 if (r != 0)
180 return r;
181
182 return route_metric_compare_func(&a->metric, &b->metric);
183
184 case AF_INET6:
185 r = CMP(a->table, b->table);
186 if (r != 0)
187 return r;
188
189 r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
190 if (r != 0)
191 return r;
192
193 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
194 if (r != 0)
195 return r;
196
197 r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
198 if (r != 0)
199 return r;
200
201 r = CMP(a->src_prefixlen, b->src_prefixlen);
202 if (r != 0)
203 return r;
204
205 r = CMP(a->priority, b->priority);
206 if (r != 0)
207 return r;
208
209 return route_nexthops_compare_func(a, b);
210
211 default:
212 /* treat any other address family as AF_UNSPEC */
213 return 0;
214 }
215 }
216
217 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
218 route_hash_ops,
219 Route,
220 route_hash_func,
221 route_compare_func,
222 route_detach);
223
224 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
225 route_hash_ops_unref,
226 Route,
227 route_hash_func,
228 route_compare_func,
229 route_unref);
230
231 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
232 route_section_hash_ops,
233 ConfigSection,
234 config_section_hash_func,
235 config_section_compare_func,
236 Route,
237 route_detach);
238
239 int route_new(Route **ret) {
240 _cleanup_(route_unrefp) Route *route = NULL;
241
242 route = new(Route, 1);
243 if (!route)
244 return -ENOMEM;
245
246 *route = (Route) {
247 .n_ref = 1,
248 .family = AF_UNSPEC,
249 .scope = RT_SCOPE_UNIVERSE,
250 .protocol = RTPROT_UNSPEC,
251 .type = RTN_UNICAST,
252 .table = RT_TABLE_MAIN,
253 .lifetime_usec = USEC_INFINITY,
254 .gateway_onlink = -1,
255 };
256
257 *ret = TAKE_PTR(route);
258
259 return 0;
260 }
261
262 int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
263 _cleanup_(config_section_freep) ConfigSection *n = NULL;
264 _cleanup_(route_unrefp) Route *route = NULL;
265 int r;
266
267 assert(network);
268 assert(ret);
269 assert(filename);
270 assert(section_line > 0);
271
272 r = config_section_new(filename, section_line, &n);
273 if (r < 0)
274 return r;
275
276 route = hashmap_get(network->routes_by_section, n);
277 if (route) {
278 *ret = TAKE_PTR(route);
279 return 0;
280 }
281
282 if (hashmap_size(network->routes_by_section) >= routes_max())
283 return -E2BIG;
284
285 r = route_new(&route);
286 if (r < 0)
287 return r;
288
289 route->protocol = RTPROT_STATIC;
290 route->network = network;
291 route->section = TAKE_PTR(n);
292 route->source = NETWORK_CONFIG_SOURCE_STATIC;
293
294 r = hashmap_ensure_put(&network->routes_by_section, &route_section_hash_ops, route->section, route);
295 if (r < 0)
296 return r;
297
298 *ret = TAKE_PTR(route);
299 return 0;
300 }
301
302 static int route_attach(Manager *manager, Route *route) {
303 int r;
304
305 assert(manager);
306 assert(route);
307 assert(!route->network);
308 assert(!route->wireguard);
309
310 r = set_ensure_put(&manager->routes, &route_hash_ops, route);
311 if (r < 0)
312 return r;
313 if (r == 0)
314 return -EEXIST;
315
316 route->manager = manager;
317 return 0;
318 }
319
320 int route_get(Manager *manager, const Route *route, Route **ret) {
321 Route *existing;
322
323 assert(manager);
324 assert(route);
325
326 existing = set_get(manager->routes, route);
327 if (!existing)
328 return -ENOENT;
329
330 if (ret)
331 *ret = existing;
332
333 return 0;
334 }
335
336 static int route_get_link(Manager *manager, const Route *route, Link **ret) {
337 int r;
338
339 assert(manager);
340 assert(route);
341
342 if (route->nexthop_id != 0) {
343 NextHop *nh;
344
345 r = nexthop_get_by_id(manager, route->nexthop_id, &nh);
346 if (r < 0)
347 return r;
348
349 return link_get_by_index(manager, nh->ifindex, ret);
350 }
351
352 return route_nexthop_get_link(manager, &route->nexthop, ret);
353 }
354
355 int route_get_request(Manager *manager, const Route *route, Request **ret) {
356 Request *req;
357
358 assert(manager);
359 assert(route);
360
361 req = ordered_set_get(manager->request_queue,
362 &(const Request) {
363 .type = REQUEST_TYPE_ROUTE,
364 .userdata = (void*) route,
365 .hash_func = (hash_func_t) route_hash_func,
366 .compare_func = (compare_func_t) route_compare_func,
367 });
368 if (!req)
369 return -ENOENT;
370
371 if (ret)
372 *ret = req;
373 return 0;
374 }
375
376 int route_dup(const Route *src, const RouteNextHop *nh, Route **ret) {
377 _cleanup_(route_unrefp) Route *dest = NULL;
378 int r;
379
380 assert(src);
381 assert(ret);
382
383 dest = newdup(Route, src, 1);
384 if (!dest)
385 return -ENOMEM;
386
387 /* Unset number of reference and all pointers */
388 dest->n_ref = 1;
389 dest->manager = NULL;
390 dest->network = NULL;
391 dest->wireguard = NULL;
392 dest->section = NULL;
393 dest->nexthop = ROUTE_NEXTHOP_NULL;
394 dest->nexthops = NULL;
395 dest->metric = ROUTE_METRIC_NULL;
396 dest->expire = NULL;
397
398 r = route_nexthops_copy(src, nh, dest);
399 if (r < 0)
400 return r;
401
402 r = route_metric_copy(&src->metric, &dest->metric);
403 if (r < 0)
404 return r;
405
406 *ret = TAKE_PTR(dest);
407 return 0;
408 }
409
410 static void log_route_debug(const Route *route, const char *str, Manager *manager) {
411 _cleanup_free_ char *state = NULL, *nexthop = NULL, *prefsrc = NULL,
412 *table = NULL, *scope = NULL, *proto = NULL, *flags = NULL;
413 const char *dst, *src;
414 Link *link = NULL;
415
416 assert(route);
417 assert(str);
418 assert(manager);
419
420 if (!DEBUG_LOGGING)
421 return;
422
423 (void) route_get_link(manager, route, &link);
424
425 (void) network_config_state_to_string_alloc(route->state, &state);
426
427 dst = in_addr_is_set(route->family, &route->dst) || route->dst_prefixlen > 0 ?
428 IN_ADDR_PREFIX_TO_STRING(route->family, &route->dst, route->dst_prefixlen) : NULL;
429 src = in_addr_is_set(route->family, &route->src) || route->src_prefixlen > 0 ?
430 IN_ADDR_PREFIX_TO_STRING(route->family, &route->src, route->src_prefixlen) : NULL;
431
432 (void) route_nexthops_to_string(route, &nexthop);
433
434 if (in_addr_is_set(route->family, &route->prefsrc))
435 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
436 (void) route_scope_to_string_alloc(route->scope, &scope);
437 (void) manager_get_route_table_to_string(manager, route->table, /* append_num = */ true, &table);
438 (void) route_protocol_full_to_string_alloc(route->protocol, &proto);
439 (void) route_flags_to_string_alloc(route->flags, &flags);
440
441 log_link_debug(link,
442 "%s %s route (%s): dst: %s, src: %s, %s, prefsrc: %s, "
443 "table: %s, priority: %"PRIu32", "
444 "proto: %s, scope: %s, type: %s, flags: %s",
445 str, strna(network_config_source_to_string(route->source)), strna(state),
446 strna(dst), strna(src), strna(nexthop), strna(prefsrc),
447 strna(table), route->priority,
448 strna(proto), strna(scope), strna(route_type_to_string(route->type)), strna(flags));
449 }
450
451 static int route_set_netlink_message(const Route *route, sd_netlink_message *m) {
452 int r;
453
454 assert(route);
455 assert(m);
456
457 /* rtmsg header (and relevant attributes) */
458 if (route->dst_prefixlen > 0) {
459 r = netlink_message_append_in_addr_union(m, RTA_DST, route->family, &route->dst);
460 if (r < 0)
461 return r;
462
463 r = sd_rtnl_message_route_set_dst_prefixlen(m, route->dst_prefixlen);
464 if (r < 0)
465 return r;
466 }
467
468 if (route->src_prefixlen > 0) {
469 r = netlink_message_append_in_addr_union(m, RTA_SRC, route->family, &route->src);
470 if (r < 0)
471 return r;
472
473 r = sd_rtnl_message_route_set_src_prefixlen(m, route->src_prefixlen);
474 if (r < 0)
475 return r;
476 }
477
478 r = sd_rtnl_message_route_set_tos(m, route->tos);
479 if (r < 0)
480 return r;
481
482 r = sd_rtnl_message_route_set_scope(m, route->scope);
483 if (r < 0)
484 return r;
485
486 r = sd_rtnl_message_route_set_type(m, route->type);
487 if (r < 0)
488 return r;
489
490 r = sd_rtnl_message_route_set_flags(m, route->flags & ~RTNH_COMPARE_MASK);
491 if (r < 0)
492 return r;
493
494 /* attributes */
495 r = sd_netlink_message_append_u32(m, RTA_PRIORITY, route->priority);
496 if (r < 0)
497 return r;
498
499 if (in_addr_is_set(route->family, &route->prefsrc)) {
500 r = netlink_message_append_in_addr_union(m, RTA_PREFSRC, route->family, &route->prefsrc);
501 if (r < 0)
502 return r;
503 }
504
505 if (route->table < 256) {
506 r = sd_rtnl_message_route_set_table(m, route->table);
507 if (r < 0)
508 return r;
509 } else {
510 r = sd_rtnl_message_route_set_table(m, RT_TABLE_UNSPEC);
511 if (r < 0)
512 return r;
513
514 /* Table attribute to allow more than 256. */
515 r = sd_netlink_message_append_u32(m, RTA_TABLE, route->table);
516 if (r < 0)
517 return r;
518 }
519
520 r = sd_netlink_message_append_u8(m, RTA_PREF, route->pref);
521 if (r < 0)
522 return r;
523
524 /* nexthops */
525 r = route_nexthops_set_netlink_message(route, m);
526 if (r < 0)
527 return r;
528
529 /* metrics */
530 r = route_metric_set_netlink_message(&route->metric, m);
531 if (r < 0)
532 return r;
533
534 return 0;
535 }
536
537 static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, RemoveRequest *rreq) {
538 int r;
539
540 assert(m);
541 assert(rreq);
542
543 Manager *manager = ASSERT_PTR(rreq->manager);
544 Route *route = ASSERT_PTR(rreq->userdata);
545
546 r = sd_netlink_message_get_errno(m);
547 if (r < 0) {
548 log_message_full_errno(m,
549 (r == -ESRCH || /* the route is already removed? */
550 (r == -EINVAL && route->nexthop_id != 0) || /* The nexthop is already removed? */
551 !route->manager) ? /* already detached? */
552 LOG_DEBUG : LOG_WARNING,
553 r, "Could not drop route, ignoring");
554
555 if (route->manager) {
556 /* If the route cannot be removed, then assume the route is already removed. */
557 log_route_debug(route, "Forgetting", manager);
558
559 Request *req;
560 if (route_get_request(manager, route, &req) >= 0)
561 route_enter_removed(req->userdata);
562
563 route_detach(route);
564 }
565 }
566
567 return 1;
568 }
569
570 int route_remove(Route *route, Manager *manager) {
571 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
572 Link *link = NULL;
573 int r;
574
575 assert(route);
576 assert(manager);
577
578 /* If the route is remembered, then use the remembered object. */
579 (void) route_get(manager, route, &route);
580
581 log_route_debug(route, "Removing", manager);
582
583 /* For logging. */
584 (void) route_get_link(manager, route, &link);
585
586 r = sd_rtnl_message_new_route(manager->rtnl, &m, RTM_DELROUTE, route->family, route->protocol);
587 if (r < 0)
588 return log_link_warning_errno(link, r, "Could not create netlink message: %m");
589
590 r = route_set_netlink_message(route, m);
591 if (r < 0)
592 return log_link_warning_errno(link, r, "Could not fill netlink message: %m");
593
594 r = manager_remove_request_add(manager, route, route, manager->rtnl, m, route_remove_handler);
595 if (r < 0)
596 return log_link_warning_errno(link, r, "Could not queue rtnetlink message: %m");
597
598 route_enter_removing(route);
599 return 0;
600 }
601
602 int route_remove_and_cancel(Route *route, Manager *manager) {
603 _cleanup_(request_unrefp) Request *req = NULL;
604 bool waiting = false;
605
606 assert(route);
607 assert(manager);
608
609 /* If the route is remembered by the manager, then use the remembered object. */
610 (void) route_get(manager, route, &route);
611
612 /* Cancel the request for the route. If the request is already called but we have not received the
613 * notification about the request, then explicitly remove the route. */
614 if (route_get_request(manager, route, &req) >= 0) {
615 request_ref(req); /* avoid the request freed by request_detach() */
616 waiting = req->waiting_reply;
617 request_detach(req);
618 route_cancel_requesting(route);
619 }
620
621 /* If we know that the route will come or already exists, remove it. */
622 if (waiting || (route->manager && route_exists(route)))
623 return route_remove(route, manager);
624
625 return 0;
626 }
627
628 static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
629 Route *route = ASSERT_PTR(userdata);
630 int r;
631
632 if (!route->manager)
633 return 0; /* already detached. */
634
635 r = route_remove(route, route->manager);
636 if (r < 0) {
637 Link *link = NULL;
638 (void) route_get_link(route->manager, route, &link);
639 log_link_warning_errno(link, r, "Could not remove route: %m");
640 if (link)
641 link_enter_failed(link);
642 }
643
644 return 1;
645 }
646
647 static int route_setup_timer(Route *route, const struct rta_cacheinfo *cacheinfo) {
648 int r;
649
650 assert(route);
651
652 if (cacheinfo && cacheinfo->rta_expires != 0)
653 route->expiration_managed_by_kernel = true;
654
655 if (route->lifetime_usec == USEC_INFINITY || /* We do not request expiration for the route. */
656 route->expiration_managed_by_kernel) { /* We have received nonzero expiration previously. The expiration is managed by the kernel. */
657 route->expire = sd_event_source_disable_unref(route->expire);
658 return 0;
659 }
660
661 Manager *manager = ASSERT_PTR(route->manager);
662 r = event_reset_time(manager->event, &route->expire, CLOCK_BOOTTIME,
663 route->lifetime_usec, 0, route_expire_handler, route, 0, "route-expiration", true);
664 if (r < 0) {
665 Link *link = NULL;
666 (void) route_get_link(manager, route, &link);
667 return log_link_warning_errno(link, r, "Failed to configure expiration timer for route, ignoring: %m");
668 }
669
670 log_route_debug(route, "Configured expiration timer for", manager);
671 return 1;
672 }
673
674 int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, Route *route, const char *error_msg) {
675 int r;
676
677 assert(m);
678 assert(link);
679 assert(link->manager);
680 assert(route);
681 assert(error_msg);
682
683 r = sd_netlink_message_get_errno(m);
684 if (r == -EEXIST) {
685 Route *existing;
686
687 if (route_get(link->manager, route, &existing) >= 0) {
688 /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE
689 * notification, so we need to update the timer here. */
690 existing->lifetime_usec = route->lifetime_usec;
691 (void) route_setup_timer(existing, NULL);
692
693 /* This may be a bug in the kernel, but the MTU of an IPv6 route can be updated only
694 * when the route has an expiration timer managed by the kernel (not by us).
695 * See fib6_add_rt2node() in net/ipv6/ip6_fib.c of the kernel. */
696 if (existing->family == AF_INET6 &&
697 existing->expiration_managed_by_kernel) {
698 r = route_metric_set(&existing->metric, RTAX_MTU, route_metric_get(&route->metric, RTAX_MTU));
699 if (r < 0) {
700 log_oom();
701 link_enter_failed(link);
702 return 0;
703 }
704 }
705 }
706
707 } else if (r < 0) {
708 log_link_message_warning_errno(link, m, r, error_msg);
709 link_enter_failed(link);
710 return 0;
711 }
712
713 return 1;
714 }
715
716 static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link, Request *req) {
717 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
718 int r;
719
720 assert(route);
721 assert(link);
722 assert(link->manager);
723 assert(req);
724
725 log_route_debug(route, "Configuring", link->manager);
726
727 r = sd_rtnl_message_new_route(link->manager->rtnl, &m, RTM_NEWROUTE, route->family, route->protocol);
728 if (r < 0)
729 return r;
730
731 r = route_set_netlink_message(route, m);
732 if (r < 0)
733 return r;
734
735 if (lifetime_sec != UINT32_MAX) {
736 r = sd_netlink_message_append_u32(m, RTA_EXPIRES, lifetime_sec);
737 if (r < 0)
738 return r;
739 }
740
741 return request_call_netlink_async(link->manager->rtnl, m, req);
742 }
743
744 static int route_requeue_request(Request *req, Link *link, const Route *route) {
745 _unused_ _cleanup_(request_unrefp) Request *req_unref = NULL;
746 _cleanup_(route_unrefp) Route *tmp = NULL;
747 int r;
748
749 assert(req);
750 assert(link);
751 assert(link->manager);
752 assert(route);
753
754 /* It is not possible to adjust the Route object owned by Request, as it is used as a key to manage
755 * Request objects in the queue. Hence, we need to re-request with the updated Route object. */
756
757 if (!route_nexthops_needs_adjust(route))
758 return 0; /* The Route object does not need the adjustment. Continue with it. */
759
760 r = route_dup(route, NULL, &tmp);
761 if (r < 0)
762 return r;
763
764 r = route_adjust_nexthops(tmp, link);
765 if (r <= 0)
766 return r;
767
768 if (route_compare_func(route, tmp) == 0 && route->type == tmp->type)
769 return 0; /* No effective change?? That's OK. */
770
771 /* Avoid the request to be freed by request_detach(). */
772 req_unref = request_ref(req);
773
774 /* Detach the request from the queue, to make not the new request is deduped.
775 * Why this is necessary? IPv6 routes with different type may be handled as the same,
776 * As commented in route_adjust_nexthops(), we need to configure the adjusted type,
777 * otherwise we cannot remove the route on reconfigure or so. If we request the new Route object
778 * without detaching the current request, the new request is deduped, and the route is configured
779 * with unmodified type. */
780 request_detach(req);
781
782 /* Request the route with the adjusted Route object combined with the same other parameters. */
783 r = link_requeue_request(link, req, tmp, NULL);
784 if (r < 0)
785 return r;
786 if (r == 0)
787 return 1; /* Already queued?? That's OK. Maybe, [Route] section is effectively duplicated. */
788
789 TAKE_PTR(tmp);
790 return 1; /* New request is queued. Finish to process this request. */
791 }
792
793 static int route_is_ready_to_configure(const Route *route, Link *link) {
794 int r;
795
796 assert(route);
797 assert(link);
798
799 if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
800 return false;
801
802 if (in_addr_is_set(route->family, &route->prefsrc) > 0) {
803 r = manager_has_address(link->manager, route->family, &route->prefsrc);
804 if (r <= 0)
805 return r;
806 }
807
808 return route_nexthops_is_ready_to_configure(route, link->manager);
809 }
810
811 static int route_process_request(Request *req, Link *link, Route *route) {
812 Route *existing;
813 int r;
814
815 assert(req);
816 assert(link);
817 assert(link->manager);
818 assert(route);
819
820 r = route_is_ready_to_configure(route, link);
821 if (r < 0)
822 return log_link_warning_errno(link, r, "Failed to check if route is ready to configure: %m");
823 if (r == 0)
824 return 0;
825
826 usec_t now_usec;
827 assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
828 uint32_t sec = usec_to_sec(route->lifetime_usec, now_usec);
829 if (sec == 0) {
830 log_link_debug(link, "Refuse to configure %s route with zero lifetime.",
831 network_config_source_to_string(route->source));
832
833 route_cancel_requesting(route);
834 if (route_get(link->manager, route, &existing) >= 0)
835 route_cancel_requesting(existing);
836 return 1;
837 }
838
839 r = route_requeue_request(req, link, route);
840 if (r != 0)
841 return r;
842
843 r = route_configure(route, sec, link, req);
844 if (r < 0)
845 return log_link_warning_errno(link, r, "Failed to configure route: %m");
846
847 route_enter_configuring(route);
848 if (route_get(link->manager, route, &existing) >= 0)
849 route_enter_configuring(existing);
850 return 1;
851 }
852
853 static int link_request_route_one(
854 Link *link,
855 const Route *route,
856 const RouteNextHop *nh,
857 unsigned *message_counter,
858 route_netlink_handler_t netlink_handler) {
859
860 _cleanup_(route_unrefp) Route *tmp = NULL;
861 Route *existing = NULL;
862 int r;
863
864 assert(link);
865 assert(link->manager);
866 assert(route);
867
868 r = route_dup(route, nh, &tmp);
869 if (r < 0)
870 return r;
871
872 r = route_adjust_nexthops(tmp, link);
873 if (r < 0)
874 return r;
875
876 if (route_get(link->manager, tmp, &existing) >= 0)
877 /* Copy state for logging below. */
878 tmp->state = existing->state;
879
880 log_route_debug(tmp, "Requesting", link->manager);
881 r = link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
882 tmp,
883 route_unref,
884 route_hash_func,
885 route_compare_func,
886 route_process_request,
887 message_counter,
888 netlink_handler,
889 NULL);
890 if (r <= 0)
891 return r;
892
893 route_enter_requesting(tmp);
894 if (existing)
895 route_enter_requesting(existing);
896
897 TAKE_PTR(tmp);
898 return 1;
899 }
900
901 int link_request_route(
902 Link *link,
903 const Route *route,
904 unsigned *message_counter,
905 route_netlink_handler_t netlink_handler) {
906
907 int r;
908
909 assert(link);
910 assert(link->manager);
911 assert(route);
912 assert(route->source != NETWORK_CONFIG_SOURCE_FOREIGN);
913
914 if (route->family == AF_INET || route_type_is_reject(route) || ordered_set_isempty(route->nexthops))
915 return link_request_route_one(link, route, NULL, message_counter, netlink_handler);
916
917 RouteNextHop *nh;
918 ORDERED_SET_FOREACH(nh, route->nexthops) {
919 r = link_request_route_one(link, route, nh, message_counter, netlink_handler);
920 if (r < 0)
921 return r;
922 }
923
924 return 0;
925 }
926
927 static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
928 int r;
929
930 assert(link);
931
932 r = route_configure_handler_internal(rtnl, m, link, route, "Could not set route");
933 if (r <= 0)
934 return r;
935
936 if (link->static_route_messages == 0) {
937 log_link_debug(link, "Routes set");
938 link->static_routes_configured = true;
939 link_check_ready(link);
940 }
941
942 return 1;
943 }
944
945 static int link_request_wireguard_routes(Link *link, bool only_ipv4) {
946 NetDev *netdev;
947 Route *route;
948 int r;
949
950 assert(link);
951
952 if (!streq_ptr(link->kind, "wireguard"))
953 return 0;
954
955 if (netdev_get(link->manager, link->ifname, &netdev) < 0)
956 return 0;
957
958 Wireguard *w = WIREGUARD(netdev);
959
960 SET_FOREACH(route, w->routes) {
961 if (only_ipv4 && route->family != AF_INET)
962 continue;
963
964 r = link_request_route(link, route, &link->static_route_messages, static_route_handler);
965 if (r < 0)
966 return r;
967 }
968
969 return 0;
970 }
971
972 int link_request_static_routes(Link *link, bool only_ipv4) {
973 Route *route;
974 int r;
975
976 assert(link);
977 assert(link->network);
978
979 link->static_routes_configured = false;
980
981 HASHMAP_FOREACH(route, link->network->routes_by_section) {
982 if (route->gateway_from_dhcp_or_ra)
983 continue;
984
985 if (only_ipv4 && route->family != AF_INET)
986 continue;
987
988 r = link_request_route(link, route, &link->static_route_messages, static_route_handler);
989 if (r < 0)
990 return r;
991 }
992
993 r = link_request_wireguard_routes(link, only_ipv4);
994 if (r < 0)
995 return r;
996
997 if (link->static_route_messages == 0) {
998 link->static_routes_configured = true;
999 link_check_ready(link);
1000 } else {
1001 log_link_debug(link, "Requesting routes");
1002 link_set_state(link, LINK_STATE_CONFIGURING);
1003 }
1004
1005 return 0;
1006 }
1007
1008 static int process_route_one(
1009 Manager *manager,
1010 uint16_t type,
1011 Route *tmp,
1012 const struct rta_cacheinfo *cacheinfo) {
1013
1014 Request *req = NULL;
1015 Route *route = NULL;
1016 Link *link = NULL;
1017 bool is_new = false, update_dhcp4;
1018 int r;
1019
1020 assert(manager);
1021 assert(tmp);
1022 assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE));
1023
1024 (void) route_get(manager, tmp, &route);
1025 (void) route_get_request(manager, tmp, &req);
1026 (void) route_get_link(manager, tmp, &link);
1027
1028 update_dhcp4 = link && tmp->family == AF_INET6 && tmp->dst_prefixlen == 0;
1029
1030 switch (type) {
1031 case RTM_NEWROUTE:
1032 if (!route) {
1033 if (!manager->manage_foreign_routes && !(req && req->waiting_reply)) {
1034 route_enter_configured(tmp);
1035 log_route_debug(tmp, "Ignoring received", manager);
1036 return 0;
1037 }
1038
1039 /* If we do not know the route, then save it. */
1040 r = route_attach(manager, tmp);
1041 if (r < 0) {
1042 log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
1043 return 0;
1044 }
1045
1046 route = route_ref(tmp);
1047 is_new = true;
1048
1049 } else
1050 /* Update remembered route with the received notification. */
1051 route->nexthop.weight = tmp->nexthop.weight;
1052
1053 /* Also update information that cannot be obtained through netlink notification. */
1054 if (req && req->waiting_reply) {
1055 Route *rt = ASSERT_PTR(req->userdata);
1056
1057 route->source = rt->source;
1058 route->provider = rt->provider;
1059 route->lifetime_usec = rt->lifetime_usec;
1060 }
1061
1062 route_enter_configured(route);
1063 log_route_debug(route, is_new ? "Received new" : "Received remembered", manager);
1064
1065 (void) route_setup_timer(route, cacheinfo);
1066
1067 break;
1068
1069 case RTM_DELROUTE:
1070 if (route) {
1071 route_enter_removed(route);
1072 log_route_debug(route, "Forgetting removed", manager);
1073 route_detach(route);
1074 } else
1075 log_route_debug(tmp,
1076 manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received",
1077 manager);
1078
1079 if (req)
1080 route_enter_removed(req->userdata);
1081
1082 break;
1083
1084 default:
1085 assert_not_reached();
1086 }
1087
1088 if (update_dhcp4) {
1089 r = dhcp4_update_ipv6_connectivity(link);
1090 if (r < 0) {
1091 log_link_warning_errno(link, r, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");
1092 link_enter_failed(link);
1093 }
1094 }
1095
1096 return 1;
1097 }
1098
1099 int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
1100 _cleanup_(route_unrefp) Route *tmp = NULL;
1101 int r;
1102
1103 assert(rtnl);
1104 assert(message);
1105 assert(m);
1106
1107 if (sd_netlink_message_is_error(message)) {
1108 r = sd_netlink_message_get_errno(message);
1109 if (r < 0)
1110 log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
1111
1112 return 0;
1113 }
1114
1115 uint16_t type;
1116 r = sd_netlink_message_get_type(message, &type);
1117 if (r < 0) {
1118 log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
1119 return 0;
1120 } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
1121 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
1122 return 0;
1123 }
1124
1125 r = route_new(&tmp);
1126 if (r < 0)
1127 return log_oom();
1128
1129 /* rtmsg header */
1130 r = sd_rtnl_message_route_get_family(message, &tmp->family);
1131 if (r < 0) {
1132 log_warning_errno(r, "rtnl: received route message without family, ignoring: %m");
1133 return 0;
1134 } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
1135 log_debug("rtnl: received route message with invalid family '%i', ignoring.", tmp->family);
1136 return 0;
1137 }
1138
1139 r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
1140 if (r < 0) {
1141 log_warning_errno(r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1142 return 0;
1143 }
1144
1145 r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
1146 if (r < 0) {
1147 log_warning_errno(r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1148 return 0;
1149 }
1150
1151 r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
1152 if (r < 0) {
1153 log_warning_errno(r, "rtnl: received route message with invalid tos, ignoring: %m");
1154 return 0;
1155 }
1156
1157 r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
1158 if (r < 0) {
1159 log_warning_errno(r, "rtnl: received route message without route protocol, ignoring: %m");
1160 return 0;
1161 }
1162
1163 r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
1164 if (r < 0) {
1165 log_warning_errno(r, "rtnl: received route message with invalid scope, ignoring: %m");
1166 return 0;
1167 }
1168
1169 r = sd_rtnl_message_route_get_type(message, &tmp->type);
1170 if (r < 0) {
1171 log_warning_errno(r, "rtnl: received route message with invalid type, ignoring: %m");
1172 return 0;
1173 }
1174
1175 r = sd_rtnl_message_route_get_flags(message, &tmp->flags);
1176 if (r < 0) {
1177 log_warning_errno(r, "rtnl: received route message without route flags, ignoring: %m");
1178 return 0;
1179 }
1180
1181 /* attributes */
1182 r = netlink_message_read_in_addr_union(message, RTA_DST, tmp->family, &tmp->dst);
1183 if (r < 0 && r != -ENODATA) {
1184 log_warning_errno(r, "rtnl: received route message without valid destination, ignoring: %m");
1185 return 0;
1186 }
1187
1188 r = netlink_message_read_in_addr_union(message, RTA_SRC, tmp->family, &tmp->src);
1189 if (r < 0 && r != -ENODATA) {
1190 log_warning_errno(r, "rtnl: received route message without valid source, ignoring: %m");
1191 return 0;
1192 }
1193
1194 r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
1195 if (r < 0 && r != -ENODATA) {
1196 log_warning_errno(r, "rtnl: received route message with invalid priority, ignoring: %m");
1197 return 0;
1198 }
1199
1200 r = netlink_message_read_in_addr_union(message, RTA_PREFSRC, tmp->family, &tmp->prefsrc);
1201 if (r < 0 && r != -ENODATA) {
1202 log_warning_errno(r, "rtnl: received route message without valid preferred source, ignoring: %m");
1203 return 0;
1204 }
1205
1206 r = sd_netlink_message_read_u32(message, RTA_TABLE, &tmp->table);
1207 if (r == -ENODATA) {
1208 unsigned char table;
1209
1210 r = sd_rtnl_message_route_get_table(message, &table);
1211 if (r >= 0)
1212 tmp->table = table;
1213 }
1214 if (r < 0) {
1215 log_warning_errno(r, "rtnl: received route message with invalid table, ignoring: %m");
1216 return 0;
1217 }
1218
1219 r = sd_netlink_message_read_u8(message, RTA_PREF, &tmp->pref);
1220 if (r < 0 && r != -ENODATA) {
1221 log_warning_errno(r, "rtnl: received route message with invalid preference, ignoring: %m");
1222 return 0;
1223 }
1224
1225 /* nexthops */
1226 if (route_nexthops_read_netlink_message(tmp, message) < 0)
1227 return 0;
1228
1229 /* metrics */
1230 if (route_metric_read_netlink_message(&tmp->metric, message) < 0)
1231 return 0;
1232
1233 bool has_cacheinfo;
1234 struct rta_cacheinfo cacheinfo;
1235 r = sd_netlink_message_read(message, RTA_CACHEINFO, sizeof(cacheinfo), &cacheinfo);
1236 if (r < 0 && r != -ENODATA) {
1237 log_warning_errno(r, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1238 return 0;
1239 }
1240 has_cacheinfo = r >= 0;
1241
1242 if (tmp->family == AF_INET || ordered_set_isempty(tmp->nexthops))
1243 return process_route_one(m, type, tmp, has_cacheinfo ? &cacheinfo : NULL);
1244
1245 RouteNextHop *nh;
1246 ORDERED_SET_FOREACH(nh, tmp->nexthops) {
1247 _cleanup_(route_unrefp) Route *dup = NULL;
1248
1249 r = route_dup(tmp, nh, &dup);
1250 if (r < 0)
1251 return log_oom();
1252
1253 r = process_route_one(m, type, dup, has_cacheinfo ? &cacheinfo : NULL);
1254 if (r < 0)
1255 return r;
1256 }
1257
1258 return 1;
1259 }
1260
1261 void manager_mark_routes(Manager *manager, Link *link, NetworkConfigSource source) {
1262 Route *route;
1263
1264 assert(manager);
1265
1266 SET_FOREACH(route, manager->routes) {
1267 if (route->source != source)
1268 continue;
1269
1270 if (link) {
1271 Link *route_link;
1272
1273 if (route_get_link(manager, route, &route_link) < 0)
1274 continue;
1275 if (route_link != link)
1276 continue;
1277 }
1278
1279 route_mark(route);
1280 }
1281 }
1282
1283 static bool route_by_kernel(const Route *route) {
1284 assert(route);
1285
1286 if (route->protocol == RTPROT_KERNEL)
1287 return true;
1288
1289 /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
1290 * multicast with RTPROT_BOOT. Do not touch it. */
1291 if (route->protocol == RTPROT_BOOT &&
1292 route->family == AF_INET6 &&
1293 route->dst_prefixlen == 8 &&
1294 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 }}}))
1295 return true;
1296
1297 return false;
1298 }
1299
1300 bool route_can_update(const Route *existing, const Route *requesting) {
1301 assert(existing);
1302 assert(requesting);
1303
1304 if (route_compare_func(existing, requesting) != 0)
1305 return false;
1306
1307 switch (existing->family) {
1308 case AF_INET:
1309 if (existing->nexthop.weight != requesting->nexthop.weight)
1310 return false;
1311 return true;
1312
1313 case AF_INET6:
1314 if (existing->protocol != requesting->protocol)
1315 return false;
1316 if (existing->type != requesting->type)
1317 return false;
1318 if (existing->flags != requesting->flags)
1319 return false;
1320 if (!in6_addr_equal(&existing->prefsrc.in6, &requesting->prefsrc.in6))
1321 return false;
1322 if (existing->pref != requesting->pref)
1323 return false;
1324 if (existing->expiration_managed_by_kernel && requesting->lifetime_usec != USEC_INFINITY)
1325 return false; /* We cannot disable expiration timer in the kernel. */
1326 if (!route_metric_can_update(&existing->metric, &requesting->metric, existing->expiration_managed_by_kernel))
1327 return false;
1328 if (existing->nexthop.weight != requesting->nexthop.weight)
1329 return false;
1330 return true;
1331
1332 default:
1333 assert_not_reached();
1334 }
1335 }
1336
1337 static int link_unmark_route(Link *link, const Route *route, const RouteNextHop *nh) {
1338 _cleanup_(route_unrefp) Route *tmp = NULL;
1339 Route *existing;
1340 int r;
1341
1342 assert(link);
1343 assert(route);
1344
1345 r = route_dup(route, nh, &tmp);
1346 if (r < 0)
1347 return r;
1348
1349 r = route_adjust_nexthops(tmp, link);
1350 if (r < 0)
1351 return r;
1352
1353 if (route_get(link->manager, tmp, &existing) < 0)
1354 return 0;
1355
1356 if (!route_can_update(existing, tmp))
1357 return 0;
1358
1359 route_unmark(existing);
1360 return 1;
1361 }
1362
1363 static int link_mark_routes(Link *link, bool foreign) {
1364 Route *route;
1365 Link *other;
1366 int r;
1367
1368 assert(link);
1369 assert(link->manager);
1370
1371 /* First, mark all routes. */
1372 SET_FOREACH(route, link->manager->routes) {
1373 /* Do not touch routes managed by the kernel. */
1374 if (route_by_kernel(route))
1375 continue;
1376
1377 /* When 'foreign' is true, mark only foreign routes, and vice versa.
1378 * Note, do not touch dynamic routes. They will removed by when e.g. lease is lost. */
1379 if (route->source != (foreign ? NETWORK_CONFIG_SOURCE_FOREIGN : NETWORK_CONFIG_SOURCE_STATIC))
1380 continue;
1381
1382 /* Ignore routes not assigned yet or already removed. */
1383 if (!route_exists(route))
1384 continue;
1385
1386 if (link->network) {
1387 if (route->protocol == RTPROT_STATIC &&
1388 FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
1389 continue;
1390
1391 if (route->protocol == RTPROT_DHCP &&
1392 FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
1393 continue;
1394 }
1395
1396 /* When we mark foreign routes, do not mark routes assigned to other interfaces.
1397 * Otherwise, routes assigned to unmanaged interfaces will be dropped.
1398 * Note, route_get_link() does not provide assigned link for routes with an unreachable type
1399 * or IPv4 multipath routes. So, the current implementation does not support managing such
1400 * routes by other daemon or so, unless ManageForeignRoutes=no. */
1401 if (foreign) {
1402 Link *route_link;
1403
1404 if (route_get_link(link->manager, route, &route_link) >= 0 && route_link != link)
1405 continue;
1406 }
1407
1408 route_mark(route);
1409 }
1410
1411 /* Then, unmark all routes requested by active links. */
1412 HASHMAP_FOREACH(other, link->manager->links_by_index) {
1413 if (!foreign && other == link)
1414 continue;
1415
1416 if (!IN_SET(other->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1417 continue;
1418
1419 HASHMAP_FOREACH(route, other->network->routes_by_section) {
1420 if (route->family == AF_INET || ordered_set_isempty(route->nexthops)) {
1421 r = link_unmark_route(other, route, NULL);
1422 if (r < 0)
1423 return r;
1424
1425 } else {
1426 RouteNextHop *nh;
1427 ORDERED_SET_FOREACH(nh, route->nexthops) {
1428 r = link_unmark_route(other, route, nh);
1429 if (r < 0)
1430 return r;
1431 }
1432 }
1433 }
1434 }
1435
1436 /* Also unmark routes requested in .netdev file. */
1437 if (foreign && link->netdev && link->netdev->kind == NETDEV_KIND_WIREGUARD) {
1438 Wireguard *w = WIREGUARD(link->netdev);
1439
1440 SET_FOREACH(route, w->routes) {
1441 r = link_unmark_route(link, route, NULL);
1442 if (r < 0)
1443 return r;
1444 }
1445 }
1446
1447 return 0;
1448 }
1449
1450 int link_drop_routes(Link *link, bool foreign) {
1451 Route *route;
1452 int r;
1453
1454 assert(link);
1455 assert(link->manager);
1456
1457 r = link_mark_routes(link, foreign);
1458 if (r < 0)
1459 return r;
1460
1461 SET_FOREACH(route, link->manager->routes) {
1462 if (!route_is_marked(route))
1463 continue;
1464
1465 RET_GATHER(r, route_remove(route, link->manager));
1466 }
1467
1468 return r;
1469 }
1470
1471 int link_foreignize_routes(Link *link) {
1472 Route *route;
1473 int r;
1474
1475 assert(link);
1476 assert(link->manager);
1477
1478 r = link_mark_routes(link, /* foreign = */ false);
1479 if (r < 0)
1480 return r;
1481
1482 SET_FOREACH(route, link->manager->routes) {
1483 if (!route_is_marked(route))
1484 continue;
1485
1486 route->source = NETWORK_CONFIG_SOURCE_FOREIGN;
1487 }
1488
1489 return 0;
1490 }
1491
1492 int network_add_ipv4ll_route(Network *network) {
1493 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1494 unsigned section_line;
1495 int r;
1496
1497 assert(network);
1498
1499 if (!network->ipv4ll_route)
1500 return 0;
1501
1502 r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
1503 if (r < 0)
1504 return r;
1505
1506 /* IPv4LLRoute= is in [Network] section. */
1507 r = route_new_static(network, network->filename, section_line, &route);
1508 if (r < 0)
1509 return r;
1510
1511 r = in_addr_from_string(AF_INET, "169.254.0.0", &route->dst);
1512 if (r < 0)
1513 return r;
1514
1515 route->family = AF_INET;
1516 route->dst_prefixlen = 16;
1517 route->scope = RT_SCOPE_LINK;
1518 route->scope_set = true;
1519 route->table_set = true;
1520 route->priority = IPV4LL_ROUTE_METRIC;
1521 route->protocol = RTPROT_STATIC;
1522
1523 TAKE_PTR(route);
1524 return 0;
1525 }
1526
1527 int network_add_default_route_on_device(Network *network) {
1528 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1529 unsigned section_line;
1530 int r;
1531
1532 assert(network);
1533
1534 if (!network->default_route_on_device)
1535 return 0;
1536
1537 r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
1538 if (r < 0)
1539 return r;
1540
1541 /* DefaultRouteOnDevice= is in [Network] section. */
1542 r = route_new_static(network, network->filename, section_line, &route);
1543 if (r < 0)
1544 return r;
1545
1546 route->family = AF_INET;
1547 route->scope = RT_SCOPE_LINK;
1548 route->scope_set = true;
1549 route->protocol = RTPROT_STATIC;
1550
1551 TAKE_PTR(route);
1552 return 0;
1553 }
1554
1555 int config_parse_preferred_src(
1556 const char *unit,
1557 const char *filename,
1558 unsigned line,
1559 const char *section,
1560 unsigned section_line,
1561 const char *lvalue,
1562 int ltype,
1563 const char *rvalue,
1564 void *data,
1565 void *userdata) {
1566
1567 Network *network = userdata;
1568 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1569 int r;
1570
1571 assert(filename);
1572 assert(section);
1573 assert(lvalue);
1574 assert(rvalue);
1575 assert(data);
1576
1577 r = route_new_static(network, filename, section_line, &route);
1578 if (r == -ENOMEM)
1579 return log_oom();
1580 if (r < 0) {
1581 log_syntax(unit, LOG_WARNING, filename, line, r,
1582 "Failed to allocate route, ignoring assignment: %m");
1583 return 0;
1584 }
1585
1586 if (route->family == AF_UNSPEC)
1587 r = in_addr_from_string_auto(rvalue, &route->family, &route->prefsrc);
1588 else
1589 r = in_addr_from_string(route->family, rvalue, &route->prefsrc);
1590 if (r < 0) {
1591 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
1592 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
1593 return 0;
1594 }
1595
1596 TAKE_PTR(route);
1597 return 0;
1598 }
1599
1600 int config_parse_destination(
1601 const char *unit,
1602 const char *filename,
1603 unsigned line,
1604 const char *section,
1605 unsigned section_line,
1606 const char *lvalue,
1607 int ltype,
1608 const char *rvalue,
1609 void *data,
1610 void *userdata) {
1611
1612 Network *network = userdata;
1613 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1614 union in_addr_union *buffer;
1615 unsigned char *prefixlen;
1616 int r;
1617
1618 assert(filename);
1619 assert(section);
1620 assert(lvalue);
1621 assert(rvalue);
1622 assert(data);
1623
1624 r = route_new_static(network, filename, section_line, &route);
1625 if (r == -ENOMEM)
1626 return log_oom();
1627 if (r < 0) {
1628 log_syntax(unit, LOG_WARNING, filename, line, r,
1629 "Failed to allocate route, ignoring assignment: %m");
1630 return 0;
1631 }
1632
1633 if (streq(lvalue, "Destination")) {
1634 buffer = &route->dst;
1635 prefixlen = &route->dst_prefixlen;
1636 } else if (streq(lvalue, "Source")) {
1637 buffer = &route->src;
1638 prefixlen = &route->src_prefixlen;
1639 } else
1640 assert_not_reached();
1641
1642 if (route->family == AF_UNSPEC)
1643 r = in_addr_prefix_from_string_auto(rvalue, &route->family, buffer, prefixlen);
1644 else
1645 r = in_addr_prefix_from_string(rvalue, route->family, buffer, prefixlen);
1646 if (r < 0) {
1647 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
1648 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
1649 return 0;
1650 }
1651
1652 (void) in_addr_mask(route->family, buffer, *prefixlen);
1653
1654 TAKE_PTR(route);
1655 return 0;
1656 }
1657
1658 int config_parse_route_priority(
1659 const char *unit,
1660 const char *filename,
1661 unsigned line,
1662 const char *section,
1663 unsigned section_line,
1664 const char *lvalue,
1665 int ltype,
1666 const char *rvalue,
1667 void *data,
1668 void *userdata) {
1669
1670 Network *network = userdata;
1671 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1672 int r;
1673
1674 assert(filename);
1675 assert(section);
1676 assert(lvalue);
1677 assert(rvalue);
1678 assert(data);
1679
1680 r = route_new_static(network, filename, section_line, &route);
1681 if (r == -ENOMEM)
1682 return log_oom();
1683 if (r < 0) {
1684 log_syntax(unit, LOG_WARNING, filename, line, r,
1685 "Failed to allocate route, ignoring assignment: %m");
1686 return 0;
1687 }
1688
1689 r = safe_atou32(rvalue, &route->priority);
1690 if (r < 0) {
1691 log_syntax(unit, LOG_WARNING, filename, line, r,
1692 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
1693 return 0;
1694 }
1695
1696 route->priority_set = true;
1697 TAKE_PTR(route);
1698 return 0;
1699 }
1700
1701 int config_parse_route_scope(
1702 const char *unit,
1703 const char *filename,
1704 unsigned line,
1705 const char *section,
1706 unsigned section_line,
1707 const char *lvalue,
1708 int ltype,
1709 const char *rvalue,
1710 void *data,
1711 void *userdata) {
1712
1713 Network *network = userdata;
1714 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1715 int r;
1716
1717 assert(filename);
1718 assert(section);
1719 assert(lvalue);
1720 assert(rvalue);
1721 assert(data);
1722
1723 r = route_new_static(network, filename, section_line, &route);
1724 if (r == -ENOMEM)
1725 return log_oom();
1726 if (r < 0) {
1727 log_syntax(unit, LOG_WARNING, filename, line, r,
1728 "Failed to allocate route, ignoring assignment: %m");
1729 return 0;
1730 }
1731
1732 r = route_scope_from_string(rvalue);
1733 if (r < 0) {
1734 log_syntax(unit, LOG_WARNING, filename, line, r, "Unknown route scope: %s", rvalue);
1735 return 0;
1736 }
1737
1738 route->scope = r;
1739 route->scope_set = true;
1740 TAKE_PTR(route);
1741 return 0;
1742 }
1743
1744 int config_parse_route_table(
1745 const char *unit,
1746 const char *filename,
1747 unsigned line,
1748 const char *section,
1749 unsigned section_line,
1750 const char *lvalue,
1751 int ltype,
1752 const char *rvalue,
1753 void *data,
1754 void *userdata) {
1755
1756 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1757 Network *network = userdata;
1758 int r;
1759
1760 assert(filename);
1761 assert(section);
1762 assert(lvalue);
1763 assert(rvalue);
1764 assert(data);
1765
1766 r = route_new_static(network, filename, section_line, &route);
1767 if (r == -ENOMEM)
1768 return log_oom();
1769 if (r < 0) {
1770 log_syntax(unit, LOG_WARNING, filename, line, r,
1771 "Failed to allocate route, ignoring assignment: %m");
1772 return 0;
1773 }
1774
1775 r = manager_get_route_table_from_string(network->manager, rvalue, &route->table);
1776 if (r < 0) {
1777 log_syntax(unit, LOG_WARNING, filename, line, r,
1778 "Could not parse route table \"%s\", ignoring assignment: %m", rvalue);
1779 return 0;
1780 }
1781
1782 route->table_set = true;
1783 TAKE_PTR(route);
1784 return 0;
1785 }
1786
1787 int config_parse_ipv6_route_preference(
1788 const char *unit,
1789 const char *filename,
1790 unsigned line,
1791 const char *section,
1792 unsigned section_line,
1793 const char *lvalue,
1794 int ltype,
1795 const char *rvalue,
1796 void *data,
1797 void *userdata) {
1798
1799 Network *network = userdata;
1800 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1801 int r;
1802
1803 r = route_new_static(network, filename, section_line, &route);
1804 if (r == -ENOMEM)
1805 return log_oom();
1806 if (r < 0) {
1807 log_syntax(unit, LOG_WARNING, filename, line, r,
1808 "Failed to allocate route, ignoring assignment: %m");
1809 return 0;
1810 }
1811
1812 if (streq(rvalue, "low"))
1813 route->pref = ICMPV6_ROUTER_PREF_LOW;
1814 else if (streq(rvalue, "medium"))
1815 route->pref = ICMPV6_ROUTER_PREF_MEDIUM;
1816 else if (streq(rvalue, "high"))
1817 route->pref = ICMPV6_ROUTER_PREF_HIGH;
1818 else {
1819 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route preference: %s", rvalue);
1820 return 0;
1821 }
1822
1823 route->pref_set = true;
1824 TAKE_PTR(route);
1825 return 0;
1826 }
1827
1828 int config_parse_route_protocol(
1829 const char *unit,
1830 const char *filename,
1831 unsigned line,
1832 const char *section,
1833 unsigned section_line,
1834 const char *lvalue,
1835 int ltype,
1836 const char *rvalue,
1837 void *data,
1838 void *userdata) {
1839
1840 Network *network = userdata;
1841 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1842 int r;
1843
1844 r = route_new_static(network, filename, section_line, &route);
1845 if (r == -ENOMEM)
1846 return log_oom();
1847 if (r < 0) {
1848 log_syntax(unit, LOG_WARNING, filename, line, r,
1849 "Failed to allocate route, ignoring assignment: %m");
1850 return 0;
1851 }
1852
1853 r = route_protocol_from_string(rvalue);
1854 if (r < 0) {
1855 log_syntax(unit, LOG_WARNING, filename, line, r,
1856 "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue);
1857 return 0;
1858 }
1859
1860 route->protocol = r;
1861
1862 TAKE_PTR(route);
1863 return 0;
1864 }
1865
1866 int config_parse_route_type(
1867 const char *unit,
1868 const char *filename,
1869 unsigned line,
1870 const char *section,
1871 unsigned section_line,
1872 const char *lvalue,
1873 int ltype,
1874 const char *rvalue,
1875 void *data,
1876 void *userdata) {
1877
1878 Network *network = userdata;
1879 _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1880 int t, r;
1881
1882 r = route_new_static(network, filename, section_line, &route);
1883 if (r == -ENOMEM)
1884 return log_oom();
1885 if (r < 0) {
1886 log_syntax(unit, LOG_WARNING, filename, line, r,
1887 "Failed to allocate route, ignoring assignment: %m");
1888 return 0;
1889 }
1890
1891 t = route_type_from_string(rvalue);
1892 if (t < 0) {
1893 log_syntax(unit, LOG_WARNING, filename, line, r,
1894 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
1895 return 0;
1896 }
1897
1898 route->type = (unsigned char) t;
1899
1900 TAKE_PTR(route);
1901 return 0;
1902 }
1903
1904 int route_section_verify(Route *route) {
1905 int r;
1906
1907 assert(route);
1908 assert(route->section);
1909
1910 if (section_is_invalid(route->section))
1911 return -EINVAL;
1912
1913 /* Currently, we do not support static route with finite lifetime. */
1914 assert(route->lifetime_usec == USEC_INFINITY);
1915
1916 r = route_section_verify_nexthops(route);
1917 if (r < 0)
1918 return r;
1919
1920 /* table */
1921 if (!route->table_set && route->network && route->network->vrf) {
1922 route->table = VRF(route->network->vrf)->table;
1923 route->table_set = true;
1924 }
1925
1926 if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
1927 route->table = RT_TABLE_LOCAL;
1928
1929 /* scope */
1930 if (!route->scope_set && route->family == AF_INET) {
1931 if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
1932 route->scope = RT_SCOPE_HOST;
1933 else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
1934 route->scope = RT_SCOPE_LINK;
1935 else if (IN_SET(route->type, RTN_UNICAST, RTN_UNSPEC) &&
1936 !route->gateway_from_dhcp_or_ra &&
1937 !in_addr_is_set(route->nexthop.family, &route->nexthop.gw) &&
1938 ordered_set_isempty(route->nexthops) &&
1939 route->nexthop_id == 0)
1940 route->scope = RT_SCOPE_LINK;
1941 }
1942
1943 /* IPv6 route */
1944 if (route->family == AF_INET6) {
1945 if (route->scope != RT_SCOPE_UNIVERSE) {
1946 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route->section->filename);
1947 route->scope = RT_SCOPE_UNIVERSE;
1948 }
1949
1950 if (route->priority == 0)
1951 route->priority = IP6_RT_PRIO_USER;
1952 }
1953
1954 return 0;
1955 }
1956
1957 void network_drop_invalid_routes(Network *network) {
1958 Route *route;
1959
1960 assert(network);
1961
1962 HASHMAP_FOREACH(route, network->routes_by_section)
1963 if (route_section_verify(route) < 0)
1964 route_detach(route);
1965 }