1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/ipv6_route.h>
7 #include "sd-ndisc-protocol.h"
8 #include "sd-netlink.h"
10 #include "alloc-util.h"
11 #include "conf-parser.h"
12 #include "errno-util.h"
13 #include "event-util.h"
14 #include "netlink-util.h"
15 #include "networkd-address.h"
16 #include "networkd-ipv4ll.h"
17 #include "networkd-link.h"
18 #include "networkd-manager.h"
19 #include "networkd-network.h"
20 #include "networkd-nexthop.h"
21 #include "networkd-queue.h"
22 #include "networkd-route.h"
23 #include "networkd-route-util.h"
24 #include "ordered-set.h"
25 #include "parse-util.h"
27 #include "siphash24.h"
28 #include "string-util.h"
30 #include "wireguard.h"
32 static Route
* route_detach_impl(Route
*route
) {
34 assert(!!route
->network
+ !!route
->manager
+ !!route
->wireguard
<= 1);
37 assert(route
->section
);
38 hashmap_remove(route
->network
->routes_by_section
, route
->section
);
39 route
->network
= NULL
;
44 route_detach_from_nexthop(route
);
45 set_remove(route
->manager
->routes
, route
);
46 route
->manager
= NULL
;
50 if (route
->wireguard
) {
51 set_remove(route
->wireguard
->routes
, route
);
52 route
->wireguard
= NULL
;
59 void route_detach(Route
*route
) {
60 route_unref(route_detach_impl(route
));
63 static Route
* route_free(Route
*route
) {
67 route_detach_impl(route
);
69 config_section_free(route
->section
);
70 route_nexthops_done(route
);
71 route_metric_done(&route
->metric
);
72 sd_event_source_disable_unref(route
->expire
);
77 DEFINE_TRIVIAL_REF_UNREF_FUNC(Route
, route
, route_free
);
79 static void route_hash_func(const Route
*route
, struct siphash
*state
) {
82 siphash24_compress_typesafe(route
->family
, state
);
84 switch (route
->family
) {
86 /* First, the table, destination prefix, priority, and tos (dscp), are used to find routes.
87 * See fib_table_insert(), fib_find_node(), and fib_find_alias() in net/ipv4/fib_trie.c of the kernel. */
88 siphash24_compress_typesafe(route
->table
, state
);
89 in_addr_hash_func(&route
->dst
, route
->family
, state
);
90 siphash24_compress_typesafe(route
->dst_prefixlen
, state
);
91 siphash24_compress_typesafe(route
->priority
, state
);
92 siphash24_compress_typesafe(route
->tos
, state
);
94 /* Then, protocol, scope, type, flags, prefsrc, metrics (RTAX_* attributes), and nexthops (gateways)
95 * are used to find routes. See fib_find_info() in net/ipv4/fib_semantics.c of the kernel. */
96 siphash24_compress_typesafe(route
->protocol
, state
);
97 siphash24_compress_typesafe(route
->scope
, state
);
98 siphash24_compress_typesafe(route
->type
, state
);
99 unsigned flags
= route
->flags
& ~RTNH_COMPARE_MASK
;
100 siphash24_compress_typesafe(flags
, state
);
101 in_addr_hash_func(&route
->prefsrc
, route
->family
, state
);
103 /* nexthops (id, number of nexthops, nexthop) */
104 route_nexthops_hash_func(route
, state
);
107 route_metric_hash_func(&route
->metric
, state
);
111 /* First, table and destination prefix are used for classifying routes.
112 * See fib6_add() and fib6_add_1() in net/ipv6/ip6_fib.c of the kernel. */
113 siphash24_compress_typesafe(route
->table
, state
);
114 in_addr_hash_func(&route
->dst
, route
->family
, state
);
115 siphash24_compress_typesafe(route
->dst_prefixlen
, state
);
117 /* Then, source prefix is used. See fib6_add(). */
118 in_addr_hash_func(&route
->src
, route
->family
, state
);
119 siphash24_compress_typesafe(route
->src_prefixlen
, state
);
121 /* See fib6_add_rt2node(). */
122 siphash24_compress_typesafe(route
->priority
, state
);
124 /* See rt6_duplicate_nexthop() in include/net/ip6_route.h of the kernel.
125 * Here, we hash nexthop in a similar way as the one for IPv4. */
126 route_nexthops_hash_func(route
, state
);
128 /* Unlike IPv4 routes, metrics are not taken into account. */
132 assert_not_reached();
136 static int route_compare_func(const Route
*a
, const Route
*b
) {
139 r
= CMP(a
->family
, b
->family
);
145 r
= CMP(a
->table
, b
->table
);
149 r
= memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
153 r
= CMP(a
->dst_prefixlen
, b
->dst_prefixlen
);
157 r
= CMP(a
->priority
, b
->priority
);
161 r
= CMP(a
->tos
, b
->tos
);
165 r
= CMP(a
->protocol
, b
->protocol
);
169 r
= CMP(a
->scope
, b
->scope
);
173 r
= CMP(a
->type
, b
->type
);
177 r
= CMP(a
->flags
& ~RTNH_COMPARE_MASK
, b
->flags
& ~RTNH_COMPARE_MASK
);
181 r
= memcmp(&a
->prefsrc
, &b
->prefsrc
, FAMILY_ADDRESS_SIZE(a
->family
));
185 r
= route_nexthops_compare_func(a
, b
);
189 return route_metric_compare_func(&a
->metric
, &b
->metric
);
192 r
= CMP(a
->table
, b
->table
);
196 r
= memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
200 r
= CMP(a
->dst_prefixlen
, b
->dst_prefixlen
);
204 r
= memcmp(&a
->src
, &b
->src
, FAMILY_ADDRESS_SIZE(a
->family
));
208 r
= CMP(a
->src_prefixlen
, b
->src_prefixlen
);
212 r
= CMP(a
->priority
, b
->priority
);
216 return route_nexthops_compare_func(a
, b
);
219 assert_not_reached();
223 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
230 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
231 route_hash_ops_unref
,
237 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
238 route_section_hash_ops
,
240 config_section_hash_func
,
241 config_section_compare_func
,
245 int route_new(Route
**ret
) {
246 _cleanup_(route_unrefp
) Route
*route
= NULL
;
248 route
= new(Route
, 1);
255 .scope
= RT_SCOPE_UNIVERSE
,
256 .protocol
= RTPROT_UNSPEC
,
258 .table
= RT_TABLE_MAIN
,
259 .lifetime_usec
= USEC_INFINITY
,
260 .gateway_onlink
= -1,
263 *ret
= TAKE_PTR(route
);
268 int route_new_static(Network
*network
, const char *filename
, unsigned section_line
, Route
**ret
) {
269 _cleanup_(config_section_freep
) ConfigSection
*n
= NULL
;
270 _cleanup_(route_unrefp
) Route
*route
= NULL
;
276 assert(section_line
> 0);
278 r
= config_section_new(filename
, section_line
, &n
);
282 route
= hashmap_get(network
->routes_by_section
, n
);
284 *ret
= TAKE_PTR(route
);
288 if (hashmap_size(network
->routes_by_section
) >= routes_max())
291 r
= route_new(&route
);
295 route
->protocol
= RTPROT_STATIC
;
296 route
->network
= network
;
297 route
->section
= TAKE_PTR(n
);
298 route
->source
= NETWORK_CONFIG_SOURCE_STATIC
;
300 r
= hashmap_ensure_put(&network
->routes_by_section
, &route_section_hash_ops
, route
->section
, route
);
304 *ret
= TAKE_PTR(route
);
308 static int route_attach(Manager
*manager
, Route
*route
) {
313 assert(!route
->network
);
314 assert(!route
->wireguard
);
316 r
= set_ensure_put(&manager
->routes
, &route_hash_ops
, route
);
322 route
->manager
= manager
;
326 int route_get(Manager
*manager
, const Route
*route
, Route
**ret
) {
332 existing
= set_get(manager
->routes
, route
);
342 static int route_get_link(Manager
*manager
, const Route
*route
, Link
**ret
) {
348 if (route
->nexthop_id
!= 0) {
351 r
= nexthop_get_by_id(manager
, route
->nexthop_id
, &nh
);
355 return link_get_by_index(manager
, nh
->ifindex
, ret
);
358 return route_nexthop_get_link(manager
, &route
->nexthop
, ret
);
361 bool route_is_bound_to_link(const Route
*route
, Link
*link
) {
364 assert(link
->manager
);
367 if (route_get_link(link
->manager
, route
, &route_link
) < 0)
370 return route_link
->ifindex
== link
->ifindex
;
373 int route_get_request(Manager
*manager
, const Route
*route
, Request
**ret
) {
379 req
= ordered_set_get(manager
->request_queue
,
381 .type
= REQUEST_TYPE_ROUTE
,
382 .userdata
= (void*) route
,
383 .hash_func
= (hash_func_t
) route_hash_func
,
384 .compare_func
= (compare_func_t
) route_compare_func
,
394 int route_dup(const Route
*src
, const RouteNextHop
*nh
, Route
**ret
) {
395 _cleanup_(route_unrefp
) Route
*dest
= NULL
;
401 dest
= newdup(Route
, src
, 1);
405 /* Unset number of reference and all pointers */
407 dest
->manager
= NULL
;
408 dest
->network
= NULL
;
409 dest
->wireguard
= NULL
;
410 dest
->section
= NULL
;
411 dest
->nexthop
= ROUTE_NEXTHOP_NULL
;
412 dest
->nexthops
= NULL
;
413 dest
->metric
= ROUTE_METRIC_NULL
;
416 r
= route_nexthops_copy(src
, nh
, dest
);
420 r
= route_metric_copy(&src
->metric
, &dest
->metric
);
424 *ret
= TAKE_PTR(dest
);
428 static int route_to_string(const Route
*route
, Manager
*manager
, char **ret
) {
429 _cleanup_free_
char *nexthop
= NULL
, *prefsrc
= NULL
,
430 *table
= NULL
, *scope
= NULL
, *proto
= NULL
, *flags
= NULL
;
431 const char *dst
, *src
;
437 dst
= in_addr_is_set(route
->family
, &route
->dst
) || route
->dst_prefixlen
> 0 ?
438 IN_ADDR_PREFIX_TO_STRING(route
->family
, &route
->dst
, route
->dst_prefixlen
) : NULL
;
439 src
= in_addr_is_set(route
->family
, &route
->src
) || route
->src_prefixlen
> 0 ?
440 IN_ADDR_PREFIX_TO_STRING(route
->family
, &route
->src
, route
->src_prefixlen
) : NULL
;
442 (void) route_nexthops_to_string(route
, &nexthop
);
444 if (in_addr_is_set(route
->family
, &route
->prefsrc
))
445 (void) in_addr_to_string(route
->family
, &route
->prefsrc
, &prefsrc
);
446 (void) route_scope_to_string_alloc(route
->scope
, &scope
);
447 (void) manager_get_route_table_to_string(manager
, route
->table
, /* append_num = */ true, &table
);
448 (void) route_protocol_full_to_string_alloc(route
->protocol
, &proto
);
449 (void) route_flags_to_string_alloc(route
->flags
, &flags
);
452 "dst: %s, src: %s, %s, prefsrc: %s, "
453 "table: %s, priority: %"PRIu32
", "
454 "proto: %s, scope: %s, "
455 "type: %s, flags: %s",
456 strna(dst
), strna(src
), strna(nexthop
), strna(prefsrc
),
457 strna(table
), route
->priority
,
458 strna(proto
), strna(scope
),
459 strna(route_type_to_string(route
->type
)), strna(flags
)) < 0)
465 void log_route_debug(const Route
*route
, const char *str
, Manager
*manager
) {
466 _cleanup_free_
char *state
= NULL
, *route_str
= NULL
;
476 (void) route_get_link(manager
, route
, &link
);
477 (void) network_config_state_to_string_alloc(route
->state
, &state
);
478 (void) route_to_string(route
, manager
, &route_str
);
480 log_link_debug(link
, "%s %s route (%s): %s",
481 str
, strna(network_config_source_to_string(route
->source
)), strna(state
), strna(route_str
));
484 static void route_forget(Manager
*manager
, Route
*route
, const char *msg
) {
490 if (route_get_request(manager
, route
, &req
) >= 0)
491 route_enter_removed(req
->userdata
);
493 if (!route
->manager
&& route_get(manager
, route
, &route
) < 0)
496 route_enter_removed(route
);
497 log_route_debug(route
, msg
, manager
);
501 static int route_set_netlink_message(const Route
*route
, sd_netlink_message
*m
) {
507 /* rtmsg header (and relevant attributes) */
508 if (route
->dst_prefixlen
> 0) {
509 r
= netlink_message_append_in_addr_union(m
, RTA_DST
, route
->family
, &route
->dst
);
513 r
= sd_rtnl_message_route_set_dst_prefixlen(m
, route
->dst_prefixlen
);
518 if (route
->src_prefixlen
> 0) {
519 r
= netlink_message_append_in_addr_union(m
, RTA_SRC
, route
->family
, &route
->src
);
523 r
= sd_rtnl_message_route_set_src_prefixlen(m
, route
->src_prefixlen
);
528 r
= sd_rtnl_message_route_set_tos(m
, route
->tos
);
532 r
= sd_rtnl_message_route_set_scope(m
, route
->scope
);
536 r
= sd_rtnl_message_route_set_type(m
, route
->type
);
540 r
= sd_rtnl_message_route_set_flags(m
, route
->flags
& ~RTNH_COMPARE_MASK
);
545 r
= sd_netlink_message_append_u32(m
, RTA_PRIORITY
, route
->priority
);
549 if (in_addr_is_set(route
->family
, &route
->prefsrc
)) {
550 r
= netlink_message_append_in_addr_union(m
, RTA_PREFSRC
, route
->family
, &route
->prefsrc
);
555 if (route
->table
< 256) {
556 r
= sd_rtnl_message_route_set_table(m
, route
->table
);
560 r
= sd_rtnl_message_route_set_table(m
, RT_TABLE_UNSPEC
);
564 /* Table attribute to allow more than 256. */
565 r
= sd_netlink_message_append_u32(m
, RTA_TABLE
, route
->table
);
570 r
= sd_netlink_message_append_u8(m
, RTA_PREF
, route
->pref
);
575 r
= route_nexthops_set_netlink_message(route
, m
);
580 r
= route_metric_set_netlink_message(&route
->metric
, m
);
587 static int route_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, RemoveRequest
*rreq
) {
593 Manager
*manager
= ASSERT_PTR(rreq
->manager
);
594 Route
*route
= ASSERT_PTR(rreq
->userdata
);
596 r
= sd_netlink_message_get_errno(m
);
598 log_message_full_errno(m
,
599 (r
== -ESRCH
|| /* the route is already removed? */
600 (r
== -EINVAL
&& route
->nexthop_id
!= 0) || /* The nexthop is already removed? */
601 !route
->manager
) ? /* already detached? */
602 LOG_DEBUG
: LOG_WARNING
,
603 r
, "Could not drop route, ignoring");
605 /* If the route cannot be removed, then assume the route is already removed. */
606 route_forget(manager
, route
, "Forgetting");
612 int route_remove(Route
*route
, Manager
*manager
) {
613 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
620 if (manager
->state
== MANAGER_STOPPED
)
621 return 0; /* The remove request will not be queued anyway. Suppress logging below. */
623 /* If the route is remembered, then use the remembered object. */
624 (void) route_get(manager
, route
, &route
);
626 log_route_debug(route
, "Removing", manager
);
629 (void) route_get_link(manager
, route
, &link
);
631 r
= sd_rtnl_message_new_route(manager
->rtnl
, &m
, RTM_DELROUTE
, route
->family
, route
->protocol
);
633 return log_link_warning_errno(link
, r
, "Could not create netlink message: %m");
635 r
= route_set_netlink_message(route
, m
);
637 return log_link_warning_errno(link
, r
, "Could not fill netlink message: %m");
639 r
= manager_remove_request_add(manager
, route
, route
, manager
->rtnl
, m
, route_remove_handler
);
641 return log_link_warning_errno(link
, r
, "Could not queue rtnetlink message: %m");
643 route_enter_removing(route
);
647 int route_remove_and_cancel(Route
*route
, Manager
*manager
) {
648 _cleanup_(request_unrefp
) Request
*req
= NULL
;
649 bool waiting
= false;
654 /* If the route is remembered by the manager, then use the remembered object. */
655 (void) route_get(manager
, route
, &route
);
657 /* Cancel the request for the route. If the request is already called but we have not received the
658 * notification about the request, then explicitly remove the route. */
659 if (route_get_request(manager
, route
, &req
) >= 0) {
660 request_ref(req
); /* avoid the request freed by request_detach() */
661 waiting
= req
->waiting_reply
;
663 route_cancel_requesting(route
);
666 /* If we know that the route will come or already exists, remove it. */
667 if (waiting
|| (route
->manager
&& route_exists(route
)))
668 return route_remove(route
, manager
);
673 static int route_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
674 Route
*route
= ASSERT_PTR(userdata
);
678 return 0; /* already detached. */
680 r
= route_remove(route
, route
->manager
);
683 (void) route_get_link(route
->manager
, route
, &link
);
684 log_link_warning_errno(link
, r
, "Could not remove route: %m");
686 link_enter_failed(link
);
692 static int route_setup_timer(Route
*route
, const struct rta_cacheinfo
*cacheinfo
) {
697 if (cacheinfo
&& cacheinfo
->rta_expires
!= 0)
698 route
->expiration_managed_by_kernel
= true;
700 if (route
->lifetime_usec
== USEC_INFINITY
|| /* We do not request expiration for the route. */
701 route
->expiration_managed_by_kernel
) { /* We have received nonzero expiration previously. The expiration is managed by the kernel. */
702 route
->expire
= sd_event_source_disable_unref(route
->expire
);
706 Manager
*manager
= ASSERT_PTR(route
->manager
);
707 r
= event_reset_time(manager
->event
, &route
->expire
, CLOCK_BOOTTIME
,
708 route
->lifetime_usec
, 0, route_expire_handler
, route
, 0, "route-expiration", true);
711 (void) route_get_link(manager
, route
, &link
);
712 return log_link_warning_errno(link
, r
, "Failed to configure expiration timer for route, ignoring: %m");
715 log_route_debug(route
, "Configured expiration timer for", manager
);
719 static int route_update_by_request(Route
*route
, Request
*req
) {
723 Route
*rt
= ASSERT_PTR(req
->userdata
);
725 route
->provider
= rt
->provider
;
726 route
->source
= rt
->source
;
727 route
->lifetime_usec
= rt
->lifetime_usec
;
732 static int route_update_on_existing_one(Request
*req
, Route
*requested
) {
733 Manager
*manager
= ASSERT_PTR(ASSERT_PTR(req
)->manager
);
739 if (route_get(manager
, requested
, &existing
) < 0)
742 r
= route_update_by_request(existing
, req
);
746 r
= route_setup_timer(existing
, NULL
);
750 /* This may be a bug in the kernel, but the MTU of an IPv6 route can be updated only when the
751 * route has an expiration timer managed by the kernel (not by us). See fib6_add_rt2node() in
752 * net/ipv6/ip6_fib.c of the kernel. */
753 if (existing
->family
== AF_INET6
&&
754 existing
->expiration_managed_by_kernel
) {
755 r
= route_metric_set(&existing
->metric
, RTAX_MTU
, route_metric_get(&requested
->metric
, RTAX_MTU
));
760 route_enter_configured(existing
);
764 static int route_update_on_existing(Request
*req
) {
765 Route
*rt
= ASSERT_PTR(ASSERT_PTR(req
)->userdata
);
769 /* Already detached? At least there are two possibilities then.
770 * 1) The interface is removed, and all queued requests for the interface are cancelled.
771 * 2) networkd is now stopping, hence all queued requests are cancelled.
772 * Anyway, we can ignore the request, and there is nothing we can do. */
775 if (rt
->family
== AF_INET
|| ordered_set_isempty(rt
->nexthops
))
776 return route_update_on_existing_one(req
, rt
);
779 ORDERED_SET_FOREACH(nh
, rt
->nexthops
) {
780 _cleanup_(route_unrefp
) Route
*dup
= NULL
;
782 r
= route_dup(rt
, nh
, &dup
);
786 r
= route_update_on_existing_one(req
, dup
);
794 int route_configure_handler_internal(sd_netlink_message
*m
, Request
*req
, Route
*route
) {
801 Link
*link
= ASSERT_PTR(req
->link
);
803 r
= sd_netlink_message_get_errno(m
);
805 /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE notification, so
806 * here we need to update the state, provider, source, timer, and so on. */
807 r
= route_update_on_existing(req
);
809 log_link_warning_errno(link
, r
, "Failed to update existing route: %m");
810 link_enter_failed(link
);
817 _cleanup_free_
char *str
= NULL
;
818 (void) route_to_string(route
, link
->manager
, &str
);
819 log_link_message_warning_errno(link
, m
, r
, "Failed to configure %s route (%s)",
820 network_config_source_to_string(route
->source
), strna(str
));
821 link_enter_failed(link
);
828 static int route_configure(const Route
*route
, uint32_t lifetime_sec
, Link
*link
, Request
*req
) {
829 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
834 assert(link
->manager
);
837 log_route_debug(route
, "Configuring", link
->manager
);
839 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &m
, RTM_NEWROUTE
, route
->family
, route
->protocol
);
843 r
= route_set_netlink_message(route
, m
);
847 if (lifetime_sec
!= UINT32_MAX
) {
848 r
= sd_netlink_message_append_u32(m
, RTA_EXPIRES
, lifetime_sec
);
853 return request_call_netlink_async(link
->manager
->rtnl
, m
, req
);
856 static int route_requeue_request(Request
*req
, Link
*link
, const Route
*route
) {
857 _unused_
_cleanup_(request_unrefp
) Request
*req_unref
= NULL
;
858 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
863 assert(link
->manager
);
866 /* It is not possible to adjust the Route object owned by Request, as it is used as a key to manage
867 * Request objects in the queue. Hence, we need to re-request with the updated Route object. */
869 if (!route_nexthops_needs_adjust(route
))
870 return 0; /* The Route object does not need the adjustment. Continue with it. */
872 r
= route_dup(route
, NULL
, &tmp
);
876 r
= route_adjust_nexthops(tmp
, link
);
880 if (route_compare_func(route
, tmp
) == 0 && route
->type
== tmp
->type
)
881 return 0; /* No effective change?? That's OK. */
883 /* Avoid the request to be freed by request_detach(). */
884 req_unref
= request_ref(req
);
886 /* Detach the request from the queue, to make not the new request is deduped.
887 * Why this is necessary? IPv6 routes with different type may be handled as the same,
888 * As commented in route_adjust_nexthops(), we need to configure the adjusted type,
889 * otherwise we cannot remove the route on reconfigure or so. If we request the new Route object
890 * without detaching the current request, the new request is deduped, and the route is configured
891 * with unmodified type. */
894 /* Request the route with the adjusted Route object combined with the same other parameters. */
895 r
= link_requeue_request(link
, req
, tmp
, NULL
);
899 return 1; /* Already queued?? That's OK. Maybe, [Route] section is effectively duplicated. */
902 return 1; /* New request is queued. Finish to process this request. */
905 static int route_is_ready_to_configure(const Route
*route
, Link
*link
) {
909 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
912 if (in_addr_is_set(route
->family
, &route
->prefsrc
) > 0) {
915 if (manager_get_address(link
->manager
, route
->family
, &route
->prefsrc
, &a
) < 0)
918 if (!address_is_ready(a
))
922 return route_nexthops_is_ready_to_configure(route
, link
->manager
);
925 static int route_process_request(Request
*req
, Link
*link
, Route
*route
) {
931 assert(link
->manager
);
934 r
= route_is_ready_to_configure(route
, link
);
936 return log_link_warning_errno(link
, r
, "Failed to check if route is ready to configure: %m");
941 assert_se(sd_event_now(link
->manager
->event
, CLOCK_BOOTTIME
, &now_usec
) >= 0);
942 uint32_t sec
= usec_to_sec(route
->lifetime_usec
, now_usec
);
944 log_link_debug(link
, "Refuse to configure %s route with zero lifetime.",
945 network_config_source_to_string(route
->source
));
947 route_cancel_requesting(route
);
948 if (route_get(link
->manager
, route
, &existing
) >= 0)
949 route_cancel_requesting(existing
);
953 r
= route_requeue_request(req
, link
, route
);
957 r
= route_configure(route
, sec
, link
, req
);
959 return log_link_warning_errno(link
, r
, "Failed to configure route: %m");
961 route_enter_configuring(route
);
962 if (route_get(link
->manager
, route
, &existing
) >= 0)
963 route_enter_configuring(existing
);
967 static int link_request_route_one(
970 const RouteNextHop
*nh
,
971 unsigned *message_counter
,
972 route_netlink_handler_t netlink_handler
) {
974 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
975 Route
*existing
= NULL
;
979 assert(link
->manager
);
982 r
= route_dup(route
, nh
, &tmp
);
986 r
= route_adjust_nexthops(tmp
, link
);
990 if (route_get(link
->manager
, tmp
, &existing
) >= 0)
991 /* Copy state for logging below. */
992 tmp
->state
= existing
->state
;
994 log_route_debug(tmp
, "Requesting", link
->manager
);
995 r
= link_queue_request_safe(link
, REQUEST_TYPE_ROUTE
,
1000 route_process_request
,
1007 route_enter_requesting(tmp
);
1009 route_enter_requesting(existing
);
1015 int link_request_route(
1018 unsigned *message_counter
,
1019 route_netlink_handler_t netlink_handler
) {
1024 assert(link
->manager
);
1026 assert(route
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
);
1028 if (route
->family
== AF_INET
|| route_is_reject(route
) || ordered_set_isempty(route
->nexthops
))
1029 return link_request_route_one(link
, route
, NULL
, message_counter
, netlink_handler
);
1032 ORDERED_SET_FOREACH(nh
, route
->nexthops
) {
1033 r
= link_request_route_one(link
, route
, nh
, message_counter
, netlink_handler
);
1041 static int static_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
1048 r
= route_configure_handler_internal(m
, req
, route
);
1052 if (link
->static_route_messages
== 0) {
1053 log_link_debug(link
, "Routes set");
1054 link
->static_routes_configured
= true;
1055 link_check_ready(link
);
1061 static int link_request_wireguard_routes(Link
*link
, bool only_ipv4
) {
1067 if (!link
->netdev
|| link
->netdev
->kind
!= NETDEV_KIND_WIREGUARD
)
1070 Wireguard
*w
= WIREGUARD(link
->netdev
);
1072 SET_FOREACH(route
, w
->routes
) {
1073 if (only_ipv4
&& route
->family
!= AF_INET
)
1076 r
= link_request_route(link
, route
, &link
->static_route_messages
, static_route_handler
);
1084 int link_request_static_routes(Link
*link
, bool only_ipv4
) {
1089 assert(link
->network
);
1091 link
->static_routes_configured
= false;
1093 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
1094 if (route
->source
!= NETWORK_CONFIG_SOURCE_STATIC
)
1097 if (only_ipv4
&& route
->family
!= AF_INET
)
1100 r
= link_request_route(link
, route
, &link
->static_route_messages
, static_route_handler
);
1105 r
= link_request_wireguard_routes(link
, only_ipv4
);
1109 if (link
->static_route_messages
== 0) {
1110 link
->static_routes_configured
= true;
1111 link_check_ready(link
);
1113 log_link_debug(link
, "Requesting routes");
1114 link_set_state(link
, LINK_STATE_CONFIGURING
);
1120 static int process_route_one(
1124 const struct rta_cacheinfo
*cacheinfo
) {
1126 Route
*route
= NULL
;
1128 bool is_new
= false, update_dhcp4
;
1133 assert(IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
));
1135 (void) route_get(manager
, tmp
, &route
);
1136 (void) route_get_link(manager
, tmp
, &link
);
1138 update_dhcp4
= link
&& tmp
->family
== AF_INET6
&& tmp
->dst_prefixlen
== 0;
1141 case RTM_NEWROUTE
: {
1142 Request
*req
= NULL
;
1143 (void) route_get_request(manager
, tmp
, &req
);
1146 if (!manager
->manage_foreign_routes
&& !(req
&& req
->waiting_reply
)) {
1147 route_enter_configured(tmp
);
1148 log_route_debug(tmp
, "Ignoring received", manager
);
1152 /* If we do not know the route, then save it. */
1153 r
= route_attach(manager
, tmp
);
1155 log_link_warning_errno(link
, r
, "Failed to remember foreign route, ignoring: %m");
1159 route
= route_ref(tmp
);
1163 /* Update remembered route with the received notification. */
1165 /* Here, update weight only when a non-zero weight is received. As the kernel does
1166 * not provide the weight of a single-path route. In such case, tmp->nexthop.weight
1167 * is zero, hence we should not overwrite the known weight of the route. */
1168 if (tmp
->nexthop
.weight
!= 0)
1169 route
->nexthop
.weight
= tmp
->nexthop
.weight
;
1172 /* Also update information that cannot be obtained through netlink notification. */
1173 if (req
&& req
->waiting_reply
) {
1174 r
= route_update_by_request(route
, req
);
1176 log_link_warning_errno(link
, r
, "Failed to update route by request: %m");
1177 link_enter_failed(link
);
1181 /* We configure IPv6 multipath route separately. When the first path is configured,
1182 * the kernel does not provide the weight of the path. So, we need to adjust it here.
1183 * Hopefully, the weight is assigned correctly. */
1184 if (route
->nexthop
.weight
== 0) {
1185 Route
*rt
= ASSERT_PTR(req
->userdata
);
1186 route
->nexthop
.weight
= rt
->nexthop
.weight
;
1190 route_attach_to_nexthop(route
);
1192 route_enter_configured(route
);
1193 log_route_debug(route
, is_new
? "Received new" : "Received remembered", manager
);
1195 (void) route_setup_timer(route
, cacheinfo
);
1201 route_forget(manager
, route
, "Forgetting removed");
1203 log_route_debug(tmp
,
1204 manager
->manage_foreign_routes
? "Kernel removed unknown" : "Ignoring received",
1209 assert_not_reached();
1213 r
= dhcp4_update_ipv6_connectivity(link
);
1215 log_link_warning_errno(link
, r
, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");
1216 link_enter_failed(link
);
1223 int manager_rtnl_process_route(sd_netlink
*rtnl
, sd_netlink_message
*message
, Manager
*m
) {
1224 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
1231 if (sd_netlink_message_is_error(message
)) {
1232 r
= sd_netlink_message_get_errno(message
);
1234 log_message_warning_errno(message
, r
, "rtnl: failed to receive route message, ignoring");
1240 r
= sd_netlink_message_get_type(message
, &type
);
1242 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
1244 } else if (!IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
)) {
1245 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type
);
1249 r
= route_new(&tmp
);
1254 r
= sd_rtnl_message_route_get_family(message
, &tmp
->family
);
1256 log_warning_errno(r
, "rtnl: received route message without family, ignoring: %m");
1258 } else if (!IN_SET(tmp
->family
, AF_INET
, AF_INET6
)) {
1259 log_debug("rtnl: received route message with invalid family '%i', ignoring.", tmp
->family
);
1263 r
= sd_rtnl_message_route_get_dst_prefixlen(message
, &tmp
->dst_prefixlen
);
1265 log_warning_errno(r
, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1269 r
= sd_rtnl_message_route_get_src_prefixlen(message
, &tmp
->src_prefixlen
);
1271 log_warning_errno(r
, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1275 r
= sd_rtnl_message_route_get_tos(message
, &tmp
->tos
);
1277 log_warning_errno(r
, "rtnl: received route message with invalid tos, ignoring: %m");
1281 r
= sd_rtnl_message_route_get_protocol(message
, &tmp
->protocol
);
1283 log_warning_errno(r
, "rtnl: received route message without route protocol, ignoring: %m");
1287 r
= sd_rtnl_message_route_get_scope(message
, &tmp
->scope
);
1289 log_warning_errno(r
, "rtnl: received route message with invalid scope, ignoring: %m");
1293 r
= sd_rtnl_message_route_get_type(message
, &tmp
->type
);
1295 log_warning_errno(r
, "rtnl: received route message with invalid type, ignoring: %m");
1299 r
= sd_rtnl_message_route_get_flags(message
, &tmp
->flags
);
1301 log_warning_errno(r
, "rtnl: received route message without route flags, ignoring: %m");
1306 r
= netlink_message_read_in_addr_union(message
, RTA_DST
, tmp
->family
, &tmp
->dst
);
1307 if (r
< 0 && r
!= -ENODATA
) {
1308 log_warning_errno(r
, "rtnl: received route message without valid destination, ignoring: %m");
1312 r
= netlink_message_read_in_addr_union(message
, RTA_SRC
, tmp
->family
, &tmp
->src
);
1313 if (r
< 0 && r
!= -ENODATA
) {
1314 log_warning_errno(r
, "rtnl: received route message without valid source, ignoring: %m");
1318 r
= sd_netlink_message_read_u32(message
, RTA_PRIORITY
, &tmp
->priority
);
1319 if (r
< 0 && r
!= -ENODATA
) {
1320 log_warning_errno(r
, "rtnl: received route message with invalid priority, ignoring: %m");
1324 r
= netlink_message_read_in_addr_union(message
, RTA_PREFSRC
, tmp
->family
, &tmp
->prefsrc
);
1325 if (r
< 0 && r
!= -ENODATA
) {
1326 log_warning_errno(r
, "rtnl: received route message without valid preferred source, ignoring: %m");
1330 r
= sd_netlink_message_read_u32(message
, RTA_TABLE
, &tmp
->table
);
1331 if (r
== -ENODATA
) {
1332 unsigned char table
;
1334 r
= sd_rtnl_message_route_get_table(message
, &table
);
1339 log_warning_errno(r
, "rtnl: received route message with invalid table, ignoring: %m");
1343 r
= sd_netlink_message_read_u8(message
, RTA_PREF
, &tmp
->pref
);
1344 if (r
< 0 && r
!= -ENODATA
) {
1345 log_warning_errno(r
, "rtnl: received route message with invalid preference, ignoring: %m");
1350 if (route_nexthops_read_netlink_message(tmp
, message
) < 0)
1354 if (route_metric_read_netlink_message(&tmp
->metric
, message
) < 0)
1358 struct rta_cacheinfo cacheinfo
;
1359 r
= sd_netlink_message_read(message
, RTA_CACHEINFO
, sizeof(cacheinfo
), &cacheinfo
);
1360 if (r
< 0 && r
!= -ENODATA
) {
1361 log_warning_errno(r
, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1364 has_cacheinfo
= r
>= 0;
1366 if (tmp
->family
== AF_INET
|| ordered_set_isempty(tmp
->nexthops
))
1367 return process_route_one(m
, type
, tmp
, has_cacheinfo
? &cacheinfo
: NULL
);
1370 ORDERED_SET_FOREACH(nh
, tmp
->nexthops
) {
1371 _cleanup_(route_unrefp
) Route
*dup
= NULL
;
1373 r
= route_dup(tmp
, nh
, &dup
);
1377 r
= process_route_one(m
, type
, dup
, has_cacheinfo
? &cacheinfo
: NULL
);
1385 void manager_mark_routes(Manager
*manager
, Link
*link
, NetworkConfigSource source
) {
1390 SET_FOREACH(route
, manager
->routes
) {
1391 if (route
->source
!= source
)
1397 if (route_get_link(manager
, route
, &route_link
) < 0)
1399 if (route_link
!= link
)
1407 static bool route_by_kernel(const Route
*route
) {
1410 if (route
->protocol
== RTPROT_KERNEL
)
1413 /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
1414 * multicast with RTPROT_BOOT. Do not touch it. */
1415 if (route
->protocol
== RTPROT_BOOT
&&
1416 route
->family
== AF_INET6
&&
1417 route
->dst_prefixlen
== 8 &&
1418 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 }}}))
1424 bool route_can_update(Manager
*manager
, const Route
*existing
, const Route
*requesting
) {
1431 if (route_compare_func(existing
, requesting
) != 0) {
1432 log_route_debug(existing
, "Cannot update route, as the existing route is different", manager
);
1436 switch (existing
->family
) {
1438 if (existing
->nexthop
.weight
!= requesting
->nexthop
.weight
) {
1439 log_debug("Cannot update route: existing weight: %u, requesting weight: %u",
1440 existing
->nexthop
.weight
, requesting
->nexthop
.weight
);
1446 if (existing
->protocol
!= requesting
->protocol
) {
1447 if (DEBUG_LOGGING
) {
1448 _cleanup_free_
char *ex
= NULL
, *req
= NULL
;
1450 r
= route_protocol_to_string_alloc(existing
->protocol
, &ex
);
1454 r
= route_protocol_to_string_alloc(requesting
->protocol
, &req
);
1458 log_debug("Cannot update route: existing protocol: %s, requesting protocol: %s", ex
, req
);
1463 if (existing
->type
!= requesting
->type
) {
1464 log_debug("Cannot update route: existing type: %s, requesting type: %s",
1465 route_type_to_string(existing
->type
),
1466 route_type_to_string(requesting
->type
));
1470 if ((existing
->flags
& ~RTNH_COMPARE_MASK
) != (requesting
->flags
& ~RTNH_COMPARE_MASK
)) {
1471 if (DEBUG_LOGGING
) {
1472 _cleanup_free_
char *ex
= NULL
, *req
= NULL
;
1474 r
= route_flags_to_string_alloc(existing
->flags
, &ex
);
1478 r
= route_flags_to_string_alloc(requesting
->flags
, &req
);
1482 log_debug("Cannot update route: existing flags: %s, requesting flags: %s", ex
, req
);
1487 if (!in6_addr_equal(&existing
->prefsrc
.in6
, &requesting
->prefsrc
.in6
)) {
1488 log_debug("Cannot update route: existing preferred source: %s, requesting preferred source: %s",
1489 IN6_ADDR_TO_STRING(&existing
->prefsrc
.in6
),
1490 IN6_ADDR_TO_STRING(&requesting
->prefsrc
.in6
));
1493 if (existing
->pref
!= requesting
->pref
) {
1494 log_debug("Cannot update route: existing preference: %u, requesting preference: %u",
1495 existing
->pref
, requesting
->pref
);
1498 if (existing
->expiration_managed_by_kernel
&& requesting
->lifetime_usec
== USEC_INFINITY
) {
1499 log_route_debug(existing
,
1500 "Cannot update route: the expiration is managed by the kernel and requested lifetime is infinite",
1502 return false; /* We cannot disable expiration timer in the kernel. */
1504 if (!route_metric_can_update(&existing
->metric
, &requesting
->metric
, existing
->expiration_managed_by_kernel
)) {
1505 log_route_debug(existing
,
1506 "Cannot update route: expiration is managed by the kernel or metrics differ",
1510 if (existing
->nexthop
.weight
!= requesting
->nexthop
.weight
) {
1511 log_debug("Cannot update route: existing weight: %u, requesting weight: %u",
1512 existing
->nexthop
.weight
, requesting
->nexthop
.weight
);
1518 assert_not_reached();
1522 static int link_unmark_route(Link
*link
, const Route
*route
, const RouteNextHop
*nh
) {
1523 _cleanup_(route_unrefp
) Route
*tmp
= NULL
;
1530 r
= route_dup(route
, nh
, &tmp
);
1534 r
= route_adjust_nexthops(tmp
, link
);
1538 if (route_get(link
->manager
, tmp
, &existing
) < 0)
1541 if (!route_can_update(link
->manager
, existing
, tmp
))
1544 route_unmark(existing
);
1548 int link_drop_routes(Link
*link
, bool only_static
) {
1554 assert(link
->manager
);
1556 /* First, mark all routes. */
1557 SET_FOREACH(route
, link
->manager
->routes
) {
1558 /* Do not touch routes managed by the kernel. */
1559 if (route_by_kernel(route
))
1562 /* Ignore routes not assigned yet or already removed. */
1563 if (!route_exists(route
))
1566 if (!link_should_mark_config(link
, only_static
, route
->source
, route
->protocol
))
1569 Link
*route_link
= NULL
;
1570 if (route_get_link(link
->manager
, route
, &route_link
) >= 0 && route_link
!= link
) {
1571 /* When we also mark foreign routes, do not mark routes assigned to other interfaces.
1572 * Otherwise, routes assigned to unmanaged interfaces will be dropped.
1573 * Note, route_get_link() does not provide assigned link for routes with an
1574 * unreachable type or IPv4 multipath routes. So, the current implementation does not
1575 * support managing such routes by other daemon or so, unless ManageForeignRoutes=no. */
1579 /* When we mark only static routes, do not mark routes assigned to links that we do
1580 * not know the assignment of .network files to the interfaces. Otherwise, if an
1581 * interface is in the pending state, even if the .network file to be assigned to the
1582 * interface has KeepConfiguration=yes, routes on the interface will be removed.
1583 * This is especially important when systemd-networkd is restarted. */
1584 if (!IN_SET(route_link
->state
, LINK_STATE_UNMANAGED
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
1591 /* Then, unmark all routes requested by active links. */
1592 HASHMAP_FOREACH(other
, link
->manager
->links_by_index
) {
1593 if (only_static
&& other
== link
)
1596 if (!IN_SET(other
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
1599 HASHMAP_FOREACH(route
, other
->network
->routes_by_section
) {
1600 if (route
->source
!= NETWORK_CONFIG_SOURCE_STATIC
)
1603 if (route
->family
== AF_INET
|| ordered_set_isempty(route
->nexthops
)) {
1604 r
= link_unmark_route(other
, route
, NULL
);
1610 ORDERED_SET_FOREACH(nh
, route
->nexthops
) {
1611 r
= link_unmark_route(other
, route
, nh
);
1618 /* Also unmark routes requested in .netdev file. */
1619 if (other
->netdev
&& other
->netdev
->kind
== NETDEV_KIND_WIREGUARD
) {
1620 Wireguard
*w
= WIREGUARD(other
->netdev
);
1622 SET_FOREACH(route
, w
->routes
) {
1623 r
= link_unmark_route(other
, route
, NULL
);
1630 /* Finally, remove all marked routes. */
1631 SET_FOREACH(route
, link
->manager
->routes
) {
1632 if (!route_is_marked(route
))
1635 RET_GATHER(r
, route_remove(route
, link
->manager
));
1641 void link_forget_routes(Link
*link
) {
1643 assert(link
->ifindex
> 0);
1644 assert(!FLAGS_SET(link
->flags
, IFF_UP
));
1646 /* When an interface went down, IPv4 non-local routes bound to the interface are silently removed by
1647 * the kernel, without any notifications. Let's forget them in that case. Otherwise, when the link
1648 * goes up later, the configuration order of routes may be confused by the nonexistent routes.
1649 * See issue #35047. */
1652 SET_FOREACH(route
, link
->manager
->routes
) {
1653 // TODO: handle multipath routes
1654 if (route
->nexthop
.ifindex
!= link
->ifindex
)
1656 if (route
->family
!= AF_INET
)
1658 // TODO: check RTN_NAT and RTN_XRESOLVE
1659 if (!IN_SET(route
->type
, RTN_UNICAST
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_MULTICAST
))
1662 route_forget(link
->manager
, route
, "Forgetting silently removed");
1666 int network_add_ipv4ll_route(Network
*network
) {
1667 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1668 unsigned section_line
;
1673 if (!network
->ipv4ll_route
)
1676 r
= hashmap_by_section_find_unused_line(network
->routes_by_section
, network
->filename
, §ion_line
);
1680 /* IPv4LLRoute= is in [Network] section. */
1681 r
= route_new_static(network
, network
->filename
, section_line
, &route
);
1685 r
= in_addr_from_string(AF_INET
, "169.254.0.0", &route
->dst
);
1689 route
->family
= AF_INET
;
1690 route
->dst_prefixlen
= 16;
1691 route
->scope
= RT_SCOPE_LINK
;
1692 route
->scope_set
= true;
1693 route
->table_set
= true;
1694 route
->priority
= IPV4LL_ROUTE_METRIC
;
1695 route
->protocol
= RTPROT_STATIC
;
1701 int network_add_default_route_on_device(Network
*network
) {
1702 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
1703 unsigned section_line
;
1708 if (!network
->default_route_on_device
)
1711 r
= hashmap_by_section_find_unused_line(network
->routes_by_section
, network
->filename
, §ion_line
);
1715 /* DefaultRouteOnDevice= is in [Network] section. */
1716 r
= route_new_static(network
, network
->filename
, section_line
, &route
);
1720 route
->family
= AF_INET
;
1721 route
->scope
= RT_SCOPE_LINK
;
1722 route
->scope_set
= true;
1723 route
->protocol
= RTPROT_STATIC
;
1729 static int config_parse_preferred_src(
1731 const char *filename
,
1733 const char *section
,
1734 unsigned section_line
,
1741 Route
*route
= ASSERT_PTR(userdata
);
1744 if (isempty(rvalue
)) {
1745 route
->prefsrc_set
= false;
1746 route
->prefsrc
= IN_ADDR_NULL
;
1750 r
= parse_boolean(rvalue
);
1752 /* Accepts only no. That prohibits prefsrc set by DHCP lease. */
1753 route
->prefsrc_set
= true;
1754 route
->prefsrc
= IN_ADDR_NULL
;
1758 if (route
->family
== AF_UNSPEC
)
1759 r
= in_addr_from_string_auto(rvalue
, &route
->family
, &route
->prefsrc
);
1761 r
= in_addr_from_string(route
->family
, rvalue
, &route
->prefsrc
);
1763 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1765 route
->prefsrc_set
= true;
1769 static int config_parse_route_destination(
1771 const char *filename
,
1773 const char *section
,
1774 unsigned section_line
,
1781 Route
*route
= ASSERT_PTR(userdata
);
1782 union in_addr_union
*buffer
;
1783 unsigned char *prefixlen
;
1789 if (streq(lvalue
, "Destination")) {
1790 buffer
= &route
->dst
;
1791 prefixlen
= &route
->dst_prefixlen
;
1792 } else if (streq(lvalue
, "Source")) {
1793 buffer
= &route
->src
;
1794 prefixlen
= &route
->src_prefixlen
;
1796 assert_not_reached();
1798 if (route
->family
== AF_UNSPEC
)
1799 r
= in_addr_prefix_from_string_auto(rvalue
, &route
->family
, buffer
, prefixlen
);
1801 r
= in_addr_prefix_from_string(rvalue
, route
->family
, buffer
, prefixlen
);
1803 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1805 (void) in_addr_mask(route
->family
, buffer
, *prefixlen
);
1809 static int config_parse_route_priority(
1811 const char *filename
,
1813 const char *section
,
1814 unsigned section_line
,
1821 Route
*route
= ASSERT_PTR(userdata
);
1826 r
= safe_atou32(rvalue
, &route
->priority
);
1828 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1830 route
->priority_set
= true;
1834 static int config_parse_route_scope(
1836 const char *filename
,
1838 const char *section
,
1839 unsigned section_line
,
1846 Route
*route
= ASSERT_PTR(userdata
);
1851 r
= route_scope_from_string(rvalue
);
1853 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1856 route
->scope_set
= true;
1860 static int config_parse_route_table(
1862 const char *filename
,
1864 const char *section
,
1865 unsigned section_line
,
1872 Route
*route
= ASSERT_PTR(userdata
);
1873 Manager
*manager
= ASSERT_PTR(ASSERT_PTR(route
->network
)->manager
);
1878 r
= manager_get_route_table_from_string(manager
, rvalue
, &route
->table
);
1880 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1882 route
->table_set
= true;
1886 static int config_parse_route_preference(
1888 const char *filename
,
1890 const char *section
,
1891 unsigned section_line
,
1898 Route
*route
= ASSERT_PTR(userdata
);
1902 if (streq(rvalue
, "low"))
1903 route
->pref
= SD_NDISC_PREFERENCE_LOW
;
1904 else if (streq(rvalue
, "medium"))
1905 route
->pref
= SD_NDISC_PREFERENCE_MEDIUM
;
1906 else if (streq(rvalue
, "high"))
1907 route
->pref
= SD_NDISC_PREFERENCE_HIGH
;
1909 return log_syntax_parse_error(unit
, filename
, line
, 0, lvalue
, rvalue
);
1911 route
->pref_set
= true;
1915 static int config_parse_route_protocol(
1917 const char *filename
,
1919 const char *section
,
1920 unsigned section_line
,
1927 unsigned char *p
= ASSERT_PTR(data
);
1932 r
= route_protocol_from_string(rvalue
);
1934 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1936 *p
= (unsigned char) r
;
1940 static int config_parse_route_type(
1942 const char *filename
,
1944 const char *section
,
1945 unsigned section_line
,
1952 unsigned char *p
= ASSERT_PTR(data
);
1957 r
= route_type_from_string(rvalue
);
1959 return log_syntax_parse_error(unit
, filename
, line
, r
, lvalue
, rvalue
);
1961 *p
= (unsigned char) r
;
1965 int config_parse_route_section(
1967 const char *filename
,
1969 const char *section
,
1970 unsigned section_line
,
1977 static const ConfigSectionParser table
[_ROUTE_CONF_PARSER_MAX
] = {
1978 [ROUTE_DESTINATION
] = { .parser
= config_parse_route_destination
, .ltype
= 0, .offset
= 0, },
1979 [ROUTE_PREFERRED_SOURCE
] = { .parser
= config_parse_preferred_src
, .ltype
= 0, .offset
= 0, },
1980 [ROUTE_PRIORITY
] = { .parser
= config_parse_route_priority
, .ltype
= 0, .offset
= 0, },
1981 [ROUTE_SCOPE
] = { .parser
= config_parse_route_scope
, .ltype
= 0, .offset
= 0, },
1982 [ROUTE_TABLE
] = { .parser
= config_parse_route_table
, .ltype
= 0, .offset
= 0, },
1983 [ROUTE_PREFERENCE
] = { .parser
= config_parse_route_preference
, .ltype
= 0, .offset
= 0, },
1984 [ROUTE_PROTOCOL
] = { .parser
= config_parse_route_protocol
, .ltype
= 0, .offset
= offsetof(Route
, protocol
), },
1985 [ROUTE_TYPE
] = { .parser
= config_parse_route_type
, .ltype
= 0, .offset
= offsetof(Route
, type
), },
1986 [ROUTE_GATEWAY_NETWORK
] = { .parser
= config_parse_gateway
, .ltype
= 0, .offset
= 0, },
1987 [ROUTE_GATEWAY
] = { .parser
= config_parse_gateway
, .ltype
= 1, .offset
= 0, },
1988 [ROUTE_GATEWAY_ONLINK
] = { .parser
= config_parse_tristate
, .ltype
= 0, .offset
= offsetof(Route
, gateway_onlink
), },
1989 [ROUTE_MULTIPATH
] = { .parser
= config_parse_multipath_route
, .ltype
= 0, .offset
= offsetof(Route
, nexthops
), },
1990 [ROUTE_NEXTHOP
] = { .parser
= config_parse_route_nexthop
, .ltype
= 0, .offset
= offsetof(Route
, nexthop_id
), },
1991 [ROUTE_METRIC_MTU
] = { .parser
= config_parse_route_metric
, .ltype
= RTAX_MTU
, .offset
= 0, },
1992 [ROUTE_METRIC_ADVMSS
] = { .parser
= config_parse_route_metric
, .ltype
= RTAX_ADVMSS
, .offset
= 0, },
1993 [ROUTE_METRIC_HOPLIMIT
] = { .parser
= config_parse_route_metric
, .ltype
= RTAX_HOPLIMIT
, .offset
= 0, },
1994 [ROUTE_METRIC_INITCWND
] = { .parser
= config_parse_route_metric
, .ltype
= RTAX_INITCWND
, .offset
= 0, },
1995 [ROUTE_METRIC_RTO_MIN
] = { .parser
= config_parse_route_metric
, .ltype
= RTAX_RTO_MIN
, .offset
= 0, },
1996 [ROUTE_METRIC_INITRWND
] = { .parser
= config_parse_route_metric
, .ltype
= RTAX_INITRWND
, .offset
= 0, },
1997 [ROUTE_METRIC_QUICKACK
] = { .parser
= config_parse_route_metric
, .ltype
= RTAX_QUICKACK
, .offset
= 0, },
1998 [ROUTE_METRIC_CC_ALGO
] = { .parser
= config_parse_string
, .ltype
= 0, .offset
= offsetof(Route
, metric
.tcp_congestion_control_algo
), },
1999 [ROUTE_METRIC_FASTOPEN_NO_COOKIE
] = { .parser
= config_parse_route_metric
, .ltype
= RTAX_FASTOPEN_NO_COOKIE
, .offset
= 0, },
2002 _cleanup_(route_unref_or_set_invalidp
) Route
*route
= NULL
;
2003 Network
*network
= ASSERT_PTR(userdata
);
2008 if (streq(section
, "Network")) {
2009 assert(streq_ptr(lvalue
, "Gateway"));
2011 /* we are not in an Route section, so use line number instead */
2012 r
= route_new_static(network
, filename
, line
, &route
);
2014 r
= route_new_static(network
, filename
, section_line
, &route
);
2018 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2019 "Failed to allocate route, ignoring assignment: %m");
2023 r
= config_section_parse(table
, ELEMENTSOF(table
),
2024 unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, route
);
2032 int route_section_verify(Route
*route
) {
2036 assert(route
->section
);
2038 if (section_is_invalid(route
->section
))
2041 /* Currently, we do not support static route with finite lifetime. */
2042 assert(route
->lifetime_usec
== USEC_INFINITY
);
2044 r
= route_section_verify_nexthops(route
);
2049 if (!route
->table_set
&& route
->network
&& route
->network
->vrf
) {
2050 route
->table
= VRF(route
->network
->vrf
)->table
;
2051 route
->table_set
= true;
2054 if (!route
->table_set
&& IN_SET(route
->type
, RTN_LOCAL
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_NAT
))
2055 route
->table
= RT_TABLE_LOCAL
;
2058 if (!route
->scope_set
&& route
->family
== AF_INET
) {
2059 if (IN_SET(route
->type
, RTN_LOCAL
, RTN_NAT
))
2060 route
->scope
= RT_SCOPE_HOST
;
2061 else if (IN_SET(route
->type
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_MULTICAST
))
2062 route
->scope
= RT_SCOPE_LINK
;
2063 else if (IN_SET(route
->type
, RTN_UNICAST
, RTN_UNSPEC
) &&
2064 !route
->gateway_from_dhcp_or_ra
&&
2065 !in_addr_is_set(route
->nexthop
.family
, &route
->nexthop
.gw
) &&
2066 ordered_set_isempty(route
->nexthops
) &&
2067 route
->nexthop_id
== 0)
2068 route
->scope
= RT_SCOPE_LINK
;
2072 if (route
->family
== AF_INET6
) {
2073 if (route
->scope
!= RT_SCOPE_UNIVERSE
) {
2074 log_section_warning(route
->section
, "Scope= is specified for IPv6 route. It will be ignored.");
2075 route
->scope
= RT_SCOPE_UNIVERSE
;
2078 if (route
->priority
== 0)
2079 route
->priority
= IP6_RT_PRIO_USER
;
2085 void network_drop_invalid_routes(Network
*network
) {
2090 HASHMAP_FOREACH(route
, network
->routes_by_section
)
2091 if (route_section_verify(route
) < 0)
2092 route_detach(route
);