1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/icmpv6.h>
4 #include <linux/ipv6_route.h>
5 #include <linux/nexthop.h>
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"
22 #include "wireguard.h"
24 static Route
* route_detach_impl(Route
*route
) {
26 assert(!!route
->network
+ !!route
->manager
+ !!route
->wireguard
<= 1);
29 assert(route
->section
);
30 hashmap_remove(route
->network
->routes_by_section
, route
->section
);
31 route
->network
= NULL
;
36 route_detach_from_nexthop(route
);
37 set_remove(route
->manager
->routes
, route
);
38 route
->manager
= NULL
;
42 if (route
->wireguard
) {
43 set_remove(route
->wireguard
->routes
, route
);
44 route
->wireguard
= NULL
;
51 static void route_detach(Route
*route
) {
52 route_unref(route_detach_impl(route
));
55 static Route
* route_free(Route
*route
) {
59 route_detach_impl(route
);
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
);
69 DEFINE_TRIVIAL_REF_UNREF_FUNC(Route
, route
, route_free
);
71 static void route_hash_func(const Route
*route
, struct siphash
*state
) {
74 siphash24_compress_typesafe(route
->family
, state
);
76 switch (route
->family
) {
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
);
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
);
95 /* nexthops (id, number of nexthops, nexthop) */
96 route_nexthops_hash_func(route
, state
);
99 route_metric_hash_func(&route
->metric
, state
);
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
);
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
);
113 /* See fib6_add_rt2node(). */
114 siphash24_compress_typesafe(route
->priority
, state
);
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
);
120 /* Unlike IPv4 routes, metrics are not taken into account. */
124 /* treat any other address family as AF_UNSPEC */
129 static int route_compare_func(const Route
*a
, const Route
*b
) {
132 r
= CMP(a
->family
, b
->family
);
138 r
= CMP(a
->table
, b
->table
);
142 r
= memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
146 r
= CMP(a
->dst_prefixlen
, b
->dst_prefixlen
);
150 r
= CMP(a
->priority
, b
->priority
);
154 r
= CMP(a
->tos
, b
->tos
);
158 r
= CMP(a
->protocol
, b
->protocol
);
162 r
= CMP(a
->scope
, b
->scope
);
166 r
= CMP(a
->type
, b
->type
);
170 r
= CMP(a
->flags
& ~RTNH_COMPARE_MASK
, b
->flags
& ~RTNH_COMPARE_MASK
);
174 r
= memcmp(&a
->prefsrc
, &b
->prefsrc
, FAMILY_ADDRESS_SIZE(a
->family
));
178 r
= route_nexthops_compare_func(a
, b
);
182 return route_metric_compare_func(&a
->metric
, &b
->metric
);
185 r
= CMP(a
->table
, b
->table
);
189 r
= memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
193 r
= CMP(a
->dst_prefixlen
, b
->dst_prefixlen
);
197 r
= memcmp(&a
->src
, &b
->src
, FAMILY_ADDRESS_SIZE(a
->family
));
201 r
= CMP(a
->src_prefixlen
, b
->src_prefixlen
);
205 r
= CMP(a
->priority
, b
->priority
);
209 return route_nexthops_compare_func(a
, b
);
212 /* treat any other address family as AF_UNSPEC */
217 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
224 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
225 route_hash_ops_unref
,
231 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
232 route_section_hash_ops
,
234 config_section_hash_func
,
235 config_section_compare_func
,
239 int route_new(Route
**ret
) {
240 _cleanup_(route_unrefp
) Route
*route
= NULL
;
242 route
= new(Route
, 1);
249 .scope
= RT_SCOPE_UNIVERSE
,
250 .protocol
= RTPROT_UNSPEC
,
252 .table
= RT_TABLE_MAIN
,
253 .lifetime_usec
= USEC_INFINITY
,
254 .gateway_onlink
= -1,
257 *ret
= TAKE_PTR(route
);
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
;
270 assert(section_line
> 0);
272 r
= config_section_new(filename
, section_line
, &n
);
276 route
= hashmap_get(network
->routes_by_section
, n
);
278 *ret
= TAKE_PTR(route
);
282 if (hashmap_size(network
->routes_by_section
) >= routes_max())
285 r
= route_new(&route
);
289 route
->protocol
= RTPROT_STATIC
;
290 route
->network
= network
;
291 route
->section
= TAKE_PTR(n
);
292 route
->source
= NETWORK_CONFIG_SOURCE_STATIC
;
294 r
= hashmap_ensure_put(&network
->routes_by_section
, &route_section_hash_ops
, route
->section
, route
);
298 *ret
= TAKE_PTR(route
);
302 static int route_attach(Manager
*manager
, Route
*route
) {
307 assert(!route
->network
);
308 assert(!route
->wireguard
);
310 r
= set_ensure_put(&manager
->routes
, &route_hash_ops
, route
);
316 route
->manager
= manager
;
320 int route_get(Manager
*manager
, const Route
*route
, Route
**ret
) {
326 existing
= set_get(manager
->routes
, route
);
336 static int route_get_link(Manager
*manager
, const Route
*route
, Link
**ret
) {
342 if (route
->nexthop_id
!= 0) {
345 r
= nexthop_get_by_id(manager
, route
->nexthop_id
, &nh
);
349 return link_get_by_index(manager
, nh
->ifindex
, ret
);
352 return route_nexthop_get_link(manager
, &route
->nexthop
, ret
);
355 int route_get_request(Manager
*manager
, const Route
*route
, Request
**ret
) {
361 req
= ordered_set_get(manager
->request_queue
,
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
,
376 int route_dup(const Route
*src
, const RouteNextHop
*nh
, Route
**ret
) {
377 _cleanup_(route_unrefp
) Route
*dest
= NULL
;
383 dest
= newdup(Route
, src
, 1);
387 /* Unset number of reference and all pointers */
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
;
398 r
= route_nexthops_copy(src
, nh
, dest
);
402 r
= route_metric_copy(&src
->metric
, &dest
->metric
);
406 *ret
= TAKE_PTR(dest
);
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
;
423 (void) route_get_link(manager
, route
, &link
);
425 (void) network_config_state_to_string_alloc(route
->state
, &state
);
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
;
432 (void) route_nexthops_to_string(route
, &nexthop
);
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
);
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
));
451 static int route_set_netlink_message(const Route
*route
, sd_netlink_message
*m
) {
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
);
463 r
= sd_rtnl_message_route_set_dst_prefixlen(m
, route
->dst_prefixlen
);
468 if (route
->src_prefixlen
> 0) {
469 r
= netlink_message_append_in_addr_union(m
, RTA_SRC
, route
->family
, &route
->src
);
473 r
= sd_rtnl_message_route_set_src_prefixlen(m
, route
->src_prefixlen
);
478 r
= sd_rtnl_message_route_set_tos(m
, route
->tos
);
482 r
= sd_rtnl_message_route_set_scope(m
, route
->scope
);
486 r
= sd_rtnl_message_route_set_type(m
, route
->type
);
490 r
= sd_rtnl_message_route_set_flags(m
, route
->flags
& ~RTNH_COMPARE_MASK
);
495 r
= sd_netlink_message_append_u32(m
, RTA_PRIORITY
, route
->priority
);
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
);
505 if (route
->table
< 256) {
506 r
= sd_rtnl_message_route_set_table(m
, route
->table
);
510 r
= sd_rtnl_message_route_set_table(m
, RT_TABLE_UNSPEC
);
514 /* Table attribute to allow more than 256. */
515 r
= sd_netlink_message_append_u32(m
, RTA_TABLE
, route
->table
);
520 r
= sd_netlink_message_append_u8(m
, RTA_PREF
, route
->pref
);
525 r
= route_nexthops_set_netlink_message(route
, m
);
530 r
= route_metric_set_netlink_message(&route
->metric
, m
);
537 static int route_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, RemoveRequest
*rreq
) {
543 Manager
*manager
= ASSERT_PTR(rreq
->manager
);
544 Route
*route
= ASSERT_PTR(rreq
->userdata
);
546 r
= sd_netlink_message_get_errno(m
);
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");
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
);
560 if (route_get_request(manager
, route
, &req
) >= 0)
561 route_enter_removed(req
->userdata
);
570 int route_remove(Route
*route
, Manager
*manager
) {
571 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
578 /* If the route is remembered, then use the remembered object. */
579 (void) route_get(manager
, route
, &route
);
581 log_route_debug(route
, "Removing", manager
);
584 (void) route_get_link(manager
, route
, &link
);
586 r
= sd_rtnl_message_new_route(manager
->rtnl
, &m
, RTM_DELROUTE
, route
->family
, route
->protocol
);
588 return log_link_warning_errno(link
, r
, "Could not create netlink message: %m");
590 r
= route_set_netlink_message(route
, m
);
592 return log_link_warning_errno(link
, r
, "Could not fill netlink message: %m");
594 r
= manager_remove_request_add(manager
, route
, route
, manager
->rtnl
, m
, route_remove_handler
);
596 return log_link_warning_errno(link
, r
, "Could not queue rtnetlink message: %m");
598 route_enter_removing(route
);
602 int route_remove_and_cancel(Route
*route
, Manager
*manager
) {
603 bool waiting
= false;
609 /* If the route is remembered by the manager, then use the remembered object. */
610 (void) route_get(manager
, route
, &route
);
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 waiting
= req
->waiting_reply
;
617 route_cancel_requesting(route
);
620 /* If we know that the route will come or already exists, remove it. */
621 if (waiting
|| (route
->manager
&& route_exists(route
)))
622 return route_remove(route
, manager
);
627 static int route_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
628 Route
*route
= ASSERT_PTR(userdata
);
632 return 0; /* already detached. */
634 r
= route_remove(route
, route
->manager
);
637 (void) route_get_link(route
->manager
, route
, &link
);
638 log_link_warning_errno(link
, r
, "Could not remove route: %m");
640 link_enter_failed(link
);
646 static int route_setup_timer(Route
*route
, const struct rta_cacheinfo
*cacheinfo
) {
651 if (cacheinfo
&& cacheinfo
->rta_expires
!= 0)
652 route
->expiration_managed_by_kernel
= true;
654 if (route
->lifetime_usec
== USEC_INFINITY
|| /* We do not request expiration for the route. */
655 route
->expiration_managed_by_kernel
) { /* We have received nonzero expiration previously. The expiration is managed by the kernel. */
656 route
->expire
= sd_event_source_disable_unref(route
->expire
);
660 Manager
*manager
= ASSERT_PTR(route
->manager
);
661 r
= event_reset_time(manager
->event
, &route
->expire
, CLOCK_BOOTTIME
,
662 route
->lifetime_usec
, 0, route_expire_handler
, route
, 0, "route-expiration", true);
665 (void) route_get_link(manager
, route
, &link
);
666 return log_link_warning_errno(link
, r
, "Failed to configure expiration timer for route, ignoring: %m");
669 log_route_debug(route
, "Configured expiration timer for", manager
);
673 int route_configure_handler_internal(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
, Route
*route
, const char *error_msg
) {
678 assert(link
->manager
);
682 r
= sd_netlink_message_get_errno(m
);
686 if (route_get(link
->manager
, route
, &existing
) >= 0) {
687 /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE
688 * notification, so we need to update the timer here. */
689 existing
->lifetime_usec
= route
->lifetime_usec
;
690 (void) route_setup_timer(existing
, NULL
);
692 /* This may be a bug in the kernel, but the MTU of an IPv6 route can be updated only
693 * when the route has an expiration timer managed by the kernel (not by us).
694 * See fib6_add_rt2node() in net/ipv6/ip6_fib.c of the kernel. */
695 if (existing
->family
== AF_INET6
&&
696 existing
->expiration_managed_by_kernel
) {
697 r
= route_metric_set(&existing
->metric
, RTAX_MTU
, route_metric_get(&route
->metric
, RTAX_MTU
));
700 link_enter_failed(link
);
707 log_link_message_warning_errno(link
, m
, r
, error_msg
);
708 link_enter_failed(link
);
715 static int route_configure(const Route
*route
, uint32_t lifetime_sec
, Link
*link
, Request
*req
) {
716 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
721 assert(link
->manager
);
724 log_route_debug(route
, "Configuring", link
->manager
);
726 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &m
, RTM_NEWROUTE
, route
->family
, route
->protocol
);
730 r
= route_set_netlink_message(route
, m
);
734 if (lifetime_sec
!= UINT32_MAX
) {
735 r
= sd_netlink_message_append_u32(m
, RTA_EXPIRES
, lifetime_sec
);
740 return request_call_netlink_async(link
->manager
->rtnl
, m
, req
);
743 static int route_requeue_request(Request
*req
, Link
*link
, const Route
*route
) {
744 _unused_
_cleanup_(request_unrefp
) Request
*req_unref
= NULL
;
745 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
750 assert(link
->manager
);
753 /* It is not possible to adjust the Route object owned by Request, as it is used as a key to manage
754 * Request objects in the queue. Hence, we need to re-request with the updated Route object. */
756 if (!route_nexthops_needs_adjust(route
))
757 return 0; /* The Route object does not need the adjustment. Continue with it. */
759 r
= route_dup(route
, NULL
, &tmp
);
763 r
= route_adjust_nexthops(tmp
, link
);
767 if (route_compare_func(route
, tmp
) == 0 && route
->type
== tmp
->type
)
768 return 0; /* No effective change?? That's OK. */
770 /* Avoid the request to be freed by request_detach(). */
771 req_unref
= request_ref(req
);
773 /* Detach the request from the queue, to make not the new request is deduped.
774 * Why this is necessary? IPv6 routes with different type may be handled as the same,
775 * As commented in route_adjust_nexthops(), we need to configure the adjusted type,
776 * otherwise we cannot remove the route on reconfigure or so. If we request the new Route object
777 * without detaching the current request, the new request is deduped, and the route is configured
778 * with unmodified type. */
781 /* Request the route with the adjusted Route object combined with the same other parameters. */
782 r
= link_queue_request_full(link
,
790 req
->netlink_handler
,
795 return 1; /* Already queued?? That's OK. Maybe, [Route] section is effectively duplicated. */
798 return 1; /* New request is queued. Finish to process this request. */
801 static int route_is_ready_to_configure(const Route
*route
, Link
*link
) {
807 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
810 if (in_addr_is_set(route
->family
, &route
->prefsrc
) > 0) {
811 r
= manager_has_address(link
->manager
, route
->family
, &route
->prefsrc
);
816 return route_nexthops_is_ready_to_configure(route
, link
->manager
);
819 static int route_process_request(Request
*req
, Link
*link
, Route
*route
) {
825 assert(link
->manager
);
828 r
= route_is_ready_to_configure(route
, link
);
830 return log_link_warning_errno(link
, r
, "Failed to check if route is ready to configure: %m");
835 assert_se(sd_event_now(link
->manager
->event
, CLOCK_BOOTTIME
, &now_usec
) >= 0);
836 uint32_t sec
= usec_to_sec(route
->lifetime_usec
, now_usec
);
838 log_link_debug(link
, "Refuse to configure %s route with zero lifetime.",
839 network_config_source_to_string(route
->source
));
841 route_cancel_requesting(route
);
842 if (route_get(link
->manager
, route
, &existing
) >= 0)
843 route_cancel_requesting(existing
);
847 r
= route_requeue_request(req
, link
, route
);
851 r
= route_configure(route
, sec
, link
, req
);
853 return log_link_warning_errno(link
, r
, "Failed to configure route: %m");
855 route_enter_configuring(route
);
856 if (route_get(link
->manager
, route
, &existing
) >= 0)
857 route_enter_configuring(existing
);
861 static int link_request_route_one(
864 const RouteNextHop
*nh
,
865 unsigned *message_counter
,
866 route_netlink_handler_t netlink_handler
) {
868 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
869 Route
*existing
= NULL
;
873 assert(link
->manager
);
876 r
= route_dup(route
, nh
, &tmp
);
880 r
= route_adjust_nexthops(tmp
, link
);
884 if (route_get(link
->manager
, tmp
, &existing
) >= 0)
885 /* Copy state for logging below. */
886 tmp
->state
= existing
->state
;
888 log_route_debug(tmp
, "Requesting", link
->manager
);
889 r
= link_queue_request_safe(link
, REQUEST_TYPE_ROUTE
,
894 route_process_request
,
901 route_enter_requesting(tmp
);
903 route_enter_requesting(existing
);
909 int link_request_route(
912 unsigned *message_counter
,
913 route_netlink_handler_t netlink_handler
) {
918 assert(link
->manager
);
920 assert(route
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
);
922 if (route
->family
== AF_INET
|| route_type_is_reject(route
) || ordered_set_isempty(route
->nexthops
))
923 return link_request_route_one(link
, route
, NULL
, message_counter
, netlink_handler
);
926 ORDERED_SET_FOREACH(nh
, route
->nexthops
) {
927 r
= link_request_route_one(link
, route
, nh
, message_counter
, netlink_handler
);
935 static int static_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
940 r
= route_configure_handler_internal(rtnl
, m
, link
, route
, "Could not set route");
944 if (link
->static_route_messages
== 0) {
945 log_link_debug(link
, "Routes set");
946 link
->static_routes_configured
= true;
947 link_check_ready(link
);
953 static int link_request_wireguard_routes(Link
*link
, bool only_ipv4
) {
960 if (!streq_ptr(link
->kind
, "wireguard"))
963 if (netdev_get(link
->manager
, link
->ifname
, &netdev
) < 0)
966 Wireguard
*w
= WIREGUARD(netdev
);
968 SET_FOREACH(route
, w
->routes
) {
969 if (only_ipv4
&& route
->family
!= AF_INET
)
972 r
= link_request_route(link
, route
, &link
->static_route_messages
, static_route_handler
);
980 int link_request_static_routes(Link
*link
, bool only_ipv4
) {
985 assert(link
->network
);
987 link
->static_routes_configured
= false;
989 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
990 if (route
->gateway_from_dhcp_or_ra
)
993 if (only_ipv4
&& route
->family
!= AF_INET
)
996 r
= link_request_route(link
, route
, &link
->static_route_messages
, static_route_handler
);
1001 r
= link_request_wireguard_routes(link
, only_ipv4
);
1005 if (link
->static_route_messages
== 0) {
1006 link
->static_routes_configured
= true;
1007 link_check_ready(link
);
1009 log_link_debug(link
, "Requesting routes");
1010 link_set_state(link
, LINK_STATE_CONFIGURING
);
1016 static int process_route_one(
1020 const struct rta_cacheinfo
*cacheinfo
) {
1022 Request
*req
= NULL
;
1023 Route
*route
= NULL
;
1025 bool is_new
= false, update_dhcp4
;
1030 assert(IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
));
1032 (void) route_get(manager
, tmp
, &route
);
1033 (void) route_get_request(manager
, tmp
, &req
);
1034 (void) route_get_link(manager
, tmp
, &link
);
1036 update_dhcp4
= link
&& tmp
->family
== AF_INET6
&& tmp
->dst_prefixlen
== 0;
1041 if (!manager
->manage_foreign_routes
&& !(req
&& req
->waiting_reply
)) {
1042 route_enter_configured(tmp
);
1043 log_route_debug(tmp
, "Ignoring received", manager
);
1047 /* If we do not know the route, then save it. */
1048 r
= route_attach(manager
, tmp
);
1050 log_link_warning_errno(link
, r
, "Failed to remember foreign route, ignoring: %m");
1054 route
= route_ref(tmp
);
1058 /* Update remembered route with the received notification. */
1059 route
->nexthop
.weight
= tmp
->nexthop
.weight
;
1061 /* Also update information that cannot be obtained through netlink notification. */
1062 if (req
&& req
->waiting_reply
) {
1063 Route
*rt
= ASSERT_PTR(req
->userdata
);
1065 route
->source
= rt
->source
;
1066 route
->provider
= rt
->provider
;
1067 route
->lifetime_usec
= rt
->lifetime_usec
;
1070 route_enter_configured(route
);
1071 log_route_debug(route
, is_new
? "Received new" : "Received remembered", manager
);
1073 (void) route_setup_timer(route
, cacheinfo
);
1079 route_enter_removed(route
);
1080 log_route_debug(route
, "Forgetting removed", manager
);
1081 route_detach(route
);
1083 log_route_debug(tmp
,
1084 manager
->manage_foreign_routes
? "Kernel removed unknown" : "Ignoring received",
1088 route_enter_removed(req
->userdata
);
1093 assert_not_reached();
1097 r
= dhcp4_update_ipv6_connectivity(link
);
1099 log_link_warning_errno(link
, r
, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");
1100 link_enter_failed(link
);
1107 int manager_rtnl_process_route(sd_netlink
*rtnl
, sd_netlink_message
*message
, Manager
*m
) {
1108 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
1115 if (sd_netlink_message_is_error(message
)) {
1116 r
= sd_netlink_message_get_errno(message
);
1118 log_message_warning_errno(message
, r
, "rtnl: failed to receive route message, ignoring");
1124 r
= sd_netlink_message_get_type(message
, &type
);
1126 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
1128 } else if (!IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
)) {
1129 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type
);
1133 r
= route_new(&tmp
);
1138 r
= sd_rtnl_message_route_get_family(message
, &tmp
->family
);
1140 log_warning_errno(r
, "rtnl: received route message without family, ignoring: %m");
1142 } else if (!IN_SET(tmp
->family
, AF_INET
, AF_INET6
)) {
1143 log_debug("rtnl: received route message with invalid family '%i', ignoring.", tmp
->family
);
1147 r
= sd_rtnl_message_route_get_dst_prefixlen(message
, &tmp
->dst_prefixlen
);
1149 log_warning_errno(r
, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1153 r
= sd_rtnl_message_route_get_src_prefixlen(message
, &tmp
->src_prefixlen
);
1155 log_warning_errno(r
, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1159 r
= sd_rtnl_message_route_get_tos(message
, &tmp
->tos
);
1161 log_warning_errno(r
, "rtnl: received route message with invalid tos, ignoring: %m");
1165 r
= sd_rtnl_message_route_get_protocol(message
, &tmp
->protocol
);
1167 log_warning_errno(r
, "rtnl: received route message without route protocol, ignoring: %m");
1171 r
= sd_rtnl_message_route_get_scope(message
, &tmp
->scope
);
1173 log_warning_errno(r
, "rtnl: received route message with invalid scope, ignoring: %m");
1177 r
= sd_rtnl_message_route_get_type(message
, &tmp
->type
);
1179 log_warning_errno(r
, "rtnl: received route message with invalid type, ignoring: %m");
1183 r
= sd_rtnl_message_route_get_flags(message
, &tmp
->flags
);
1185 log_warning_errno(r
, "rtnl: received route message without route flags, ignoring: %m");
1190 r
= netlink_message_read_in_addr_union(message
, RTA_DST
, tmp
->family
, &tmp
->dst
);
1191 if (r
< 0 && r
!= -ENODATA
) {
1192 log_warning_errno(r
, "rtnl: received route message without valid destination, ignoring: %m");
1196 r
= netlink_message_read_in_addr_union(message
, RTA_SRC
, tmp
->family
, &tmp
->src
);
1197 if (r
< 0 && r
!= -ENODATA
) {
1198 log_warning_errno(r
, "rtnl: received route message without valid source, ignoring: %m");
1202 r
= sd_netlink_message_read_u32(message
, RTA_PRIORITY
, &tmp
->priority
);
1203 if (r
< 0 && r
!= -ENODATA
) {
1204 log_warning_errno(r
, "rtnl: received route message with invalid priority, ignoring: %m");
1208 r
= netlink_message_read_in_addr_union(message
, RTA_PREFSRC
, tmp
->family
, &tmp
->prefsrc
);
1209 if (r
< 0 && r
!= -ENODATA
) {
1210 log_warning_errno(r
, "rtnl: received route message without valid preferred source, ignoring: %m");
1214 r
= sd_netlink_message_read_u32(message
, RTA_TABLE
, &tmp
->table
);
1215 if (r
== -ENODATA
) {
1216 unsigned char table
;
1218 r
= sd_rtnl_message_route_get_table(message
, &table
);
1223 log_warning_errno(r
, "rtnl: received route message with invalid table, ignoring: %m");
1227 r
= sd_netlink_message_read_u8(message
, RTA_PREF
, &tmp
->pref
);
1228 if (r
< 0 && r
!= -ENODATA
) {
1229 log_warning_errno(r
, "rtnl: received route message with invalid preference, ignoring: %m");
1234 if (route_nexthops_read_netlink_message(tmp
, message
) < 0)
1238 if (route_metric_read_netlink_message(&tmp
->metric
, message
) < 0)
1242 struct rta_cacheinfo cacheinfo
;
1243 r
= sd_netlink_message_read(message
, RTA_CACHEINFO
, sizeof(cacheinfo
), &cacheinfo
);
1244 if (r
< 0 && r
!= -ENODATA
) {
1245 log_warning_errno(r
, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1248 has_cacheinfo
= r
>= 0;
1250 if (tmp
->family
== AF_INET
|| ordered_set_isempty(tmp
->nexthops
))
1251 return process_route_one(m
, type
, tmp
, has_cacheinfo
? &cacheinfo
: NULL
);
1254 ORDERED_SET_FOREACH(nh
, tmp
->nexthops
) {
1255 _cleanup_(route_unrefp
) Route
*dup
= NULL
;
1257 r
= route_dup(tmp
, nh
, &dup
);
1261 r
= process_route_one(m
, type
, dup
, has_cacheinfo
? &cacheinfo
: NULL
);
1269 void manager_mark_routes(Manager
*manager
, Link
*link
, NetworkConfigSource source
) {
1274 SET_FOREACH(route
, manager
->routes
) {
1275 if (route
->source
!= source
)
1281 if (route_get_link(manager
, route
, &route_link
) < 0)
1283 if (route_link
!= link
)
1291 static bool route_by_kernel(const Route
*route
) {
1294 if (route
->protocol
== RTPROT_KERNEL
)
1297 /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
1298 * multicast with RTPROT_BOOT. Do not touch it. */
1299 if (route
->protocol
== RTPROT_BOOT
&&
1300 route
->family
== AF_INET6
&&
1301 route
->dst_prefixlen
== 8 &&
1302 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 }}}))
1308 bool route_can_update(const Route
*existing
, const Route
*requesting
) {
1312 if (route_compare_func(existing
, requesting
) != 0)
1315 switch (existing
->family
) {
1317 if (existing
->nexthop
.weight
!= requesting
->nexthop
.weight
)
1322 if (existing
->protocol
!= requesting
->protocol
)
1324 if (existing
->type
!= requesting
->type
)
1326 if (existing
->flags
!= requesting
->flags
)
1328 if (!in6_addr_equal(&existing
->prefsrc
.in6
, &requesting
->prefsrc
.in6
))
1330 if (existing
->pref
!= requesting
->pref
)
1332 if (existing
->expiration_managed_by_kernel
&& requesting
->lifetime_usec
!= USEC_INFINITY
)
1333 return false; /* We cannot disable expiration timer in the kernel. */
1334 if (!route_metric_can_update(&existing
->metric
, &requesting
->metric
, existing
->expiration_managed_by_kernel
))
1336 if (existing
->nexthop
.weight
!= requesting
->nexthop
.weight
)
1341 assert_not_reached();
1345 static int link_unmark_route(Link
*link
, const Route
*route
, const RouteNextHop
*nh
) {
1346 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
1353 r
= route_dup(route
, nh
, &tmp
);
1357 r
= route_adjust_nexthops(tmp
, link
);
1361 if (route_get(link
->manager
, tmp
, &existing
) < 0)
1364 if (!route_can_update(existing
, tmp
))
1367 route_unmark(existing
);
1371 static int link_mark_routes(Link
*link
, bool foreign
) {
1377 assert(link
->manager
);
1379 /* First, mark all routes. */
1380 SET_FOREACH(route
, link
->manager
->routes
) {
1381 /* Do not touch routes managed by the kernel. */
1382 if (route_by_kernel(route
))
1385 /* When 'foreign' is true, mark only foreign routes, and vice versa.
1386 * Note, do not touch dynamic routes. They will removed by when e.g. lease is lost. */
1387 if (route
->source
!= (foreign
? NETWORK_CONFIG_SOURCE_FOREIGN
: NETWORK_CONFIG_SOURCE_STATIC
))
1390 /* Ignore routes not assigned yet or already removed. */
1391 if (!route_exists(route
))
1394 if (link
->network
) {
1395 if (route
->protocol
== RTPROT_STATIC
&&
1396 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_STATIC
))
1399 if (route
->protocol
== RTPROT_DHCP
&&
1400 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_DHCP
))
1404 /* When we mark foreign routes, do not mark routes assigned to other interfaces.
1405 * Otherwise, routes assigned to unmanaged interfaces will be dropped.
1406 * Note, route_get_link() does not provide assigned link for routes with an unreachable type
1407 * or IPv4 multipath routes. So, the current implementation does not support managing such
1408 * routes by other daemon or so, unless ManageForeignRoutes=no. */
1412 if (route_get_link(link
->manager
, route
, &route_link
) >= 0 && route_link
!= link
)
1419 /* Then, unmark all routes requested by active links. */
1420 HASHMAP_FOREACH(other
, link
->manager
->links_by_index
) {
1421 if (!foreign
&& other
== link
)
1424 if (!IN_SET(other
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
1427 HASHMAP_FOREACH(route
, other
->network
->routes_by_section
) {
1428 if (route
->family
== AF_INET
|| ordered_set_isempty(route
->nexthops
)) {
1429 r
= link_unmark_route(other
, route
, NULL
);
1435 ORDERED_SET_FOREACH(nh
, route
->nexthops
) {
1436 r
= link_unmark_route(other
, route
, nh
);
1444 /* Also unmark routes requested in .netdev file. */
1445 if (foreign
&& link
->netdev
&& link
->netdev
->kind
== NETDEV_KIND_WIREGUARD
) {
1446 Wireguard
*w
= WIREGUARD(link
->netdev
);
1448 SET_FOREACH(route
, w
->routes
) {
1449 r
= link_unmark_route(link
, route
, NULL
);
1458 int link_drop_routes(Link
*link
, bool foreign
) {
1463 assert(link
->manager
);
1465 r
= link_mark_routes(link
, foreign
);
1469 SET_FOREACH(route
, link
->manager
->routes
) {
1470 if (!route_is_marked(route
))
1473 RET_GATHER(r
, route_remove(route
, link
->manager
));
1479 int link_foreignize_routes(Link
*link
) {
1484 assert(link
->manager
);
1486 r
= link_mark_routes(link
, /* foreign = */ false);
1490 SET_FOREACH(route
, link
->manager
->routes
) {
1491 if (!route_is_marked(route
))
1494 route
->source
= NETWORK_CONFIG_SOURCE_FOREIGN
;
1500 int network_add_ipv4ll_route(Network
*network
) {
1501 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1502 unsigned section_line
;
1507 if (!network
->ipv4ll_route
)
1510 r
= hashmap_by_section_find_unused_line(network
->routes_by_section
, network
->filename
, §ion_line
);
1514 /* IPv4LLRoute= is in [Network] section. */
1515 r
= route_new_static(network
, network
->filename
, section_line
, &route
);
1519 r
= in_addr_from_string(AF_INET
, "169.254.0.0", &route
->dst
);
1523 route
->family
= AF_INET
;
1524 route
->dst_prefixlen
= 16;
1525 route
->scope
= RT_SCOPE_LINK
;
1526 route
->scope_set
= true;
1527 route
->table_set
= true;
1528 route
->priority
= IPV4LL_ROUTE_METRIC
;
1529 route
->protocol
= RTPROT_STATIC
;
1535 int network_add_default_route_on_device(Network
*network
) {
1536 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1537 unsigned section_line
;
1542 if (!network
->default_route_on_device
)
1545 r
= hashmap_by_section_find_unused_line(network
->routes_by_section
, network
->filename
, §ion_line
);
1549 /* DefaultRouteOnDevice= is in [Network] section. */
1550 r
= route_new_static(network
, network
->filename
, section_line
, &route
);
1554 route
->family
= AF_INET
;
1555 route
->scope
= RT_SCOPE_LINK
;
1556 route
->scope_set
= true;
1557 route
->protocol
= RTPROT_STATIC
;
1563 int config_parse_preferred_src(
1565 const char *filename
,
1567 const char *section
,
1568 unsigned section_line
,
1575 Network
*network
= userdata
;
1576 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1585 r
= route_new_static(network
, filename
, section_line
, &route
);
1589 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1590 "Failed to allocate route, ignoring assignment: %m");
1594 if (route
->family
== AF_UNSPEC
)
1595 r
= in_addr_from_string_auto(rvalue
, &route
->family
, &route
->prefsrc
);
1597 r
= in_addr_from_string(route
->family
, rvalue
, &route
->prefsrc
);
1599 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
1600 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
1608 int config_parse_destination(
1610 const char *filename
,
1612 const char *section
,
1613 unsigned section_line
,
1620 Network
*network
= userdata
;
1621 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1622 union in_addr_union
*buffer
;
1623 unsigned char *prefixlen
;
1632 r
= route_new_static(network
, filename
, section_line
, &route
);
1636 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1637 "Failed to allocate route, ignoring assignment: %m");
1641 if (streq(lvalue
, "Destination")) {
1642 buffer
= &route
->dst
;
1643 prefixlen
= &route
->dst_prefixlen
;
1644 } else if (streq(lvalue
, "Source")) {
1645 buffer
= &route
->src
;
1646 prefixlen
= &route
->src_prefixlen
;
1648 assert_not_reached();
1650 if (route
->family
== AF_UNSPEC
)
1651 r
= in_addr_prefix_from_string_auto(rvalue
, &route
->family
, buffer
, prefixlen
);
1653 r
= in_addr_prefix_from_string(rvalue
, route
->family
, buffer
, prefixlen
);
1655 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
1656 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
1660 (void) in_addr_mask(route
->family
, buffer
, *prefixlen
);
1666 int config_parse_route_priority(
1668 const char *filename
,
1670 const char *section
,
1671 unsigned section_line
,
1678 Network
*network
= userdata
;
1679 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1688 r
= route_new_static(network
, filename
, section_line
, &route
);
1692 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1693 "Failed to allocate route, ignoring assignment: %m");
1697 r
= safe_atou32(rvalue
, &route
->priority
);
1699 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1700 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue
);
1704 route
->priority_set
= true;
1709 int config_parse_route_scope(
1711 const char *filename
,
1713 const char *section
,
1714 unsigned section_line
,
1721 Network
*network
= userdata
;
1722 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1731 r
= route_new_static(network
, filename
, section_line
, &route
);
1735 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1736 "Failed to allocate route, ignoring assignment: %m");
1740 r
= route_scope_from_string(rvalue
);
1742 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Unknown route scope: %s", rvalue
);
1747 route
->scope_set
= true;
1752 int config_parse_route_table(
1754 const char *filename
,
1756 const char *section
,
1757 unsigned section_line
,
1764 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1765 Network
*network
= userdata
;
1774 r
= route_new_static(network
, filename
, section_line
, &route
);
1778 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1779 "Failed to allocate route, ignoring assignment: %m");
1783 r
= manager_get_route_table_from_string(network
->manager
, rvalue
, &route
->table
);
1785 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1786 "Could not parse route table \"%s\", ignoring assignment: %m", rvalue
);
1790 route
->table_set
= true;
1795 int config_parse_ipv6_route_preference(
1797 const char *filename
,
1799 const char *section
,
1800 unsigned section_line
,
1807 Network
*network
= userdata
;
1808 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1811 r
= route_new_static(network
, filename
, section_line
, &route
);
1815 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1816 "Failed to allocate route, ignoring assignment: %m");
1820 if (streq(rvalue
, "low"))
1821 route
->pref
= ICMPV6_ROUTER_PREF_LOW
;
1822 else if (streq(rvalue
, "medium"))
1823 route
->pref
= ICMPV6_ROUTER_PREF_MEDIUM
;
1824 else if (streq(rvalue
, "high"))
1825 route
->pref
= ICMPV6_ROUTER_PREF_HIGH
;
1827 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown route preference: %s", rvalue
);
1831 route
->pref_set
= true;
1836 int config_parse_route_protocol(
1838 const char *filename
,
1840 const char *section
,
1841 unsigned section_line
,
1848 Network
*network
= userdata
;
1849 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1852 r
= route_new_static(network
, filename
, section_line
, &route
);
1856 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1857 "Failed to allocate route, ignoring assignment: %m");
1861 r
= route_protocol_from_string(rvalue
);
1863 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1864 "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue
);
1868 route
->protocol
= r
;
1874 int config_parse_route_type(
1876 const char *filename
,
1878 const char *section
,
1879 unsigned section_line
,
1886 Network
*network
= userdata
;
1887 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1890 r
= route_new_static(network
, filename
, section_line
, &route
);
1894 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1895 "Failed to allocate route, ignoring assignment: %m");
1899 t
= route_type_from_string(rvalue
);
1901 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1902 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue
);
1906 route
->type
= (unsigned char) t
;
1912 int route_section_verify(Route
*route
) {
1916 assert(route
->section
);
1918 if (section_is_invalid(route
->section
))
1921 /* Currently, we do not support static route with finite lifetime. */
1922 assert(route
->lifetime_usec
== USEC_INFINITY
);
1924 r
= route_section_verify_nexthops(route
);
1929 if (!route
->table_set
&& route
->network
&& route
->network
->vrf
) {
1930 route
->table
= VRF(route
->network
->vrf
)->table
;
1931 route
->table_set
= true;
1934 if (!route
->table_set
&& IN_SET(route
->type
, RTN_LOCAL
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_NAT
))
1935 route
->table
= RT_TABLE_LOCAL
;
1938 if (!route
->scope_set
&& route
->family
== AF_INET
) {
1939 if (IN_SET(route
->type
, RTN_LOCAL
, RTN_NAT
))
1940 route
->scope
= RT_SCOPE_HOST
;
1941 else if (IN_SET(route
->type
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_MULTICAST
))
1942 route
->scope
= RT_SCOPE_LINK
;
1943 else if (IN_SET(route
->type
, RTN_UNICAST
, RTN_UNSPEC
) &&
1944 !route
->gateway_from_dhcp_or_ra
&&
1945 !in_addr_is_set(route
->nexthop
.family
, &route
->nexthop
.gw
) &&
1946 ordered_set_isempty(route
->nexthops
) &&
1947 route
->nexthop_id
== 0)
1948 route
->scope
= RT_SCOPE_LINK
;
1952 if (route
->family
== AF_INET6
) {
1953 if (route
->scope
!= RT_SCOPE_UNIVERSE
) {
1954 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route
->section
->filename
);
1955 route
->scope
= RT_SCOPE_UNIVERSE
;
1958 if (route
->priority
== 0)
1959 route
->priority
= IP6_RT_PRIO_USER
;
1965 void network_drop_invalid_routes(Network
*network
) {
1970 HASHMAP_FOREACH(route
, network
->routes_by_section
)
1971 if (route_section_verify(route
) < 0)
1972 route_detach(route
);