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 int route_new(Route
**ret
) {
25 _cleanup_(route_freep
) Route
*route
= NULL
;
27 route
= new(Route
, 1);
33 .scope
= RT_SCOPE_UNIVERSE
,
34 .protocol
= RTPROT_UNSPEC
,
36 .table
= RT_TABLE_MAIN
,
37 .lifetime_usec
= USEC_INFINITY
,
39 .fast_open_no_cookie
= -1,
44 *ret
= TAKE_PTR(route
);
49 static int route_new_static(Network
*network
, const char *filename
, unsigned section_line
, Route
**ret
) {
50 _cleanup_(config_section_freep
) ConfigSection
*n
= NULL
;
51 _cleanup_(route_freep
) Route
*route
= NULL
;
57 assert(section_line
> 0);
59 r
= config_section_new(filename
, section_line
, &n
);
63 route
= hashmap_get(network
->routes_by_section
, n
);
65 *ret
= TAKE_PTR(route
);
69 if (hashmap_size(network
->routes_by_section
) >= routes_max())
72 r
= route_new(&route
);
76 route
->protocol
= RTPROT_STATIC
;
77 route
->network
= network
;
78 route
->section
= TAKE_PTR(n
);
79 route
->source
= NETWORK_CONFIG_SOURCE_STATIC
;
81 r
= hashmap_ensure_put(&network
->routes_by_section
, &config_section_hash_ops
, route
->section
, route
);
85 *ret
= TAKE_PTR(route
);
89 Route
*route_free(Route
*route
) {
94 assert(route
->section
);
95 hashmap_remove(route
->network
->routes_by_section
, route
->section
);
98 config_section_free(route
->section
);
101 set_remove(route
->link
->routes
, route
);
104 set_remove(route
->manager
->routes
, route
);
106 ordered_set_free_with_destructor(route
->multipath_routes
, multipath_route_free
);
108 sd_event_source_disable_unref(route
->expire
);
110 free(route
->tcp_congestion_control_algo
);
115 static void route_hash_func(const Route
*route
, struct siphash
*state
) {
118 siphash24_compress(&route
->family
, sizeof(route
->family
), state
);
120 switch (route
->family
) {
123 siphash24_compress(&route
->dst_prefixlen
, sizeof(route
->dst_prefixlen
), state
);
124 siphash24_compress(&route
->dst
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
126 siphash24_compress(&route
->src_prefixlen
, sizeof(route
->src_prefixlen
), state
);
127 siphash24_compress(&route
->src
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
129 siphash24_compress(&route
->gw_family
, sizeof(route
->gw_family
), state
);
130 if (IN_SET(route
->gw_family
, AF_INET
, AF_INET6
)) {
131 siphash24_compress(&route
->gw
, FAMILY_ADDRESS_SIZE(route
->gw_family
), state
);
132 siphash24_compress(&route
->gw_weight
, sizeof(route
->gw_weight
), state
);
135 siphash24_compress(&route
->prefsrc
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
137 siphash24_compress(&route
->tos
, sizeof(route
->tos
), state
);
138 siphash24_compress(&route
->priority
, sizeof(route
->priority
), state
);
139 siphash24_compress(&route
->table
, sizeof(route
->table
), state
);
140 siphash24_compress(&route
->protocol
, sizeof(route
->protocol
), state
);
141 siphash24_compress(&route
->scope
, sizeof(route
->scope
), state
);
142 siphash24_compress(&route
->type
, sizeof(route
->type
), state
);
144 siphash24_compress(&route
->initcwnd
, sizeof(route
->initcwnd
), state
);
145 siphash24_compress(&route
->initrwnd
, sizeof(route
->initrwnd
), state
);
147 siphash24_compress(&route
->advmss
, sizeof(route
->advmss
), state
);
148 siphash24_compress(&route
->nexthop_id
, sizeof(route
->nexthop_id
), state
);
152 /* treat any other address family as AF_UNSPEC */
157 static int route_compare_func(const Route
*a
, const Route
*b
) {
160 r
= CMP(a
->family
, b
->family
);
167 r
= CMP(a
->dst_prefixlen
, b
->dst_prefixlen
);
171 r
= memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
175 r
= CMP(a
->src_prefixlen
, b
->src_prefixlen
);
179 r
= memcmp(&a
->src
, &b
->src
, FAMILY_ADDRESS_SIZE(a
->family
));
183 r
= CMP(a
->gw_family
, b
->gw_family
);
187 if (IN_SET(a
->gw_family
, AF_INET
, AF_INET6
)) {
188 r
= memcmp(&a
->gw
, &b
->gw
, FAMILY_ADDRESS_SIZE(a
->family
));
192 r
= CMP(a
->gw_weight
, b
->gw_weight
);
197 r
= memcmp(&a
->prefsrc
, &b
->prefsrc
, FAMILY_ADDRESS_SIZE(a
->family
));
201 r
= CMP(a
->tos
, b
->tos
);
205 r
= CMP(a
->priority
, b
->priority
);
209 r
= CMP(a
->table
, b
->table
);
213 r
= CMP(a
->protocol
, b
->protocol
);
217 r
= CMP(a
->scope
, b
->scope
);
221 r
= CMP(a
->type
, b
->type
);
225 r
= CMP(a
->initcwnd
, b
->initcwnd
);
229 r
= CMP(a
->initrwnd
, b
->initrwnd
);
233 r
= CMP(a
->advmss
, b
->advmss
);
237 r
= CMP(a
->nexthop_id
, b
->nexthop_id
);
243 /* treat any other address family as AF_UNSPEC */
248 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
255 static bool route_type_is_reject(const Route
*route
) {
258 return IN_SET(route
->type
, RTN_UNREACHABLE
, RTN_PROHIBIT
, RTN_BLACKHOLE
, RTN_THROW
);
261 static bool route_needs_convert(const Route
*route
) {
264 return route
->nexthop_id
> 0 || !ordered_set_isempty(route
->multipath_routes
);
267 static int route_add(Manager
*manager
, Link
*link
, Route
*route
) {
272 if (route_type_is_reject(route
)) {
275 r
= set_ensure_put(&manager
->routes
, &route_hash_ops
, route
);
281 route
->manager
= manager
;
285 r
= set_ensure_put(&link
->routes
, &route_hash_ops
, route
);
297 int route_get(Manager
*manager
, Link
*link
, const Route
*in
, Route
**ret
) {
302 if (route_type_is_reject(in
)) {
306 route
= set_get(manager
->routes
, in
);
311 route
= set_get(link
->routes
, in
);
322 int route_dup(const Route
*src
, Route
**ret
) {
323 _cleanup_(route_freep
) Route
*dest
= NULL
;
326 /* This does not copy mulipath routes. */
331 dest
= newdup(Route
, src
, 1);
335 /* Unset all pointers */
336 dest
->network
= NULL
;
337 dest
->section
= NULL
;
339 dest
->manager
= NULL
;
340 dest
->multipath_routes
= NULL
;
342 dest
->tcp_congestion_control_algo
= NULL
;
344 r
= free_and_strdup(&dest
->tcp_congestion_control_algo
, src
->tcp_congestion_control_algo
);
348 *ret
= TAKE_PTR(dest
);
352 static void route_apply_nexthop(Route
*route
, const NextHop
*nh
, uint8_t nh_weight
) {
355 assert(hashmap_isempty(nh
->group
));
357 route
->gw_family
= nh
->family
;
360 if (nh_weight
!= UINT8_MAX
)
361 route
->gw_weight
= nh_weight
;
364 route
->type
= RTN_BLACKHOLE
;
367 static void route_apply_multipath_route(Route
*route
, const MultipathRoute
*m
) {
371 route
->gw_family
= m
->gateway
.family
;
372 route
->gw
= m
->gateway
.address
;
373 route
->gw_weight
= m
->weight
;
376 static int multipath_route_get_link(Manager
*manager
, const MultipathRoute
*m
, Link
**ret
) {
383 r
= link_get_by_name(manager
, m
->ifname
, ret
);
384 return r
< 0 ? r
: 1;
386 } else if (m
->ifindex
> 0) { /* Always ignore ifindex if ifname is set. */
387 r
= link_get_by_index(manager
, m
->ifindex
, ret
);
388 return r
< 0 ? r
: 1;
396 typedef struct ConvertedRoutes
{
402 static ConvertedRoutes
*converted_routes_free(ConvertedRoutes
*c
) {
406 for (size_t i
= 0; i
< c
->n
; i
++)
407 route_free(c
->routes
[i
]);
415 DEFINE_TRIVIAL_CLEANUP_FUNC(ConvertedRoutes
*, converted_routes_free
);
417 static int converted_routes_new(size_t n
, ConvertedRoutes
**ret
) {
418 _cleanup_(converted_routes_freep
) ConvertedRoutes
*c
= NULL
;
419 _cleanup_free_ Route
**routes
= NULL
;
420 _cleanup_free_ Link
**links
= NULL
;
425 routes
= new0(Route
*, n
);
429 links
= new0(Link
*, n
);
433 c
= new(ConvertedRoutes
, 1);
437 *c
= (ConvertedRoutes
) {
439 .routes
= TAKE_PTR(routes
),
440 .links
= TAKE_PTR(links
),
447 static int route_convert(Manager
*manager
, const Route
*route
, ConvertedRoutes
**ret
) {
448 _cleanup_(converted_routes_freep
) ConvertedRoutes
*c
= NULL
;
455 if (!route_needs_convert(route
)) {
460 if (route
->nexthop_id
> 0) {
461 struct nexthop_grp
*nhg
;
464 r
= manager_get_nexthop_by_id(manager
, route
->nexthop_id
, &nh
);
468 if (hashmap_isempty(nh
->group
)) {
469 r
= converted_routes_new(1, &c
);
473 r
= route_dup(route
, &c
->routes
[0]);
477 route_apply_nexthop(c
->routes
[0], nh
, UINT8_MAX
);
478 c
->links
[0] = nh
->link
;
484 r
= converted_routes_new(hashmap_size(nh
->group
), &c
);
489 HASHMAP_FOREACH(nhg
, nh
->group
) {
492 r
= manager_get_nexthop_by_id(manager
, nhg
->id
, &h
);
496 r
= route_dup(route
, &c
->routes
[i
]);
500 route_apply_nexthop(c
->routes
[i
], h
, nhg
->weight
);
501 c
->links
[i
] = h
->link
;
511 assert(!ordered_set_isempty(route
->multipath_routes
));
513 r
= converted_routes_new(ordered_set_size(route
->multipath_routes
), &c
);
519 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
520 r
= route_dup(route
, &c
->routes
[i
]);
524 route_apply_multipath_route(c
->routes
[i
], m
);
526 r
= multipath_route_get_link(manager
, m
, &c
->links
[i
]);
537 void link_mark_routes(Link
*link
, NetworkConfigSource source
) {
542 SET_FOREACH(route
, link
->routes
) {
543 if (route
->source
!= source
)
550 static void log_route_debug(const Route
*route
, const char *str
, const Link
*link
, const Manager
*manager
) {
551 _cleanup_free_
char *state
= NULL
, *gw_alloc
= NULL
, *prefsrc
= NULL
,
552 *table
= NULL
, *scope
= NULL
, *proto
= NULL
, *flags
= NULL
;
553 const char *gw
= NULL
, *dst
, *src
;
559 /* link may be NULL. */
564 (void) network_config_state_to_string_alloc(route
->state
, &state
);
566 dst
= in_addr_is_set(route
->family
, &route
->dst
) || route
->dst_prefixlen
> 0 ?
567 IN_ADDR_PREFIX_TO_STRING(route
->family
, &route
->dst
, route
->dst_prefixlen
) : NULL
;
568 src
= in_addr_is_set(route
->family
, &route
->src
) || route
->src_prefixlen
> 0 ?
569 IN_ADDR_PREFIX_TO_STRING(route
->family
, &route
->src
, route
->src_prefixlen
) : NULL
;
571 if (in_addr_is_set(route
->gw_family
, &route
->gw
)) {
572 (void) in_addr_to_string(route
->gw_family
, &route
->gw
, &gw_alloc
);
574 } else if (route
->gateway_from_dhcp_or_ra
) {
575 if (route
->gw_family
== AF_INET
)
577 else if (route
->gw_family
== AF_INET6
)
582 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
583 _cleanup_free_
char *buf
= NULL
;
584 union in_addr_union a
= m
->gateway
.address
;
586 (void) in_addr_to_string(m
->gateway
.family
, &a
, &buf
);
587 (void) strextend_with_separator(&gw_alloc
, ",", strna(buf
));
589 (void) strextend(&gw_alloc
, "@", m
->ifname
);
590 else if (m
->ifindex
> 0)
591 (void) strextendf(&gw_alloc
, "@%i", m
->ifindex
);
592 /* See comments in config_parse_multipath_route(). */
593 (void) strextendf(&gw_alloc
, ":%"PRIu32
, m
->weight
+ 1);
597 if (in_addr_is_set(route
->family
, &route
->prefsrc
))
598 (void) in_addr_to_string(route
->family
, &route
->prefsrc
, &prefsrc
);
599 (void) route_scope_to_string_alloc(route
->scope
, &scope
);
600 (void) manager_get_route_table_to_string(manager
, route
->table
, /* append_num = */ true, &table
);
601 (void) route_protocol_full_to_string_alloc(route
->protocol
, &proto
);
602 (void) route_flags_to_string_alloc(route
->flags
, &flags
);
605 "%s %s route (%s): dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, "
606 "proto: %s, type: %s, nexthop: %"PRIu32
", priority: %"PRIu32
", flags: %s",
607 str
, strna(network_config_source_to_string(route
->source
)), strna(state
),
608 strna(dst
), strna(src
), strna(gw
), strna(prefsrc
),
609 strna(scope
), strna(table
), strna(proto
),
610 strna(route_type_to_string(route
->type
)),
611 route
->nexthop_id
, route
->priority
, strna(flags
));
614 static int route_set_netlink_message(const Route
*route
, sd_netlink_message
*req
, Link
*link
) {
620 /* link may be NULL */
622 if (in_addr_is_set(route
->gw_family
, &route
->gw
) && route
->nexthop_id
== 0) {
623 if (route
->gw_family
== route
->family
) {
624 r
= netlink_message_append_in_addr_union(req
, RTA_GATEWAY
, route
->gw_family
, &route
->gw
);
629 .family
= route
->gw_family
,
630 .address
= route
->gw
,
633 r
= sd_netlink_message_append_data(req
, RTA_VIA
, &rtvia
, sizeof(rtvia
));
639 if (route
->dst_prefixlen
> 0) {
640 r
= netlink_message_append_in_addr_union(req
, RTA_DST
, route
->family
, &route
->dst
);
644 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
649 if (route
->src_prefixlen
> 0) {
650 r
= netlink_message_append_in_addr_union(req
, RTA_SRC
, route
->family
, &route
->src
);
654 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
659 if (in_addr_is_set(route
->family
, &route
->prefsrc
)) {
660 r
= netlink_message_append_in_addr_union(req
, RTA_PREFSRC
, route
->family
, &route
->prefsrc
);
665 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
669 r
= sd_rtnl_message_route_set_flags(req
, route
->flags
& RTNH_F_ONLINK
);
673 if (route
->table
< 256) {
674 r
= sd_rtnl_message_route_set_table(req
, route
->table
);
678 r
= sd_rtnl_message_route_set_table(req
, RT_TABLE_UNSPEC
);
682 /* Table attribute to allow more than 256. */
683 r
= sd_netlink_message_append_u32(req
, RTA_TABLE
, route
->table
);
688 if (!route_type_is_reject(route
) &&
689 route
->nexthop_id
== 0 &&
690 ordered_set_isempty(route
->multipath_routes
)) {
691 assert(link
); /* Those routes must be attached to a specific link */
693 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
698 if (route
->nexthop_id
> 0) {
699 r
= sd_netlink_message_append_u32(req
, RTA_NH_ID
, route
->nexthop_id
);
704 r
= sd_netlink_message_append_u8(req
, RTA_PREF
, route
->pref
);
708 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->priority
);
715 static int route_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
720 /* link may be NULL. */
722 if (link
&& IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
725 r
= sd_netlink_message_get_errno(m
);
726 if (r
< 0 && r
!= -ESRCH
)
727 log_link_message_warning_errno(link
, m
, r
, "Could not drop route, ignoring");
732 int route_remove(Route
*route
) {
733 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
740 assert(route
->manager
|| (route
->link
&& route
->link
->manager
));
741 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
744 manager
= route
->manager
?: link
->manager
;
746 log_route_debug(route
, "Removing", link
, manager
);
748 r
= sd_rtnl_message_new_route(manager
->rtnl
, &req
,
749 RTM_DELROUTE
, route
->family
,
752 return log_link_error_errno(link
, r
, "Could not create netlink message: %m");
754 if (route
->family
== AF_INET
&& route
->nexthop_id
> 0 && route
->type
== RTN_BLACKHOLE
)
755 /* When IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel
756 * sends RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type
757 * fib_rt_info::type may not be blackhole. Thus, we cannot know the internal value.
758 * Moreover, on route removal, the matching is done with the hidden value if we set
759 * non-zero type in RTM_DELROUTE message. Note, sd_rtnl_message_new_route() sets
760 * RTN_UNICAST by default. So, we need to clear the type here. */
765 r
= sd_rtnl_message_route_set_type(req
, type
);
767 return log_link_error_errno(link
, r
, "Could not set route type: %m");
769 r
= route_set_netlink_message(route
, req
, link
);
771 return log_error_errno(r
, "Could not fill netlink message: %m");
773 r
= netlink_call_async(manager
->rtnl
, NULL
, req
, route_remove_handler
,
774 link
? link_netlink_destroy_callback
: NULL
, link
);
776 return log_link_error_errno(link
, r
, "Could not send netlink message: %m");
780 route_enter_removing(route
);
784 int route_remove_and_drop(Route
*route
) {
788 route_cancel_request(route
, NULL
);
790 if (route_exists(route
))
791 return route_remove(route
);
793 if (route
->state
== 0)
799 static void manager_mark_routes(Manager
*manager
, bool foreign
, const Link
*except
) {
806 /* First, mark all routes. */
807 SET_FOREACH(route
, manager
->routes
) {
808 /* Do not touch routes managed by the kernel. */
809 if (route
->protocol
== RTPROT_KERNEL
)
812 /* When 'foreign' is true, mark only foreign routes, and vice versa. */
813 if (foreign
!= (route
->source
== NETWORK_CONFIG_SOURCE_FOREIGN
))
816 /* Do not touch dynamic routes. They will removed by dhcp_pd_prefix_lost() */
817 if (IN_SET(route
->source
, NETWORK_CONFIG_SOURCE_DHCP4
, NETWORK_CONFIG_SOURCE_DHCP6
))
820 /* Ignore routes not assigned yet or already removed. */
821 if (!route_exists(route
))
827 /* Then, unmark all routes requested by active links. */
828 HASHMAP_FOREACH(link
, manager
->links_by_index
) {
835 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
838 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
839 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
842 r
= route_convert(manager
, route
, &converted
);
846 if (route_get(manager
, NULL
, route
, &existing
) >= 0)
847 route_unmark(existing
);
851 for (size_t i
= 0; i
< converted
->n
; i
++)
852 if (route_get(manager
, NULL
, converted
->routes
[i
], &existing
) >= 0)
853 route_unmark(existing
);
858 static int manager_drop_marked_routes(Manager
*manager
) {
864 SET_FOREACH(route
, manager
->routes
) {
865 if (!route_is_marked(route
))
868 RET_GATHER(r
, route_remove(route
));
874 static bool route_by_kernel(const Route
*route
) {
877 if (route
->protocol
== RTPROT_KERNEL
)
880 /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
881 * multicast with RTPROT_BOOT. Do not touch it. */
882 if (route
->protocol
== RTPROT_BOOT
&&
883 route
->family
== AF_INET6
&&
884 route
->dst_prefixlen
== 8 &&
885 in6_addr_equal(&route
->dst
.in6
, & (struct in6_addr
) {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}}))
891 static void link_unmark_wireguard_routes(Link
*link
) {
894 if (!link
->netdev
|| link
->netdev
->kind
!= NETDEV_KIND_WIREGUARD
)
897 Route
*route
, *existing
;
898 Wireguard
*w
= WIREGUARD(link
->netdev
);
900 SET_FOREACH(route
, w
->routes
)
901 if (route_get(NULL
, link
, route
, &existing
) >= 0)
902 route_unmark(existing
);
905 int link_drop_foreign_routes(Link
*link
) {
910 assert(link
->manager
);
911 assert(link
->network
);
913 SET_FOREACH(route
, link
->routes
) {
914 /* do not touch routes managed by the kernel */
915 if (route_by_kernel(route
))
918 /* Do not remove routes we configured. */
919 if (route
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
)
922 /* Ignore routes not assigned yet or already removed. */
923 if (!route_exists(route
))
926 if (route
->protocol
== RTPROT_STATIC
&&
927 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_STATIC
))
930 if (route
->protocol
== RTPROT_DHCP
&&
931 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_DHCP
))
937 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
938 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
941 r
= route_convert(link
->manager
, route
, &converted
);
945 if (route_get(NULL
, link
, route
, &existing
) >= 0)
946 route_unmark(existing
);
950 for (size_t i
= 0; i
< converted
->n
; i
++)
951 if (route_get(NULL
, link
, converted
->routes
[i
], &existing
) >= 0)
952 route_unmark(existing
);
955 link_unmark_wireguard_routes(link
);
958 SET_FOREACH(route
, link
->routes
) {
959 if (!route_is_marked(route
))
962 RET_GATHER(r
, route_remove(route
));
965 manager_mark_routes(link
->manager
, /* foreign = */ true, NULL
);
967 return RET_GATHER(r
, manager_drop_marked_routes(link
->manager
));
970 int link_drop_managed_routes(Link
*link
) {
976 SET_FOREACH(route
, link
->routes
) {
977 /* do not touch routes managed by the kernel */
978 if (route_by_kernel(route
))
981 /* Do not touch routes managed by kernel or other tools. */
982 if (route
->source
== NETWORK_CONFIG_SOURCE_FOREIGN
)
985 if (!route_exists(route
))
988 RET_GATHER(r
, route_remove(route
));
991 manager_mark_routes(link
->manager
, /* foreign = */ false, link
);
993 return RET_GATHER(r
, manager_drop_marked_routes(link
->manager
));
996 void link_foreignize_routes(Link
*link
) {
1001 SET_FOREACH(route
, link
->routes
)
1002 route
->source
= NETWORK_CONFIG_SOURCE_FOREIGN
;
1004 manager_mark_routes(link
->manager
, /* foreign = */ false, link
);
1006 SET_FOREACH(route
, link
->manager
->routes
) {
1007 if (!route_is_marked(route
))
1010 route
->source
= NETWORK_CONFIG_SOURCE_FOREIGN
;
1014 static int route_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1015 Route
*route
= ASSERT_PTR(userdata
);
1019 assert(route
->manager
|| (route
->link
&& route
->link
->manager
));
1021 link
= route
->link
; /* This may be NULL. */
1023 r
= route_remove(route
);
1025 log_link_warning_errno(link
, r
, "Could not remove route: %m");
1027 link_enter_failed(link
);
1033 static int route_setup_timer(Route
*route
, const struct rta_cacheinfo
*cacheinfo
) {
1038 assert(route
->manager
|| (route
->link
&& route
->link
->manager
));
1040 manager
= route
->manager
?: route
->link
->manager
;
1042 if (route
->lifetime_usec
== USEC_INFINITY
)
1045 if (cacheinfo
&& cacheinfo
->rta_expires
!= 0)
1046 /* Assume that non-zero rta_expires means kernel will handle the route expiration. */
1049 r
= event_reset_time(manager
->event
, &route
->expire
, CLOCK_BOOTTIME
,
1050 route
->lifetime_usec
, 0, route_expire_handler
, route
, 0, "route-expiration", true);
1057 static int append_nexthop_one(const Link
*link
, const Route
*route
, const MultipathRoute
*m
, struct rtattr
**rta
, size_t offset
) {
1058 struct rtnexthop
*rtnh
;
1059 struct rtattr
*new_rta
;
1067 new_rta
= realloc(*rta
, RTA_ALIGN((*rta
)->rta_len
) + RTA_SPACE(sizeof(struct rtnexthop
)));
1072 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1073 *rtnh
= (struct rtnexthop
) {
1074 .rtnh_len
= sizeof(*rtnh
),
1075 .rtnh_ifindex
= m
->ifindex
> 0 ? m
->ifindex
: link
->ifindex
,
1076 .rtnh_hops
= m
->weight
,
1079 (*rta
)->rta_len
+= sizeof(struct rtnexthop
);
1081 if (route
->family
== m
->gateway
.family
) {
1082 r
= rtattr_append_attribute(rta
, RTA_GATEWAY
, &m
->gateway
.address
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1085 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1086 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1088 r
= rtattr_append_attribute(rta
, RTA_VIA
, &m
->gateway
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1091 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1092 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1098 (*rta
)->rta_len
-= sizeof(struct rtnexthop
);
1102 static int append_nexthops(const Link
*link
, const Route
*route
, sd_netlink_message
*req
) {
1103 _cleanup_free_
struct rtattr
*rta
= NULL
;
1104 struct rtnexthop
*rtnh
;
1113 if (ordered_set_isempty(route
->multipath_routes
))
1116 rta
= new(struct rtattr
, 1);
1120 *rta
= (struct rtattr
) {
1121 .rta_type
= RTA_MULTIPATH
,
1122 .rta_len
= RTA_LENGTH(0),
1124 offset
= (uint8_t *) RTA_DATA(rta
) - (uint8_t *) rta
;
1126 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1127 r
= append_nexthop_one(link
, route
, m
, &rta
, offset
);
1131 rtnh
= (struct rtnexthop
*)((uint8_t *) rta
+ offset
);
1132 offset
= (uint8_t *) RTNH_NEXT(rtnh
) - (uint8_t *) rta
;
1135 r
= sd_netlink_message_append_data(req
, RTA_MULTIPATH
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
1142 int route_configure_handler_internal(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
, const char *error_msg
) {
1149 r
= sd_netlink_message_get_errno(m
);
1150 if (r
< 0 && r
!= -EEXIST
) {
1151 log_link_message_warning_errno(link
, m
, r
, "Could not set route");
1152 link_enter_failed(link
);
1159 static int route_configure(const Route
*route
, uint32_t lifetime_sec
, Link
*link
, Request
*req
) {
1160 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
1164 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
1166 assert(link
->manager
);
1167 assert(link
->manager
->rtnl
);
1168 assert(link
->ifindex
> 0);
1171 log_route_debug(route
, "Configuring", link
, link
->manager
);
1173 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &m
, RTM_NEWROUTE
, route
->family
, route
->protocol
);
1177 r
= sd_rtnl_message_route_set_type(m
, route
->type
);
1181 r
= route_set_netlink_message(route
, m
, link
);
1185 if (lifetime_sec
!= UINT32_MAX
) {
1186 r
= sd_netlink_message_append_u32(m
, RTA_EXPIRES
, lifetime_sec
);
1191 if (route
->ttl_propagate
>= 0) {
1192 r
= sd_netlink_message_append_u8(m
, RTA_TTL_PROPAGATE
, route
->ttl_propagate
);
1197 r
= sd_netlink_message_open_container(m
, RTA_METRICS
);
1201 if (route
->mtu
> 0) {
1202 r
= sd_netlink_message_append_u32(m
, RTAX_MTU
, route
->mtu
);
1207 if (route
->initcwnd
> 0) {
1208 r
= sd_netlink_message_append_u32(m
, RTAX_INITCWND
, route
->initcwnd
);
1213 if (route
->initrwnd
> 0) {
1214 r
= sd_netlink_message_append_u32(m
, RTAX_INITRWND
, route
->initrwnd
);
1219 if (route
->quickack
>= 0) {
1220 r
= sd_netlink_message_append_u32(m
, RTAX_QUICKACK
, route
->quickack
);
1225 if (route
->fast_open_no_cookie
>= 0) {
1226 r
= sd_netlink_message_append_u32(m
, RTAX_FASTOPEN_NO_COOKIE
, route
->fast_open_no_cookie
);
1231 if (route
->advmss
> 0) {
1232 r
= sd_netlink_message_append_u32(m
, RTAX_ADVMSS
, route
->advmss
);
1237 if (!isempty(route
->tcp_congestion_control_algo
)) {
1238 r
= sd_netlink_message_append_string(m
, RTAX_CC_ALGO
, route
->tcp_congestion_control_algo
);
1243 if (route
->hop_limit
> 0) {
1244 r
= sd_netlink_message_append_u32(m
, RTAX_HOPLIMIT
, route
->hop_limit
);
1249 if (route
->tcp_rto_usec
> 0) {
1250 r
= sd_netlink_message_append_u32(m
, RTAX_RTO_MIN
, DIV_ROUND_UP(route
->tcp_rto_usec
, USEC_PER_MSEC
));
1255 r
= sd_netlink_message_close_container(m
);
1259 if (!ordered_set_isempty(route
->multipath_routes
)) {
1260 assert(route
->nexthop_id
== 0);
1261 assert(!in_addr_is_set(route
->gw_family
, &route
->gw
));
1263 r
= append_nexthops(link
, route
, m
);
1268 return request_call_netlink_async(link
->manager
->rtnl
, m
, req
);
1271 static int route_is_ready_to_configure(const Route
*route
, Link
*link
) {
1277 if (!link_is_ready_to_configure(link
, false))
1280 if (set_size(link
->routes
) >= routes_max())
1283 if (route
->nexthop_id
> 0) {
1284 struct nexthop_grp
*nhg
;
1287 if (manager_get_nexthop_by_id(link
->manager
, route
->nexthop_id
, &nh
) < 0)
1290 if (!nexthop_exists(nh
))
1293 HASHMAP_FOREACH(nhg
, nh
->group
) {
1296 if (manager_get_nexthop_by_id(link
->manager
, nhg
->id
, &g
) < 0)
1299 if (!nexthop_exists(g
))
1304 if (in_addr_is_set(route
->family
, &route
->prefsrc
) > 0) {
1305 r
= manager_has_address(link
->manager
, route
->family
, &route
->prefsrc
, route
->family
== AF_INET6
);
1310 if (!gateway_is_ready(link
, FLAGS_SET(route
->flags
, RTNH_F_ONLINK
), route
->gw_family
, &route
->gw
))
1314 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1315 union in_addr_union a
= m
->gateway
.address
;
1318 r
= multipath_route_get_link(link
->manager
, m
, &l
);
1322 if (!link_is_ready_to_configure(l
, /* allow_unmanaged = */ true) ||
1323 !link_has_carrier(l
))
1326 m
->ifindex
= l
->ifindex
;
1329 if (!gateway_is_ready(l
?: link
, FLAGS_SET(route
->flags
, RTNH_F_ONLINK
), m
->gateway
.family
, &a
))
1336 static int route_process_request(Request
*req
, Link
*link
, Route
*route
) {
1337 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
1342 assert(link
->manager
);
1345 r
= route_is_ready_to_configure(route
, link
);
1347 return log_link_warning_errno(link
, r
, "Failed to check if route is ready to configure: %m");
1351 if (route_needs_convert(route
)) {
1352 r
= route_convert(link
->manager
, route
, &converted
);
1354 return log_link_warning_errno(link
, r
, "Failed to convert route: %m");
1359 for (size_t i
= 0; i
< converted
->n
; i
++) {
1362 if (route_get(link
->manager
, converted
->links
[i
] ?: link
, converted
->routes
[i
], &existing
) < 0) {
1363 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1365 r
= route_dup(converted
->routes
[i
], &tmp
);
1369 r
= route_add(link
->manager
, converted
->links
[i
] ?: link
, tmp
);
1371 return log_link_warning_errno(link
, r
, "Failed to add route: %m");
1375 existing
->source
= converted
->routes
[i
]->source
;
1376 existing
->provider
= converted
->routes
[i
]->provider
;
1382 assert_se(sd_event_now(link
->manager
->event
, CLOCK_BOOTTIME
, &now_usec
) >= 0);
1383 uint32_t sec
= usec_to_sec(route
->lifetime_usec
, now_usec
);
1385 log_link_debug(link
, "Refuse to configure %s route with zero lifetime.",
1386 network_config_source_to_string(route
->source
));
1389 for (size_t i
= 0; i
< converted
->n
; i
++) {
1392 assert_se(route_get(link
->manager
, converted
->links
[i
] ?: link
, converted
->routes
[i
], &existing
) >= 0);
1393 route_cancel_requesting(existing
);
1396 route_cancel_requesting(route
);
1401 r
= route_configure(route
, sec
, link
, req
);
1403 return log_link_warning_errno(link
, r
, "Failed to configure route: %m");
1406 for (size_t i
= 0; i
< converted
->n
; i
++) {
1409 assert_se(route_get(link
->manager
, converted
->links
[i
] ?: link
, converted
->routes
[i
], &existing
) >= 0);
1410 route_enter_configuring(existing
);
1413 route_enter_configuring(route
);
1418 int link_request_route(
1421 bool consume_object
,
1422 unsigned *message_counter
,
1423 route_netlink_handler_t netlink_handler
,
1426 Route
*existing
= NULL
;
1430 assert(link
->manager
);
1432 assert(route
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
);
1433 assert(!route_needs_convert(route
));
1435 (void) route_get(link
->manager
, link
, route
, &existing
);
1437 if (route
->lifetime_usec
== 0) {
1441 /* The requested route is outdated. Let's remove it. */
1442 return route_remove_and_drop(existing
);
1446 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1451 r
= route_dup(route
, &tmp
);
1456 r
= route_add(link
->manager
, link
, tmp
);
1460 existing
= TAKE_PTR(tmp
);
1462 existing
->source
= route
->source
;
1463 existing
->provider
= route
->provider
;
1464 existing
->lifetime_usec
= route
->lifetime_usec
;
1468 if (existing
->expire
) {
1469 /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE
1470 * message, so we need to update the timer here. */
1471 r
= route_setup_timer(existing
, NULL
);
1473 log_link_warning_errno(link
, r
, "Failed to update expiration timer for route, ignoring: %m");
1475 log_route_debug(existing
, "Updated expiration timer for", link
, link
->manager
);
1479 log_route_debug(existing
, "Requesting", link
, link
->manager
);
1480 r
= link_queue_request_safe(link
, REQUEST_TYPE_ROUTE
,
1484 route_process_request
,
1485 message_counter
, netlink_handler
, ret
);
1489 route_enter_requesting(existing
);
1493 static int static_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
1498 r
= route_configure_handler_internal(rtnl
, m
, link
, "Could not set route");
1502 if (link
->static_route_messages
== 0) {
1503 log_link_debug(link
, "Routes set");
1504 link
->static_routes_configured
= true;
1505 link_check_ready(link
);
1511 static int link_request_static_route(Link
*link
, Route
*route
) {
1513 assert(link
->manager
);
1516 if (!route_needs_convert(route
))
1517 return link_request_route(link
, route
, false, &link
->static_route_messages
,
1518 static_route_handler
, NULL
);
1520 log_route_debug(route
, "Requesting", link
, link
->manager
);
1521 return link_queue_request_safe(link
, REQUEST_TYPE_ROUTE
,
1522 route
, NULL
, route_hash_func
, route_compare_func
,
1523 route_process_request
,
1524 &link
->static_route_messages
, static_route_handler
, NULL
);
1527 static int link_request_wireguard_routes(Link
*link
, bool only_ipv4
) {
1534 if (!streq_ptr(link
->kind
, "wireguard"))
1537 if (netdev_get(link
->manager
, link
->ifname
, &netdev
) < 0)
1540 Wireguard
*w
= WIREGUARD(netdev
);
1542 SET_FOREACH(route
, w
->routes
) {
1543 if (only_ipv4
&& route
->family
!= AF_INET
)
1546 r
= link_request_static_route(link
, route
);
1554 int link_request_static_routes(Link
*link
, bool only_ipv4
) {
1559 assert(link
->network
);
1561 link
->static_routes_configured
= false;
1563 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
1564 if (route
->gateway_from_dhcp_or_ra
)
1567 if (only_ipv4
&& route
->family
!= AF_INET
)
1570 r
= link_request_static_route(link
, route
);
1575 r
= link_request_wireguard_routes(link
, only_ipv4
);
1579 if (link
->static_route_messages
== 0) {
1580 link
->static_routes_configured
= true;
1581 link_check_ready(link
);
1583 log_link_debug(link
, "Requesting routes");
1584 link_set_state(link
, LINK_STATE_CONFIGURING
);
1590 void route_cancel_request(Route
*route
, Link
*link
) {
1595 link
= route
->link
?: link
;
1599 if (!route_is_requesting(route
))
1604 .type
= REQUEST_TYPE_ROUTE
,
1606 .hash_func
= (hash_func_t
) route_hash_func
,
1607 .compare_func
= (compare_func_t
) route_compare_func
,
1610 request_detach(link
->manager
, &req
);
1611 route_cancel_requesting(route
);
1614 static int process_route_one(
1619 const struct rta_cacheinfo
*cacheinfo
) {
1621 _cleanup_(route_freep
) Route
*tmp
= in
;
1622 Route
*route
= NULL
;
1628 assert(IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
));
1630 /* link may be NULL. This consumes 'in'. */
1632 update_dhcp4
= link
&& tmp
->family
== AF_INET6
&& tmp
->dst_prefixlen
== 0;
1634 (void) route_get(manager
, link
, tmp
, &route
);
1639 route
->flags
= tmp
->flags
;
1640 route_enter_configured(route
);
1641 log_route_debug(route
, "Received remembered", link
, manager
);
1643 r
= route_setup_timer(route
, cacheinfo
);
1645 log_link_warning_errno(link
, r
, "Failed to configure expiration timer for route, ignoring: %m");
1647 log_route_debug(route
, "Configured expiration timer for", link
, manager
);
1649 } else if (!manager
->manage_foreign_routes
) {
1650 route_enter_configured(tmp
);
1651 log_route_debug(tmp
, "Ignoring received", link
, manager
);
1654 /* A route appeared that we did not request */
1655 route_enter_configured(tmp
);
1656 log_route_debug(tmp
, "Received new", link
, manager
);
1657 r
= route_add(manager
, link
, tmp
);
1659 log_link_warning_errno(link
, r
, "Failed to remember foreign route, ignoring: %m");
1669 route_enter_removed(route
);
1670 if (route
->state
== 0) {
1671 log_route_debug(route
, "Forgetting", link
, manager
);
1674 log_route_debug(route
, "Removed", link
, manager
);
1676 log_route_debug(tmp
,
1677 manager
->manage_foreign_routes
? "Kernel removed unknown" : "Ignoring received",
1683 assert_not_reached();
1687 r
= dhcp4_update_ipv6_connectivity(link
);
1689 log_link_warning_errno(link
, r
, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");
1690 link_enter_failed(link
);
1697 int manager_rtnl_process_route(sd_netlink
*rtnl
, sd_netlink_message
*message
, Manager
*m
) {
1698 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
1699 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1700 _cleanup_free_
void *rta_multipath
= NULL
;
1701 struct rta_cacheinfo cacheinfo
;
1713 if (sd_netlink_message_is_error(message
)) {
1714 r
= sd_netlink_message_get_errno(message
);
1716 log_message_warning_errno(message
, r
, "rtnl: failed to receive route message, ignoring");
1721 r
= sd_netlink_message_get_type(message
, &type
);
1723 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
1725 } else if (!IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
)) {
1726 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type
);
1730 r
= sd_netlink_message_read_u32(message
, RTA_OIF
, &ifindex
);
1731 if (r
< 0 && r
!= -ENODATA
) {
1732 log_warning_errno(r
, "rtnl: could not get ifindex from route message, ignoring: %m");
1734 } else if (r
>= 0) {
1736 log_warning("rtnl: received route message with invalid ifindex %u, ignoring.", ifindex
);
1740 r
= link_get_by_index(m
, ifindex
, &link
);
1742 /* when enumerating we might be out of sync, but we will
1743 * get the route again, so just ignore it */
1744 if (!m
->enumerating
)
1745 log_warning("rtnl: received route message for link (%u) we do not know about, ignoring", ifindex
);
1750 r
= route_new(&tmp
);
1754 r
= sd_rtnl_message_route_get_family(message
, &tmp
->family
);
1756 log_link_warning(link
, "rtnl: received route message without family, ignoring");
1758 } else if (!IN_SET(tmp
->family
, AF_INET
, AF_INET6
)) {
1759 log_link_debug(link
, "rtnl: received route message with invalid family '%i', ignoring", tmp
->family
);
1763 r
= sd_rtnl_message_route_get_protocol(message
, &tmp
->protocol
);
1765 log_warning_errno(r
, "rtnl: received route message without route protocol, ignoring: %m");
1769 r
= sd_rtnl_message_route_get_flags(message
, &tmp
->flags
);
1771 log_warning_errno(r
, "rtnl: received route message without route flags, ignoring: %m");
1775 r
= netlink_message_read_in_addr_union(message
, RTA_DST
, tmp
->family
, &tmp
->dst
);
1776 if (r
< 0 && r
!= -ENODATA
) {
1777 log_link_warning_errno(link
, r
, "rtnl: received route message without valid destination, ignoring: %m");
1781 r
= netlink_message_read_in_addr_union(message
, RTA_GATEWAY
, tmp
->family
, &tmp
->gw
);
1782 if (r
< 0 && r
!= -ENODATA
) {
1783 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1786 tmp
->gw_family
= tmp
->family
;
1787 else if (tmp
->family
== AF_INET
) {
1790 r
= sd_netlink_message_read(message
, RTA_VIA
, sizeof(via
), &via
);
1791 if (r
< 0 && r
!= -ENODATA
) {
1792 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1794 } else if (r
>= 0) {
1795 tmp
->gw_family
= via
.family
;
1796 tmp
->gw
= via
.address
;
1800 r
= netlink_message_read_in_addr_union(message
, RTA_SRC
, tmp
->family
, &tmp
->src
);
1801 if (r
< 0 && r
!= -ENODATA
) {
1802 log_link_warning_errno(link
, r
, "rtnl: received route message without valid source, ignoring: %m");
1806 r
= netlink_message_read_in_addr_union(message
, RTA_PREFSRC
, tmp
->family
, &tmp
->prefsrc
);
1807 if (r
< 0 && r
!= -ENODATA
) {
1808 log_link_warning_errno(link
, r
, "rtnl: received route message without valid preferred source, ignoring: %m");
1812 r
= sd_rtnl_message_route_get_dst_prefixlen(message
, &tmp
->dst_prefixlen
);
1814 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1818 r
= sd_rtnl_message_route_get_src_prefixlen(message
, &tmp
->src_prefixlen
);
1820 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1824 r
= sd_rtnl_message_route_get_scope(message
, &tmp
->scope
);
1826 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid scope, ignoring: %m");
1830 r
= sd_rtnl_message_route_get_tos(message
, &tmp
->tos
);
1832 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid tos, ignoring: %m");
1836 r
= sd_rtnl_message_route_get_type(message
, &tmp
->type
);
1838 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid type, ignoring: %m");
1842 r
= sd_netlink_message_read_u32(message
, RTA_TABLE
, &tmp
->table
);
1843 if (r
== -ENODATA
) {
1844 unsigned char table
;
1846 r
= sd_rtnl_message_route_get_table(message
, &table
);
1851 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid table, ignoring: %m");
1855 r
= sd_netlink_message_read_u32(message
, RTA_PRIORITY
, &tmp
->priority
);
1856 if (r
< 0 && r
!= -ENODATA
) {
1857 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid priority, ignoring: %m");
1861 r
= sd_netlink_message_read_u32(message
, RTA_NH_ID
, &tmp
->nexthop_id
);
1862 if (r
< 0 && r
!= -ENODATA
) {
1863 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid nexthop id, ignoring: %m");
1867 r
= sd_netlink_message_enter_container(message
, RTA_METRICS
);
1868 if (r
< 0 && r
!= -ENODATA
) {
1869 log_link_error_errno(link
, r
, "rtnl: Could not enter RTA_METRICS container, ignoring: %m");
1873 r
= sd_netlink_message_read_u32(message
, RTAX_INITCWND
, &tmp
->initcwnd
);
1874 if (r
< 0 && r
!= -ENODATA
) {
1875 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initcwnd, ignoring: %m");
1879 r
= sd_netlink_message_read_u32(message
, RTAX_INITRWND
, &tmp
->initrwnd
);
1880 if (r
< 0 && r
!= -ENODATA
) {
1881 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initrwnd, ignoring: %m");
1885 r
= sd_netlink_message_read_u32(message
, RTAX_ADVMSS
, &tmp
->advmss
);
1886 if (r
< 0 && r
!= -ENODATA
) {
1887 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid advmss, ignoring: %m");
1891 r
= sd_netlink_message_exit_container(message
);
1893 log_link_error_errno(link
, r
, "rtnl: Could not exit from RTA_METRICS container, ignoring: %m");
1898 r
= sd_netlink_message_read_data(message
, RTA_MULTIPATH
, &rta_len
, &rta_multipath
);
1899 if (r
< 0 && r
!= -ENODATA
) {
1900 log_link_warning_errno(link
, r
, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
1902 } else if (r
>= 0) {
1903 r
= rtattr_read_nexthop(rta_multipath
, rta_len
, tmp
->family
, &tmp
->multipath_routes
);
1905 log_link_warning_errno(link
, r
, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
1910 r
= sd_netlink_message_read(message
, RTA_CACHEINFO
, sizeof(cacheinfo
), &cacheinfo
);
1911 if (r
< 0 && r
!= -ENODATA
) {
1912 log_link_warning_errno(link
, r
, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1915 has_cacheinfo
= r
>= 0;
1917 /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
1918 * fib6_nh_init() in net/ipv6/route.c. However, we'd like to manage them by Manager. Hence, set
1919 * link to NULL here. */
1920 if (route_type_is_reject(tmp
))
1923 if (!route_needs_convert(tmp
))
1924 return process_route_one(m
, link
, type
, TAKE_PTR(tmp
), has_cacheinfo
? &cacheinfo
: NULL
);
1926 r
= route_convert(m
, tmp
, &converted
);
1928 log_link_warning_errno(link
, r
, "rtnl: failed to convert received route, ignoring: %m");
1935 for (size_t i
= 0; i
< converted
->n
; i
++)
1936 (void) process_route_one(m
,
1937 converted
->links
[i
] ?: link
,
1939 TAKE_PTR(converted
->routes
[i
]),
1940 has_cacheinfo
? &cacheinfo
: NULL
);
1945 int network_add_ipv4ll_route(Network
*network
) {
1946 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
1947 unsigned section_line
;
1952 if (!network
->ipv4ll_route
)
1955 r
= hashmap_by_section_find_unused_line(network
->routes_by_section
, network
->filename
, §ion_line
);
1959 /* IPv4LLRoute= is in [Network] section. */
1960 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
1964 r
= in_addr_from_string(AF_INET
, "169.254.0.0", &n
->dst
);
1968 n
->family
= AF_INET
;
1969 n
->dst_prefixlen
= 16;
1970 n
->scope
= RT_SCOPE_LINK
;
1971 n
->scope_set
= true;
1972 n
->table_set
= true;
1973 n
->priority
= IPV4LL_ROUTE_METRIC
;
1974 n
->protocol
= RTPROT_STATIC
;
1980 int network_add_default_route_on_device(Network
*network
) {
1981 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
1982 unsigned section_line
;
1987 if (!network
->default_route_on_device
)
1990 r
= hashmap_by_section_find_unused_line(network
->routes_by_section
, network
->filename
, §ion_line
);
1994 /* DefaultRouteOnDevice= is in [Network] section. */
1995 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
1999 n
->family
= AF_INET
;
2000 n
->scope
= RT_SCOPE_LINK
;
2001 n
->scope_set
= true;
2002 n
->protocol
= RTPROT_STATIC
;
2008 int config_parse_gateway(
2010 const char *filename
,
2012 const char *section
,
2013 unsigned section_line
,
2020 Network
*network
= userdata
;
2021 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2030 if (streq(section
, "Network")) {
2031 /* we are not in an Route section, so use line number instead */
2032 r
= route_new_static(network
, filename
, line
, &n
);
2036 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2037 "Failed to allocate route, ignoring assignment: %m");
2041 r
= route_new_static(network
, filename
, section_line
, &n
);
2045 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2046 "Failed to allocate route, ignoring assignment: %m");
2050 if (isempty(rvalue
)) {
2051 n
->gateway_from_dhcp_or_ra
= false;
2052 n
->gw_family
= AF_UNSPEC
;
2053 n
->gw
= IN_ADDR_NULL
;
2058 if (streq(rvalue
, "_dhcp")) {
2059 n
->gateway_from_dhcp_or_ra
= true;
2064 if (streq(rvalue
, "_dhcp4")) {
2065 n
->gw_family
= AF_INET
;
2066 n
->gateway_from_dhcp_or_ra
= true;
2071 if (streq(rvalue
, "_ipv6ra")) {
2072 n
->gw_family
= AF_INET6
;
2073 n
->gateway_from_dhcp_or_ra
= true;
2079 r
= in_addr_from_string_auto(rvalue
, &n
->gw_family
, &n
->gw
);
2081 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2082 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2086 n
->gateway_from_dhcp_or_ra
= false;
2091 int config_parse_preferred_src(
2093 const char *filename
,
2095 const char *section
,
2096 unsigned section_line
,
2103 Network
*network
= userdata
;
2104 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2113 r
= route_new_static(network
, filename
, section_line
, &n
);
2117 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2118 "Failed to allocate route, ignoring assignment: %m");
2122 if (n
->family
== AF_UNSPEC
)
2123 r
= in_addr_from_string_auto(rvalue
, &n
->family
, &n
->prefsrc
);
2125 r
= in_addr_from_string(n
->family
, rvalue
, &n
->prefsrc
);
2127 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2128 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2136 int config_parse_destination(
2138 const char *filename
,
2140 const char *section
,
2141 unsigned section_line
,
2148 Network
*network
= userdata
;
2149 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2150 union in_addr_union
*buffer
;
2151 unsigned char *prefixlen
;
2160 r
= route_new_static(network
, filename
, section_line
, &n
);
2164 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2165 "Failed to allocate route, ignoring assignment: %m");
2169 if (streq(lvalue
, "Destination")) {
2171 prefixlen
= &n
->dst_prefixlen
;
2172 } else if (streq(lvalue
, "Source")) {
2174 prefixlen
= &n
->src_prefixlen
;
2176 assert_not_reached();
2178 if (n
->family
== AF_UNSPEC
)
2179 r
= in_addr_prefix_from_string_auto(rvalue
, &n
->family
, buffer
, prefixlen
);
2181 r
= in_addr_prefix_from_string(rvalue
, n
->family
, buffer
, prefixlen
);
2183 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2184 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2188 (void) in_addr_mask(n
->family
, buffer
, *prefixlen
);
2194 int config_parse_route_priority(
2196 const char *filename
,
2198 const char *section
,
2199 unsigned section_line
,
2206 Network
*network
= userdata
;
2207 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2216 r
= route_new_static(network
, filename
, section_line
, &n
);
2220 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2221 "Failed to allocate route, ignoring assignment: %m");
2225 r
= safe_atou32(rvalue
, &n
->priority
);
2227 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2228 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue
);
2232 n
->priority_set
= true;
2237 int config_parse_route_scope(
2239 const char *filename
,
2241 const char *section
,
2242 unsigned section_line
,
2249 Network
*network
= userdata
;
2250 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2259 r
= route_new_static(network
, filename
, section_line
, &n
);
2263 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2264 "Failed to allocate route, ignoring assignment: %m");
2268 r
= route_scope_from_string(rvalue
);
2270 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Unknown route scope: %s", rvalue
);
2275 n
->scope_set
= true;
2280 int config_parse_route_nexthop(
2282 const char *filename
,
2284 const char *section
,
2285 unsigned section_line
,
2292 Network
*network
= userdata
;
2293 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2303 r
= route_new_static(network
, filename
, section_line
, &n
);
2307 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2308 "Failed to allocate route, ignoring assignment: %m");
2312 if (isempty(rvalue
)) {
2318 r
= safe_atou32(rvalue
, &id
);
2320 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue
);
2324 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue
);
2333 int config_parse_route_table(
2335 const char *filename
,
2337 const char *section
,
2338 unsigned section_line
,
2345 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2346 Network
*network
= userdata
;
2355 r
= route_new_static(network
, filename
, section_line
, &n
);
2359 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2360 "Failed to allocate route, ignoring assignment: %m");
2364 r
= manager_get_route_table_from_string(network
->manager
, rvalue
, &n
->table
);
2366 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2367 "Could not parse route table \"%s\", ignoring assignment: %m", rvalue
);
2371 n
->table_set
= true;
2376 int config_parse_route_boolean(
2378 const char *filename
,
2380 const char *section
,
2381 unsigned section_line
,
2388 Network
*network
= userdata
;
2389 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2398 r
= route_new_static(network
, filename
, section_line
, &n
);
2402 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2403 "Failed to allocate route, ignoring assignment: %m");
2407 r
= parse_boolean(rvalue
);
2409 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2410 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2414 if (STR_IN_SET(lvalue
, "GatewayOnLink", "GatewayOnlink"))
2415 n
->gateway_onlink
= r
;
2416 else if (streq(lvalue
, "QuickAck"))
2418 else if (streq(lvalue
, "FastOpenNoCookie"))
2419 n
->fast_open_no_cookie
= r
;
2420 else if (streq(lvalue
, "TTLPropagate"))
2421 n
->ttl_propagate
= r
;
2423 assert_not_reached();
2429 int config_parse_ipv6_route_preference(
2431 const char *filename
,
2433 const char *section
,
2434 unsigned section_line
,
2441 Network
*network
= userdata
;
2442 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2445 r
= route_new_static(network
, filename
, section_line
, &n
);
2449 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2450 "Failed to allocate route, ignoring assignment: %m");
2454 if (streq(rvalue
, "low"))
2455 n
->pref
= ICMPV6_ROUTER_PREF_LOW
;
2456 else if (streq(rvalue
, "medium"))
2457 n
->pref
= ICMPV6_ROUTER_PREF_MEDIUM
;
2458 else if (streq(rvalue
, "high"))
2459 n
->pref
= ICMPV6_ROUTER_PREF_HIGH
;
2461 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown route preference: %s", rvalue
);
2470 int config_parse_route_protocol(
2472 const char *filename
,
2474 const char *section
,
2475 unsigned section_line
,
2482 Network
*network
= userdata
;
2483 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2486 r
= route_new_static(network
, filename
, section_line
, &n
);
2490 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2491 "Failed to allocate route, ignoring assignment: %m");
2495 r
= route_protocol_from_string(rvalue
);
2497 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2498 "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue
);
2508 int config_parse_route_type(
2510 const char *filename
,
2512 const char *section
,
2513 unsigned section_line
,
2520 Network
*network
= userdata
;
2521 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2524 r
= route_new_static(network
, filename
, section_line
, &n
);
2528 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2529 "Failed to allocate route, ignoring assignment: %m");
2533 t
= route_type_from_string(rvalue
);
2535 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2536 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue
);
2540 n
->type
= (unsigned char) t
;
2546 int config_parse_route_hop_limit(
2548 const char *filename
,
2550 const char *section
,
2551 unsigned section_line
,
2558 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2559 Network
*network
= userdata
;
2569 r
= route_new_static(network
, filename
, section_line
, &n
);
2573 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2574 "Failed to allocate route, ignoring assignment: %m");
2578 if (isempty(rvalue
)) {
2584 r
= safe_atou32(rvalue
, &k
);
2586 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2587 "Could not parse per route hop limit, ignoring assignment: %s", rvalue
);
2591 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2592 "Specified per route hop limit \"%s\" is too large, ignoring assignment: %m", rvalue
);
2596 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2597 "Invalid per route hop limit \"%s\", ignoring assignment: %m", rvalue
);
2607 int config_parse_tcp_congestion(
2609 const char *filename
,
2611 const char *section
,
2612 unsigned section_line
,
2619 Network
*network
= userdata
;
2620 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2629 r
= route_new_static(network
, filename
, section_line
, &n
);
2633 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2634 "Failed to allocate route, ignoring assignment: %m");
2638 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2639 rvalue
, &n
->tcp_congestion_control_algo
, userdata
);
2647 int config_parse_tcp_advmss(
2649 const char *filename
,
2651 const char *section
,
2652 unsigned section_line
,
2659 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2660 Network
*network
= userdata
;
2670 r
= route_new_static(network
, filename
, section_line
, &n
);
2674 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2675 "Failed to allocate route, ignoring assignment: %m");
2679 if (isempty(rvalue
)) {
2685 r
= parse_size(rvalue
, 1024, &u
);
2687 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2688 "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2692 if (u
== 0 || u
> UINT32_MAX
) {
2693 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2694 "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2704 int config_parse_tcp_window(
2706 const char *filename
,
2708 const char *section
,
2709 unsigned section_line
,
2716 uint32_t *window
= ASSERT_PTR(data
);
2726 r
= safe_atou32(rvalue
, &k
);
2728 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2729 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2733 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2734 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue
, rvalue
);
2738 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2739 "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2747 int config_parse_route_tcp_window(
2749 const char *filename
,
2751 const char *section
,
2752 unsigned section_line
,
2759 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2760 Network
*network
= userdata
;
2770 r
= route_new_static(network
, filename
, section_line
, &n
);
2774 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2775 "Failed to allocate route, ignoring assignment: %m");
2779 if (streq(lvalue
, "InitialCongestionWindow"))
2781 else if (streq(lvalue
, "InitialAdvertisedReceiveWindow"))
2784 assert_not_reached();
2786 r
= config_parse_tcp_window(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, d
, userdata
);
2794 int config_parse_route_mtu(
2796 const char *filename
,
2798 const char *section
,
2799 unsigned section_line
,
2806 Network
*network
= userdata
;
2807 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2816 r
= route_new_static(network
, filename
, section_line
, &n
);
2820 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2821 "Failed to allocate route, ignoring assignment: %m");
2825 r
= config_parse_mtu(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &n
->mtu
, userdata
);
2833 int config_parse_route_tcp_rto(
2835 const char *filename
,
2837 const char *section
,
2838 unsigned section_line
,
2845 Network
*network
= userdata
;
2846 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2856 r
= route_new_static(network
, filename
, section_line
, &n
);
2860 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2861 "Failed to allocate route, ignoring assignment: %m");
2865 r
= parse_sec(rvalue
, &usec
);
2867 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2868 "Failed to parse route TCP retransmission timeout (RTO), ignoring assignment: %s", rvalue
);
2872 if (IN_SET(usec
, 0, USEC_INFINITY
) ||
2873 DIV_ROUND_UP(usec
, USEC_PER_MSEC
) > UINT32_MAX
) {
2874 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2875 "Route TCP retransmission timeout (RTO) must be in the range 0…%"PRIu32
"ms, ignoring assignment: %s", UINT32_MAX
, rvalue
);
2879 n
->tcp_rto_usec
= usec
;
2885 int config_parse_multipath_route(
2887 const char *filename
,
2889 const char *section
,
2890 unsigned section_line
,
2897 _cleanup_(multipath_route_freep
) MultipathRoute
*m
= NULL
;
2898 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2899 _cleanup_free_
char *word
= NULL
;
2900 Network
*network
= userdata
;
2901 union in_addr_union a
;
2912 r
= route_new_static(network
, filename
, section_line
, &n
);
2916 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2917 "Failed to allocate route, ignoring assignment: %m");
2921 if (isempty(rvalue
)) {
2922 n
->multipath_routes
= ordered_set_free_with_destructor(n
->multipath_routes
, multipath_route_free
);
2926 m
= new0(MultipathRoute
, 1);
2931 r
= extract_first_word(&p
, &word
, NULL
, 0);
2935 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2936 "Invalid multipath route option, ignoring assignment: %s", rvalue
);
2940 dev
= strchr(word
, '@');
2944 r
= parse_ifindex(dev
);
2948 if (!ifname_valid_full(dev
, IFNAME_VALID_ALTERNATIVE
)) {
2949 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2950 "Invalid interface name '%s' in %s=, ignoring: %s", dev
, lvalue
, rvalue
);
2954 m
->ifname
= strdup(dev
);
2960 r
= in_addr_from_string_auto(word
, &family
, &a
);
2962 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2963 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue
);
2966 m
->gateway
.address
= a
;
2967 m
->gateway
.family
= family
;
2970 r
= safe_atou32(p
, &m
->weight
);
2972 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2973 "Invalid multipath route weight, ignoring assignment: %s", p
);
2976 /* ip command takes weight in the range 1…255, while kernel takes the value in the
2977 * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip
2978 * command uses, then networkd decreases by one and stores it to match the range which
2980 if (m
->weight
== 0 || m
->weight
> 256) {
2981 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2982 "Invalid multipath route weight, ignoring assignment: %s", p
);
2988 r
= ordered_set_ensure_put(&n
->multipath_routes
, NULL
, m
);
2992 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2993 "Failed to store multipath route, ignoring assignment: %m");
3002 static int route_section_verify(Route
*route
, Network
*network
) {
3003 if (section_is_invalid(route
->section
))
3006 /* Currently, we do not support static route with finite lifetime. */
3007 assert(route
->lifetime_usec
== USEC_INFINITY
);
3009 if (route
->gateway_from_dhcp_or_ra
) {
3010 if (route
->gw_family
== AF_UNSPEC
) {
3011 /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
3012 switch (route
->family
) {
3014 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3015 "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
3016 route
->section
->filename
, route
->section
->line
);
3017 route
->family
= AF_INET
;
3021 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3022 "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
3023 route
->section
->filename
, route
->section
->line
, route
->family
== AF_INET
? "_dhcp4" : "_ipv6ra");
3026 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3027 "%s: Invalid route family. Ignoring [Route] section from line %u.",
3028 route
->section
->filename
, route
->section
->line
);
3030 route
->gw_family
= route
->family
;
3033 if (route
->gw_family
== AF_INET
&& !FLAGS_SET(network
->dhcp
, ADDRESS_FAMILY_IPV4
))
3034 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3035 "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
3036 "Ignoring [Route] section from line %u.",
3037 route
->section
->filename
, route
->section
->line
);
3039 if (route
->gw_family
== AF_INET6
&& !network
->ipv6_accept_ra
)
3040 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3041 "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
3042 "Ignoring [Route] section from line %u.",
3043 route
->section
->filename
, route
->section
->line
);
3046 /* When only Gateway= is specified, assume the route family based on the Gateway address. */
3047 if (route
->family
== AF_UNSPEC
)
3048 route
->family
= route
->gw_family
;
3050 if (route
->family
== AF_UNSPEC
) {
3051 assert(route
->section
);
3053 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3054 "%s: Route section without Gateway=, Destination=, Source=, "
3055 "or PreferredSource= field configured. "
3056 "Ignoring [Route] section from line %u.",
3057 route
->section
->filename
, route
->section
->line
);
3060 if (route
->family
== AF_INET6
&& route
->gw_family
== AF_INET
)
3061 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3062 "%s: IPv4 gateway is configured for IPv6 route. "
3063 "Ignoring [Route] section from line %u.",
3064 route
->section
->filename
, route
->section
->line
);
3066 if (!route
->table_set
&& network
->vrf
) {
3067 route
->table
= VRF(network
->vrf
)->table
;
3068 route
->table_set
= true;
3071 if (!route
->table_set
&& IN_SET(route
->type
, RTN_LOCAL
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_NAT
))
3072 route
->table
= RT_TABLE_LOCAL
;
3074 if (!route
->scope_set
&& route
->family
!= AF_INET6
) {
3075 if (IN_SET(route
->type
, RTN_LOCAL
, RTN_NAT
))
3076 route
->scope
= RT_SCOPE_HOST
;
3077 else if (IN_SET(route
->type
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_MULTICAST
))
3078 route
->scope
= RT_SCOPE_LINK
;
3079 else if (IN_SET(route
->type
, RTN_UNICAST
, RTN_UNSPEC
) &&
3080 !route
->gateway_from_dhcp_or_ra
&&
3081 !in_addr_is_set(route
->gw_family
, &route
->gw
) &&
3082 ordered_set_isempty(route
->multipath_routes
) &&
3083 route
->nexthop_id
== 0)
3084 route
->scope
= RT_SCOPE_LINK
;
3087 if (route
->scope
!= RT_SCOPE_UNIVERSE
&& route
->family
== AF_INET6
) {
3088 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route
->section
->filename
);
3089 route
->scope
= RT_SCOPE_UNIVERSE
;
3092 if (route
->family
== AF_INET6
&& route
->priority
== 0)
3093 route
->priority
= IP6_RT_PRIO_USER
;
3095 if (route
->gateway_onlink
< 0 && in_addr_is_set(route
->gw_family
, &route
->gw
) &&
3096 ordered_hashmap_isempty(network
->addresses_by_section
)) {
3097 /* If no address is configured, in most cases the gateway cannot be reachable.
3098 * TODO: we may need to improve the condition above. */
3099 log_warning("%s: Gateway= without static address configured. "
3100 "Enabling GatewayOnLink= option.",
3102 route
->gateway_onlink
= true;
3105 if (route
->gateway_onlink
>= 0)
3106 SET_FLAG(route
->flags
, RTNH_F_ONLINK
, route
->gateway_onlink
);
3108 if (route
->family
== AF_INET6
) {
3111 ORDERED_SET_FOREACH(m
, route
->multipath_routes
)
3112 if (m
->gateway
.family
== AF_INET
)
3113 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3114 "%s: IPv4 multipath route is specified for IPv6 route. "
3115 "Ignoring [Route] section from line %u.",
3116 route
->section
->filename
, route
->section
->line
);
3119 if ((route
->gateway_from_dhcp_or_ra
||
3120 in_addr_is_set(route
->gw_family
, &route
->gw
)) &&
3121 !ordered_set_isempty(route
->multipath_routes
))
3122 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3123 "%s: Gateway= cannot be specified with MultiPathRoute=. "
3124 "Ignoring [Route] section from line %u.",
3125 route
->section
->filename
, route
->section
->line
);
3127 if (route
->nexthop_id
> 0 &&
3128 (route
->gateway_from_dhcp_or_ra
||
3129 in_addr_is_set(route
->gw_family
, &route
->gw
) ||
3130 !ordered_set_isempty(route
->multipath_routes
)))
3131 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3132 "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
3133 "Ignoring [Route] section from line %u.",
3134 route
->section
->filename
, route
->section
->line
);
3139 void network_drop_invalid_routes(Network
*network
) {
3144 HASHMAP_FOREACH(route
, network
->routes_by_section
)
3145 if (route_section_verify(route
, network
) < 0)