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,
43 *ret
= TAKE_PTR(route
);
48 static int route_new_static(Network
*network
, const char *filename
, unsigned section_line
, Route
**ret
) {
49 _cleanup_(config_section_freep
) ConfigSection
*n
= NULL
;
50 _cleanup_(route_freep
) Route
*route
= NULL
;
56 assert(section_line
> 0);
58 r
= config_section_new(filename
, section_line
, &n
);
62 route
= hashmap_get(network
->routes_by_section
, n
);
64 *ret
= TAKE_PTR(route
);
68 if (hashmap_size(network
->routes_by_section
) >= routes_max())
71 r
= route_new(&route
);
75 route
->protocol
= RTPROT_STATIC
;
76 route
->network
= network
;
77 route
->section
= TAKE_PTR(n
);
78 route
->source
= NETWORK_CONFIG_SOURCE_STATIC
;
80 r
= hashmap_ensure_put(&network
->routes_by_section
, &config_section_hash_ops
, route
->section
, route
);
84 *ret
= TAKE_PTR(route
);
88 Route
*route_free(Route
*route
) {
93 assert(route
->section
);
94 hashmap_remove(route
->network
->routes_by_section
, route
->section
);
97 config_section_free(route
->section
);
100 set_remove(route
->link
->routes
, route
);
103 set_remove(route
->manager
->routes
, route
);
105 ordered_set_free_with_destructor(route
->multipath_routes
, multipath_route_free
);
107 sd_event_source_disable_unref(route
->expire
);
109 free(route
->tcp_congestion_control_algo
);
114 static void route_hash_func(const Route
*route
, struct siphash
*state
) {
117 siphash24_compress_typesafe(route
->family
, state
);
119 switch (route
->family
) {
122 siphash24_compress_typesafe(route
->dst_prefixlen
, state
);
123 in_addr_hash_func(&route
->dst
, route
->family
, state
);
125 siphash24_compress_typesafe(route
->src_prefixlen
, state
);
126 in_addr_hash_func(&route
->src
, route
->family
, state
);
128 siphash24_compress_typesafe(route
->gw_family
, state
);
129 if (IN_SET(route
->gw_family
, AF_INET
, AF_INET6
)) {
130 in_addr_hash_func(&route
->gw
, route
->gw_family
, state
);
131 siphash24_compress_typesafe(route
->gw_weight
, state
);
134 in_addr_hash_func(&route
->prefsrc
, route
->family
, state
);
136 siphash24_compress_typesafe(route
->tos
, state
);
137 siphash24_compress_typesafe(route
->priority
, state
);
138 siphash24_compress_typesafe(route
->table
, state
);
139 siphash24_compress_typesafe(route
->protocol
, state
);
140 siphash24_compress_typesafe(route
->scope
, state
);
141 siphash24_compress_typesafe(route
->type
, state
);
143 siphash24_compress_typesafe(route
->initcwnd
, state
);
144 siphash24_compress_typesafe(route
->initrwnd
, state
);
146 siphash24_compress_typesafe(route
->advmss
, state
);
147 siphash24_compress_typesafe(route
->nexthop_id
, state
);
151 /* treat any other address family as AF_UNSPEC */
156 static int route_compare_func(const Route
*a
, const Route
*b
) {
159 r
= CMP(a
->family
, b
->family
);
166 r
= CMP(a
->dst_prefixlen
, b
->dst_prefixlen
);
170 r
= memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
174 r
= CMP(a
->src_prefixlen
, b
->src_prefixlen
);
178 r
= memcmp(&a
->src
, &b
->src
, FAMILY_ADDRESS_SIZE(a
->family
));
182 r
= CMP(a
->gw_family
, b
->gw_family
);
186 if (IN_SET(a
->gw_family
, AF_INET
, AF_INET6
)) {
187 r
= memcmp(&a
->gw
, &b
->gw
, FAMILY_ADDRESS_SIZE(a
->family
));
191 r
= CMP(a
->gw_weight
, b
->gw_weight
);
196 r
= memcmp(&a
->prefsrc
, &b
->prefsrc
, FAMILY_ADDRESS_SIZE(a
->family
));
200 r
= CMP(a
->tos
, b
->tos
);
204 r
= CMP(a
->priority
, b
->priority
);
208 r
= CMP(a
->table
, b
->table
);
212 r
= CMP(a
->protocol
, b
->protocol
);
216 r
= CMP(a
->scope
, b
->scope
);
220 r
= CMP(a
->type
, b
->type
);
224 r
= CMP(a
->initcwnd
, b
->initcwnd
);
228 r
= CMP(a
->initrwnd
, b
->initrwnd
);
232 r
= CMP(a
->advmss
, b
->advmss
);
236 r
= CMP(a
->nexthop_id
, b
->nexthop_id
);
242 /* treat any other address family as AF_UNSPEC */
247 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
254 static bool route_type_is_reject(const Route
*route
) {
257 return IN_SET(route
->type
, RTN_UNREACHABLE
, RTN_PROHIBIT
, RTN_BLACKHOLE
, RTN_THROW
);
260 static bool route_needs_convert(const Route
*route
) {
263 return route
->nexthop_id
> 0 || !ordered_set_isempty(route
->multipath_routes
);
266 static int route_add(Manager
*manager
, Link
*link
, Route
*route
) {
271 if (route_type_is_reject(route
)) {
274 r
= set_ensure_put(&manager
->routes
, &route_hash_ops
, route
);
280 route
->manager
= manager
;
284 r
= set_ensure_put(&link
->routes
, &route_hash_ops
, route
);
296 int route_get(Manager
*manager
, Link
*link
, const Route
*in
, Route
**ret
) {
301 if (route_type_is_reject(in
)) {
305 route
= set_get(manager
->routes
, in
);
310 route
= set_get(link
->routes
, in
);
321 int route_dup(const Route
*src
, Route
**ret
) {
322 _cleanup_(route_freep
) Route
*dest
= NULL
;
325 /* This does not copy mulipath routes. */
330 dest
= newdup(Route
, src
, 1);
334 /* Unset all pointers */
335 dest
->network
= NULL
;
336 dest
->section
= NULL
;
338 dest
->manager
= NULL
;
339 dest
->multipath_routes
= NULL
;
341 dest
->tcp_congestion_control_algo
= NULL
;
343 r
= free_and_strdup(&dest
->tcp_congestion_control_algo
, src
->tcp_congestion_control_algo
);
347 *ret
= TAKE_PTR(dest
);
351 static void route_apply_nexthop(Route
*route
, const NextHop
*nh
, uint8_t nh_weight
) {
354 assert(hashmap_isempty(nh
->group
));
356 route
->gw_family
= nh
->family
;
359 if (nh_weight
!= UINT8_MAX
)
360 route
->gw_weight
= nh_weight
;
363 route
->type
= RTN_BLACKHOLE
;
366 static void route_apply_multipath_route(Route
*route
, const MultipathRoute
*m
) {
370 route
->gw_family
= m
->gateway
.family
;
371 route
->gw
= m
->gateway
.address
;
372 route
->gw_weight
= m
->weight
;
375 static int multipath_route_get_link(Manager
*manager
, const MultipathRoute
*m
, Link
**ret
) {
382 r
= link_get_by_name(manager
, m
->ifname
, ret
);
383 return r
< 0 ? r
: 1;
385 } else if (m
->ifindex
> 0) { /* Always ignore ifindex if ifname is set. */
386 r
= link_get_by_index(manager
, m
->ifindex
, ret
);
387 return r
< 0 ? r
: 1;
395 typedef struct ConvertedRoutes
{
401 static ConvertedRoutes
*converted_routes_free(ConvertedRoutes
*c
) {
405 for (size_t i
= 0; i
< c
->n
; i
++)
406 route_free(c
->routes
[i
]);
414 DEFINE_TRIVIAL_CLEANUP_FUNC(ConvertedRoutes
*, converted_routes_free
);
416 static int converted_routes_new(size_t n
, ConvertedRoutes
**ret
) {
417 _cleanup_(converted_routes_freep
) ConvertedRoutes
*c
= NULL
;
418 _cleanup_free_ Route
**routes
= NULL
;
419 _cleanup_free_ Link
**links
= NULL
;
424 routes
= new0(Route
*, n
);
428 links
= new0(Link
*, n
);
432 c
= new(ConvertedRoutes
, 1);
436 *c
= (ConvertedRoutes
) {
438 .routes
= TAKE_PTR(routes
),
439 .links
= TAKE_PTR(links
),
446 static int route_convert(Manager
*manager
, const Route
*route
, ConvertedRoutes
**ret
) {
447 _cleanup_(converted_routes_freep
) ConvertedRoutes
*c
= NULL
;
454 if (!route_needs_convert(route
)) {
459 if (route
->nexthop_id
> 0) {
460 struct nexthop_grp
*nhg
;
463 r
= nexthop_get_by_id(manager
, route
->nexthop_id
, &nh
);
467 if (hashmap_isempty(nh
->group
)) {
468 r
= converted_routes_new(1, &c
);
472 r
= route_dup(route
, &c
->routes
[0]);
476 route_apply_nexthop(c
->routes
[0], nh
, UINT8_MAX
);
477 (void) link_get_by_index(manager
, nh
->ifindex
, c
->links
);
483 r
= converted_routes_new(hashmap_size(nh
->group
), &c
);
488 HASHMAP_FOREACH(nhg
, nh
->group
) {
491 r
= nexthop_get_by_id(manager
, nhg
->id
, &h
);
495 r
= route_dup(route
, &c
->routes
[i
]);
499 route_apply_nexthop(c
->routes
[i
], h
, nhg
->weight
);
500 (void) link_get_by_index(manager
, h
->ifindex
, c
->links
+ i
);
510 assert(!ordered_set_isempty(route
->multipath_routes
));
512 r
= converted_routes_new(ordered_set_size(route
->multipath_routes
), &c
);
518 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
519 r
= route_dup(route
, &c
->routes
[i
]);
523 route_apply_multipath_route(c
->routes
[i
], m
);
525 r
= multipath_route_get_link(manager
, m
, &c
->links
[i
]);
536 void link_mark_routes(Link
*link
, NetworkConfigSource source
) {
541 SET_FOREACH(route
, link
->routes
) {
542 if (route
->source
!= source
)
549 static void log_route_debug(const Route
*route
, const char *str
, const Link
*link
, const Manager
*manager
) {
550 _cleanup_free_
char *state
= NULL
, *gw_alloc
= NULL
, *prefsrc
= NULL
,
551 *table
= NULL
, *scope
= NULL
, *proto
= NULL
, *flags
= NULL
;
552 const char *gw
= NULL
, *dst
, *src
;
558 /* link may be NULL. */
563 (void) network_config_state_to_string_alloc(route
->state
, &state
);
565 dst
= in_addr_is_set(route
->family
, &route
->dst
) || route
->dst_prefixlen
> 0 ?
566 IN_ADDR_PREFIX_TO_STRING(route
->family
, &route
->dst
, route
->dst_prefixlen
) : NULL
;
567 src
= in_addr_is_set(route
->family
, &route
->src
) || route
->src_prefixlen
> 0 ?
568 IN_ADDR_PREFIX_TO_STRING(route
->family
, &route
->src
, route
->src_prefixlen
) : NULL
;
570 if (in_addr_is_set(route
->gw_family
, &route
->gw
)) {
571 (void) in_addr_to_string(route
->gw_family
, &route
->gw
, &gw_alloc
);
573 } else if (route
->gateway_from_dhcp_or_ra
) {
574 if (route
->gw_family
== AF_INET
)
576 else if (route
->gw_family
== AF_INET6
)
581 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
582 _cleanup_free_
char *buf
= NULL
;
583 union in_addr_union a
= m
->gateway
.address
;
585 (void) in_addr_to_string(m
->gateway
.family
, &a
, &buf
);
586 (void) strextend_with_separator(&gw_alloc
, ",", strna(buf
));
588 (void) strextend(&gw_alloc
, "@", m
->ifname
);
589 else if (m
->ifindex
> 0)
590 (void) strextendf(&gw_alloc
, "@%i", m
->ifindex
);
591 /* See comments in config_parse_multipath_route(). */
592 (void) strextendf(&gw_alloc
, ":%"PRIu32
, m
->weight
+ 1);
596 if (in_addr_is_set(route
->family
, &route
->prefsrc
))
597 (void) in_addr_to_string(route
->family
, &route
->prefsrc
, &prefsrc
);
598 (void) route_scope_to_string_alloc(route
->scope
, &scope
);
599 (void) manager_get_route_table_to_string(manager
, route
->table
, /* append_num = */ true, &table
);
600 (void) route_protocol_full_to_string_alloc(route
->protocol
, &proto
);
601 (void) route_flags_to_string_alloc(route
->flags
, &flags
);
604 "%s %s route (%s): dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, "
605 "proto: %s, type: %s, nexthop: %"PRIu32
", priority: %"PRIu32
", flags: %s",
606 str
, strna(network_config_source_to_string(route
->source
)), strna(state
),
607 strna(dst
), strna(src
), strna(gw
), strna(prefsrc
),
608 strna(scope
), strna(table
), strna(proto
),
609 strna(route_type_to_string(route
->type
)),
610 route
->nexthop_id
, route
->priority
, strna(flags
));
613 static int route_set_netlink_message(const Route
*route
, sd_netlink_message
*req
, Link
*link
) {
619 /* link may be NULL */
621 if (in_addr_is_set(route
->gw_family
, &route
->gw
) && route
->nexthop_id
== 0) {
622 if (route
->gw_family
== route
->family
) {
623 r
= netlink_message_append_in_addr_union(req
, RTA_GATEWAY
, route
->gw_family
, &route
->gw
);
628 .family
= route
->gw_family
,
629 .address
= route
->gw
,
632 r
= sd_netlink_message_append_data(req
, RTA_VIA
, &rtvia
, sizeof(rtvia
));
638 if (route
->dst_prefixlen
> 0) {
639 r
= netlink_message_append_in_addr_union(req
, RTA_DST
, route
->family
, &route
->dst
);
643 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
648 if (route
->src_prefixlen
> 0) {
649 r
= netlink_message_append_in_addr_union(req
, RTA_SRC
, route
->family
, &route
->src
);
653 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
658 if (in_addr_is_set(route
->family
, &route
->prefsrc
)) {
659 r
= netlink_message_append_in_addr_union(req
, RTA_PREFSRC
, route
->family
, &route
->prefsrc
);
664 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
668 r
= sd_rtnl_message_route_set_flags(req
, route
->flags
& RTNH_F_ONLINK
);
672 if (route
->table
< 256) {
673 r
= sd_rtnl_message_route_set_table(req
, route
->table
);
677 r
= sd_rtnl_message_route_set_table(req
, RT_TABLE_UNSPEC
);
681 /* Table attribute to allow more than 256. */
682 r
= sd_netlink_message_append_u32(req
, RTA_TABLE
, route
->table
);
687 if (!route_type_is_reject(route
) &&
688 route
->nexthop_id
== 0 &&
689 ordered_set_isempty(route
->multipath_routes
)) {
690 assert(link
); /* Those routes must be attached to a specific link */
692 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
697 if (route
->nexthop_id
> 0) {
698 r
= sd_netlink_message_append_u32(req
, RTA_NH_ID
, route
->nexthop_id
);
703 r
= sd_netlink_message_append_u8(req
, RTA_PREF
, route
->pref
);
707 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->priority
);
714 static int route_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
719 /* link may be NULL. */
721 if (link
&& IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
724 r
= sd_netlink_message_get_errno(m
);
725 if (r
< 0 && r
!= -ESRCH
)
726 log_link_message_warning_errno(link
, m
, r
, "Could not drop route, ignoring");
731 int route_remove(Route
*route
) {
732 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
739 assert(route
->manager
|| (route
->link
&& route
->link
->manager
));
740 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
743 manager
= route
->manager
?: link
->manager
;
745 log_route_debug(route
, "Removing", link
, manager
);
747 r
= sd_rtnl_message_new_route(manager
->rtnl
, &req
,
748 RTM_DELROUTE
, route
->family
,
751 return log_link_error_errno(link
, r
, "Could not create netlink message: %m");
753 if (route
->family
== AF_INET
&& route
->nexthop_id
> 0 && route
->type
== RTN_BLACKHOLE
)
754 /* When IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel
755 * sends RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type
756 * fib_rt_info::type may not be blackhole. Thus, we cannot know the internal value.
757 * Moreover, on route removal, the matching is done with the hidden value if we set
758 * non-zero type in RTM_DELROUTE message. Note, sd_rtnl_message_new_route() sets
759 * RTN_UNICAST by default. So, we need to clear the type here. */
764 r
= sd_rtnl_message_route_set_type(req
, type
);
766 return log_link_error_errno(link
, r
, "Could not set route type: %m");
768 r
= route_set_netlink_message(route
, req
, link
);
770 return log_error_errno(r
, "Could not fill netlink message: %m");
772 r
= netlink_call_async(manager
->rtnl
, NULL
, req
, route_remove_handler
,
773 link
? link_netlink_destroy_callback
: NULL
, link
);
775 return log_link_error_errno(link
, r
, "Could not send netlink message: %m");
779 route_enter_removing(route
);
783 int route_remove_and_drop(Route
*route
) {
787 route_cancel_request(route
, NULL
);
789 if (route_exists(route
))
790 return route_remove(route
);
792 if (route
->state
== 0)
798 static void manager_mark_routes(Manager
*manager
, bool foreign
, const Link
*except
) {
805 /* First, mark all routes. */
806 SET_FOREACH(route
, manager
->routes
) {
807 /* Do not touch routes managed by the kernel. */
808 if (route
->protocol
== RTPROT_KERNEL
)
811 /* When 'foreign' is true, mark only foreign routes, and vice versa. */
812 if (foreign
!= (route
->source
== NETWORK_CONFIG_SOURCE_FOREIGN
))
815 /* Do not touch dynamic routes. They will removed by dhcp_pd_prefix_lost() */
816 if (IN_SET(route
->source
, NETWORK_CONFIG_SOURCE_DHCP4
, NETWORK_CONFIG_SOURCE_DHCP6
))
819 /* Ignore routes not assigned yet or already removed. */
820 if (!route_exists(route
))
826 /* Then, unmark all routes requested by active links. */
827 HASHMAP_FOREACH(link
, manager
->links_by_index
) {
834 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
837 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
838 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
841 r
= route_convert(manager
, route
, &converted
);
845 if (route_get(manager
, NULL
, route
, &existing
) >= 0)
846 route_unmark(existing
);
850 for (size_t i
= 0; i
< converted
->n
; i
++)
851 if (route_get(manager
, NULL
, converted
->routes
[i
], &existing
) >= 0)
852 route_unmark(existing
);
857 static int manager_drop_marked_routes(Manager
*manager
) {
863 SET_FOREACH(route
, manager
->routes
) {
864 if (!route_is_marked(route
))
867 RET_GATHER(r
, route_remove(route
));
873 static bool route_by_kernel(const Route
*route
) {
876 if (route
->protocol
== RTPROT_KERNEL
)
879 /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
880 * multicast with RTPROT_BOOT. Do not touch it. */
881 if (route
->protocol
== RTPROT_BOOT
&&
882 route
->family
== AF_INET6
&&
883 route
->dst_prefixlen
== 8 &&
884 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 }}}))
890 static void link_unmark_wireguard_routes(Link
*link
) {
893 if (!link
->netdev
|| link
->netdev
->kind
!= NETDEV_KIND_WIREGUARD
)
896 Route
*route
, *existing
;
897 Wireguard
*w
= WIREGUARD(link
->netdev
);
899 SET_FOREACH(route
, w
->routes
)
900 if (route_get(NULL
, link
, route
, &existing
) >= 0)
901 route_unmark(existing
);
904 int link_drop_foreign_routes(Link
*link
) {
909 assert(link
->manager
);
910 assert(link
->network
);
912 SET_FOREACH(route
, link
->routes
) {
913 /* do not touch routes managed by the kernel */
914 if (route_by_kernel(route
))
917 /* Do not remove routes we configured. */
918 if (route
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
)
921 /* Ignore routes not assigned yet or already removed. */
922 if (!route_exists(route
))
925 if (route
->protocol
== RTPROT_STATIC
&&
926 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_STATIC
))
929 if (route
->protocol
== RTPROT_DHCP
&&
930 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_DHCP
))
936 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
937 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
940 r
= route_convert(link
->manager
, route
, &converted
);
944 if (route_get(NULL
, link
, route
, &existing
) >= 0)
945 route_unmark(existing
);
949 for (size_t i
= 0; i
< converted
->n
; i
++)
950 if (route_get(NULL
, link
, converted
->routes
[i
], &existing
) >= 0)
951 route_unmark(existing
);
954 link_unmark_wireguard_routes(link
);
957 SET_FOREACH(route
, link
->routes
) {
958 if (!route_is_marked(route
))
961 RET_GATHER(r
, route_remove(route
));
964 manager_mark_routes(link
->manager
, /* foreign = */ true, NULL
);
966 return RET_GATHER(r
, manager_drop_marked_routes(link
->manager
));
969 int link_drop_managed_routes(Link
*link
) {
975 SET_FOREACH(route
, link
->routes
) {
976 /* do not touch routes managed by the kernel */
977 if (route_by_kernel(route
))
980 /* Do not touch routes managed by kernel or other tools. */
981 if (route
->source
== NETWORK_CONFIG_SOURCE_FOREIGN
)
984 if (!route_exists(route
))
987 RET_GATHER(r
, route_remove(route
));
990 manager_mark_routes(link
->manager
, /* foreign = */ false, link
);
992 return RET_GATHER(r
, manager_drop_marked_routes(link
->manager
));
995 void link_foreignize_routes(Link
*link
) {
1000 SET_FOREACH(route
, link
->routes
)
1001 route
->source
= NETWORK_CONFIG_SOURCE_FOREIGN
;
1003 manager_mark_routes(link
->manager
, /* foreign = */ false, link
);
1005 SET_FOREACH(route
, link
->manager
->routes
) {
1006 if (!route_is_marked(route
))
1009 route
->source
= NETWORK_CONFIG_SOURCE_FOREIGN
;
1013 static int route_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1014 Route
*route
= ASSERT_PTR(userdata
);
1018 assert(route
->manager
|| (route
->link
&& route
->link
->manager
));
1020 link
= route
->link
; /* This may be NULL. */
1022 r
= route_remove(route
);
1024 log_link_warning_errno(link
, r
, "Could not remove route: %m");
1026 link_enter_failed(link
);
1032 static int route_setup_timer(Route
*route
, const struct rta_cacheinfo
*cacheinfo
) {
1037 assert(route
->manager
|| (route
->link
&& route
->link
->manager
));
1039 manager
= route
->manager
?: route
->link
->manager
;
1041 if (route
->lifetime_usec
== USEC_INFINITY
)
1044 if (cacheinfo
&& cacheinfo
->rta_expires
!= 0)
1045 /* Assume that non-zero rta_expires means kernel will handle the route expiration. */
1048 r
= event_reset_time(manager
->event
, &route
->expire
, CLOCK_BOOTTIME
,
1049 route
->lifetime_usec
, 0, route_expire_handler
, route
, 0, "route-expiration", true);
1056 static int append_nexthop_one(const Link
*link
, const Route
*route
, const MultipathRoute
*m
, struct rtattr
**rta
, size_t offset
) {
1057 struct rtnexthop
*rtnh
;
1058 struct rtattr
*new_rta
;
1066 new_rta
= realloc(*rta
, RTA_ALIGN((*rta
)->rta_len
) + RTA_SPACE(sizeof(struct rtnexthop
)));
1071 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1072 *rtnh
= (struct rtnexthop
) {
1073 .rtnh_len
= sizeof(*rtnh
),
1074 .rtnh_ifindex
= m
->ifindex
> 0 ? m
->ifindex
: link
->ifindex
,
1075 .rtnh_hops
= m
->weight
,
1078 (*rta
)->rta_len
+= sizeof(struct rtnexthop
);
1080 if (route
->family
== m
->gateway
.family
) {
1081 r
= rtattr_append_attribute(rta
, RTA_GATEWAY
, &m
->gateway
.address
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1084 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1085 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1087 r
= rtattr_append_attribute(rta
, RTA_VIA
, &m
->gateway
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1090 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1091 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1097 (*rta
)->rta_len
-= sizeof(struct rtnexthop
);
1101 static int append_nexthops(const Link
*link
, const Route
*route
, sd_netlink_message
*req
) {
1102 _cleanup_free_
struct rtattr
*rta
= NULL
;
1103 struct rtnexthop
*rtnh
;
1112 if (ordered_set_isempty(route
->multipath_routes
))
1115 rta
= new(struct rtattr
, 1);
1119 *rta
= (struct rtattr
) {
1120 .rta_type
= RTA_MULTIPATH
,
1121 .rta_len
= RTA_LENGTH(0),
1123 offset
= (uint8_t *) RTA_DATA(rta
) - (uint8_t *) rta
;
1125 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1126 r
= append_nexthop_one(link
, route
, m
, &rta
, offset
);
1130 rtnh
= (struct rtnexthop
*)((uint8_t *) rta
+ offset
);
1131 offset
= (uint8_t *) RTNH_NEXT(rtnh
) - (uint8_t *) rta
;
1134 r
= sd_netlink_message_append_data(req
, RTA_MULTIPATH
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
1141 int route_configure_handler_internal(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
, const char *error_msg
) {
1148 r
= sd_netlink_message_get_errno(m
);
1149 if (r
< 0 && r
!= -EEXIST
) {
1150 log_link_message_warning_errno(link
, m
, r
, "Could not set route");
1151 link_enter_failed(link
);
1158 static int route_configure(const Route
*route
, uint32_t lifetime_sec
, Link
*link
, Request
*req
) {
1159 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
1163 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
1165 assert(link
->manager
);
1166 assert(link
->manager
->rtnl
);
1167 assert(link
->ifindex
> 0);
1170 log_route_debug(route
, "Configuring", link
, link
->manager
);
1172 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &m
, RTM_NEWROUTE
, route
->family
, route
->protocol
);
1176 r
= sd_rtnl_message_route_set_type(m
, route
->type
);
1180 r
= route_set_netlink_message(route
, m
, link
);
1184 if (lifetime_sec
!= UINT32_MAX
) {
1185 r
= sd_netlink_message_append_u32(m
, RTA_EXPIRES
, lifetime_sec
);
1190 r
= sd_netlink_message_open_container(m
, RTA_METRICS
);
1194 if (route
->mtu
> 0) {
1195 r
= sd_netlink_message_append_u32(m
, RTAX_MTU
, route
->mtu
);
1200 if (route
->initcwnd
> 0) {
1201 r
= sd_netlink_message_append_u32(m
, RTAX_INITCWND
, route
->initcwnd
);
1206 if (route
->initrwnd
> 0) {
1207 r
= sd_netlink_message_append_u32(m
, RTAX_INITRWND
, route
->initrwnd
);
1212 if (route
->quickack
>= 0) {
1213 r
= sd_netlink_message_append_u32(m
, RTAX_QUICKACK
, route
->quickack
);
1218 if (route
->fast_open_no_cookie
>= 0) {
1219 r
= sd_netlink_message_append_u32(m
, RTAX_FASTOPEN_NO_COOKIE
, route
->fast_open_no_cookie
);
1224 if (route
->advmss
> 0) {
1225 r
= sd_netlink_message_append_u32(m
, RTAX_ADVMSS
, route
->advmss
);
1230 if (!isempty(route
->tcp_congestion_control_algo
)) {
1231 r
= sd_netlink_message_append_string(m
, RTAX_CC_ALGO
, route
->tcp_congestion_control_algo
);
1236 if (route
->hop_limit
> 0) {
1237 r
= sd_netlink_message_append_u32(m
, RTAX_HOPLIMIT
, route
->hop_limit
);
1242 if (route
->tcp_rto_usec
> 0) {
1243 r
= sd_netlink_message_append_u32(m
, RTAX_RTO_MIN
, DIV_ROUND_UP(route
->tcp_rto_usec
, USEC_PER_MSEC
));
1248 r
= sd_netlink_message_close_container(m
);
1252 if (!ordered_set_isempty(route
->multipath_routes
)) {
1253 assert(route
->nexthop_id
== 0);
1254 assert(!in_addr_is_set(route
->gw_family
, &route
->gw
));
1256 r
= append_nexthops(link
, route
, m
);
1261 return request_call_netlink_async(link
->manager
->rtnl
, m
, req
);
1264 static int route_is_ready_to_configure(const Route
*route
, Link
*link
) {
1270 if (!link_is_ready_to_configure(link
, false))
1273 if (set_size(link
->routes
) >= routes_max())
1276 if (route
->nexthop_id
> 0) {
1277 struct nexthop_grp
*nhg
;
1280 if (nexthop_get_by_id(link
->manager
, route
->nexthop_id
, &nh
) < 0)
1283 if (!nexthop_exists(nh
))
1286 HASHMAP_FOREACH(nhg
, nh
->group
) {
1289 if (nexthop_get_by_id(link
->manager
, nhg
->id
, &g
) < 0)
1292 if (!nexthop_exists(g
))
1297 if (in_addr_is_set(route
->family
, &route
->prefsrc
) > 0) {
1298 r
= manager_has_address(link
->manager
, route
->family
, &route
->prefsrc
);
1303 if (!gateway_is_ready(link
, FLAGS_SET(route
->flags
, RTNH_F_ONLINK
), route
->gw_family
, &route
->gw
))
1307 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1308 union in_addr_union a
= m
->gateway
.address
;
1311 r
= multipath_route_get_link(link
->manager
, m
, &l
);
1315 if (!link_is_ready_to_configure(l
, /* allow_unmanaged = */ true) ||
1316 !link_has_carrier(l
))
1319 m
->ifindex
= l
->ifindex
;
1322 if (!gateway_is_ready(l
?: link
, FLAGS_SET(route
->flags
, RTNH_F_ONLINK
), m
->gateway
.family
, &a
))
1329 static int route_process_request(Request
*req
, Link
*link
, Route
*route
) {
1330 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
1335 assert(link
->manager
);
1338 r
= route_is_ready_to_configure(route
, link
);
1340 return log_link_warning_errno(link
, r
, "Failed to check if route is ready to configure: %m");
1344 if (route_needs_convert(route
)) {
1345 r
= route_convert(link
->manager
, route
, &converted
);
1347 return log_link_warning_errno(link
, r
, "Failed to convert route: %m");
1352 for (size_t i
= 0; i
< converted
->n
; i
++) {
1355 if (route_get(link
->manager
, converted
->links
[i
] ?: link
, converted
->routes
[i
], &existing
) < 0) {
1356 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1358 r
= route_dup(converted
->routes
[i
], &tmp
);
1362 r
= route_add(link
->manager
, converted
->links
[i
] ?: link
, tmp
);
1364 return log_link_warning_errno(link
, r
, "Failed to add route: %m");
1368 existing
->source
= converted
->routes
[i
]->source
;
1369 existing
->provider
= converted
->routes
[i
]->provider
;
1375 assert_se(sd_event_now(link
->manager
->event
, CLOCK_BOOTTIME
, &now_usec
) >= 0);
1376 uint32_t sec
= usec_to_sec(route
->lifetime_usec
, now_usec
);
1378 log_link_debug(link
, "Refuse to configure %s route with zero lifetime.",
1379 network_config_source_to_string(route
->source
));
1382 for (size_t i
= 0; i
< converted
->n
; i
++) {
1385 assert_se(route_get(link
->manager
, converted
->links
[i
] ?: link
, converted
->routes
[i
], &existing
) >= 0);
1386 route_cancel_requesting(existing
);
1389 route_cancel_requesting(route
);
1394 r
= route_configure(route
, sec
, link
, req
);
1396 return log_link_warning_errno(link
, r
, "Failed to configure route: %m");
1399 for (size_t i
= 0; i
< converted
->n
; i
++) {
1402 assert_se(route_get(link
->manager
, converted
->links
[i
] ?: link
, converted
->routes
[i
], &existing
) >= 0);
1403 route_enter_configuring(existing
);
1406 route_enter_configuring(route
);
1411 int link_request_route(
1414 bool consume_object
,
1415 unsigned *message_counter
,
1416 route_netlink_handler_t netlink_handler
,
1419 Route
*existing
= NULL
;
1423 assert(link
->manager
);
1425 assert(route
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
);
1426 assert(!route_needs_convert(route
));
1428 (void) route_get(link
->manager
, link
, route
, &existing
);
1430 if (route
->lifetime_usec
== 0) {
1434 /* The requested route is outdated. Let's remove it. */
1435 return route_remove_and_drop(existing
);
1439 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1444 r
= route_dup(route
, &tmp
);
1449 r
= route_add(link
->manager
, link
, tmp
);
1453 existing
= TAKE_PTR(tmp
);
1455 existing
->source
= route
->source
;
1456 existing
->provider
= route
->provider
;
1457 existing
->lifetime_usec
= route
->lifetime_usec
;
1461 if (existing
->expire
) {
1462 /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE
1463 * message, so we need to update the timer here. */
1464 r
= route_setup_timer(existing
, NULL
);
1466 log_link_warning_errno(link
, r
, "Failed to update expiration timer for route, ignoring: %m");
1468 log_route_debug(existing
, "Updated expiration timer for", link
, link
->manager
);
1472 log_route_debug(existing
, "Requesting", link
, link
->manager
);
1473 r
= link_queue_request_safe(link
, REQUEST_TYPE_ROUTE
,
1477 route_process_request
,
1478 message_counter
, netlink_handler
, ret
);
1482 route_enter_requesting(existing
);
1486 static int static_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Route
*route
) {
1491 r
= route_configure_handler_internal(rtnl
, m
, link
, "Could not set route");
1495 if (link
->static_route_messages
== 0) {
1496 log_link_debug(link
, "Routes set");
1497 link
->static_routes_configured
= true;
1498 link_check_ready(link
);
1504 static int link_request_static_route(Link
*link
, Route
*route
) {
1506 assert(link
->manager
);
1509 if (!route_needs_convert(route
))
1510 return link_request_route(link
, route
, false, &link
->static_route_messages
,
1511 static_route_handler
, NULL
);
1513 log_route_debug(route
, "Requesting", link
, link
->manager
);
1514 return link_queue_request_safe(link
, REQUEST_TYPE_ROUTE
,
1515 route
, NULL
, route_hash_func
, route_compare_func
,
1516 route_process_request
,
1517 &link
->static_route_messages
, static_route_handler
, NULL
);
1520 static int link_request_wireguard_routes(Link
*link
, bool only_ipv4
) {
1527 if (!streq_ptr(link
->kind
, "wireguard"))
1530 if (netdev_get(link
->manager
, link
->ifname
, &netdev
) < 0)
1533 Wireguard
*w
= WIREGUARD(netdev
);
1535 SET_FOREACH(route
, w
->routes
) {
1536 if (only_ipv4
&& route
->family
!= AF_INET
)
1539 r
= link_request_static_route(link
, route
);
1547 int link_request_static_routes(Link
*link
, bool only_ipv4
) {
1552 assert(link
->network
);
1554 link
->static_routes_configured
= false;
1556 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
1557 if (route
->gateway_from_dhcp_or_ra
)
1560 if (only_ipv4
&& route
->family
!= AF_INET
)
1563 r
= link_request_static_route(link
, route
);
1568 r
= link_request_wireguard_routes(link
, only_ipv4
);
1572 if (link
->static_route_messages
== 0) {
1573 link
->static_routes_configured
= true;
1574 link_check_ready(link
);
1576 log_link_debug(link
, "Requesting routes");
1577 link_set_state(link
, LINK_STATE_CONFIGURING
);
1583 void route_cancel_request(Route
*route
, Link
*link
) {
1588 link
= route
->link
?: link
;
1592 if (!route_is_requesting(route
))
1597 .type
= REQUEST_TYPE_ROUTE
,
1599 .hash_func
= (hash_func_t
) route_hash_func
,
1600 .compare_func
= (compare_func_t
) route_compare_func
,
1603 request_detach(link
->manager
, &req
);
1604 route_cancel_requesting(route
);
1607 static int process_route_one(
1612 const struct rta_cacheinfo
*cacheinfo
) {
1614 _cleanup_(route_freep
) Route
*tmp
= in
;
1615 Route
*route
= NULL
;
1621 assert(IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
));
1623 /* link may be NULL. This consumes 'in'. */
1625 update_dhcp4
= link
&& tmp
->family
== AF_INET6
&& tmp
->dst_prefixlen
== 0;
1627 (void) route_get(manager
, link
, tmp
, &route
);
1632 route
->flags
= tmp
->flags
;
1633 route_enter_configured(route
);
1634 log_route_debug(route
, "Received remembered", link
, manager
);
1636 r
= route_setup_timer(route
, cacheinfo
);
1638 log_link_warning_errno(link
, r
, "Failed to configure expiration timer for route, ignoring: %m");
1640 log_route_debug(route
, "Configured expiration timer for", link
, manager
);
1642 } else if (!manager
->manage_foreign_routes
) {
1643 route_enter_configured(tmp
);
1644 log_route_debug(tmp
, "Ignoring received", link
, manager
);
1647 /* A route appeared that we did not request */
1648 route_enter_configured(tmp
);
1649 log_route_debug(tmp
, "Received new", link
, manager
);
1650 r
= route_add(manager
, link
, tmp
);
1652 log_link_warning_errno(link
, r
, "Failed to remember foreign route, ignoring: %m");
1662 route_enter_removed(route
);
1663 if (route
->state
== 0) {
1664 log_route_debug(route
, "Forgetting", link
, manager
);
1667 log_route_debug(route
, "Removed", link
, manager
);
1669 log_route_debug(tmp
,
1670 manager
->manage_foreign_routes
? "Kernel removed unknown" : "Ignoring received",
1676 assert_not_reached();
1680 r
= dhcp4_update_ipv6_connectivity(link
);
1682 log_link_warning_errno(link
, r
, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");
1683 link_enter_failed(link
);
1690 int manager_rtnl_process_route(sd_netlink
*rtnl
, sd_netlink_message
*message
, Manager
*m
) {
1691 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
1692 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1693 _cleanup_free_
void *rta_multipath
= NULL
;
1694 struct rta_cacheinfo cacheinfo
;
1706 if (sd_netlink_message_is_error(message
)) {
1707 r
= sd_netlink_message_get_errno(message
);
1709 log_message_warning_errno(message
, r
, "rtnl: failed to receive route message, ignoring");
1714 r
= sd_netlink_message_get_type(message
, &type
);
1716 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
1718 } else if (!IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
)) {
1719 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type
);
1723 r
= sd_netlink_message_read_u32(message
, RTA_OIF
, &ifindex
);
1724 if (r
< 0 && r
!= -ENODATA
) {
1725 log_warning_errno(r
, "rtnl: could not get ifindex from route message, ignoring: %m");
1727 } else if (r
>= 0) {
1729 log_warning("rtnl: received route message with invalid ifindex %u, ignoring.", ifindex
);
1733 r
= link_get_by_index(m
, ifindex
, &link
);
1735 /* when enumerating we might be out of sync, but we will
1736 * get the route again, so just ignore it */
1737 if (!m
->enumerating
)
1738 log_warning("rtnl: received route message for link (%u) we do not know about, ignoring", ifindex
);
1743 r
= route_new(&tmp
);
1747 r
= sd_rtnl_message_route_get_family(message
, &tmp
->family
);
1749 log_link_warning(link
, "rtnl: received route message without family, ignoring");
1751 } else if (!IN_SET(tmp
->family
, AF_INET
, AF_INET6
)) {
1752 log_link_debug(link
, "rtnl: received route message with invalid family '%i', ignoring", tmp
->family
);
1756 r
= sd_rtnl_message_route_get_protocol(message
, &tmp
->protocol
);
1758 log_warning_errno(r
, "rtnl: received route message without route protocol, ignoring: %m");
1762 r
= sd_rtnl_message_route_get_flags(message
, &tmp
->flags
);
1764 log_warning_errno(r
, "rtnl: received route message without route flags, ignoring: %m");
1768 r
= netlink_message_read_in_addr_union(message
, RTA_DST
, tmp
->family
, &tmp
->dst
);
1769 if (r
< 0 && r
!= -ENODATA
) {
1770 log_link_warning_errno(link
, r
, "rtnl: received route message without valid destination, ignoring: %m");
1774 r
= netlink_message_read_in_addr_union(message
, RTA_GATEWAY
, tmp
->family
, &tmp
->gw
);
1775 if (r
< 0 && r
!= -ENODATA
) {
1776 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1779 tmp
->gw_family
= tmp
->family
;
1780 else if (tmp
->family
== AF_INET
) {
1783 r
= sd_netlink_message_read(message
, RTA_VIA
, sizeof(via
), &via
);
1784 if (r
< 0 && r
!= -ENODATA
) {
1785 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1787 } else if (r
>= 0) {
1788 tmp
->gw_family
= via
.family
;
1789 tmp
->gw
= via
.address
;
1793 r
= netlink_message_read_in_addr_union(message
, RTA_SRC
, tmp
->family
, &tmp
->src
);
1794 if (r
< 0 && r
!= -ENODATA
) {
1795 log_link_warning_errno(link
, r
, "rtnl: received route message without valid source, ignoring: %m");
1799 r
= netlink_message_read_in_addr_union(message
, RTA_PREFSRC
, tmp
->family
, &tmp
->prefsrc
);
1800 if (r
< 0 && r
!= -ENODATA
) {
1801 log_link_warning_errno(link
, r
, "rtnl: received route message without valid preferred source, ignoring: %m");
1805 r
= sd_rtnl_message_route_get_dst_prefixlen(message
, &tmp
->dst_prefixlen
);
1807 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1811 r
= sd_rtnl_message_route_get_src_prefixlen(message
, &tmp
->src_prefixlen
);
1813 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1817 r
= sd_rtnl_message_route_get_scope(message
, &tmp
->scope
);
1819 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid scope, ignoring: %m");
1823 r
= sd_rtnl_message_route_get_tos(message
, &tmp
->tos
);
1825 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid tos, ignoring: %m");
1829 r
= sd_rtnl_message_route_get_type(message
, &tmp
->type
);
1831 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid type, ignoring: %m");
1835 r
= sd_netlink_message_read_u32(message
, RTA_TABLE
, &tmp
->table
);
1836 if (r
== -ENODATA
) {
1837 unsigned char table
;
1839 r
= sd_rtnl_message_route_get_table(message
, &table
);
1844 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid table, ignoring: %m");
1848 r
= sd_netlink_message_read_u32(message
, RTA_PRIORITY
, &tmp
->priority
);
1849 if (r
< 0 && r
!= -ENODATA
) {
1850 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid priority, ignoring: %m");
1854 r
= sd_netlink_message_read_u32(message
, RTA_NH_ID
, &tmp
->nexthop_id
);
1855 if (r
< 0 && r
!= -ENODATA
) {
1856 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid nexthop id, ignoring: %m");
1860 r
= sd_netlink_message_enter_container(message
, RTA_METRICS
);
1861 if (r
< 0 && r
!= -ENODATA
) {
1862 log_link_error_errno(link
, r
, "rtnl: Could not enter RTA_METRICS container, ignoring: %m");
1866 r
= sd_netlink_message_read_u32(message
, RTAX_INITCWND
, &tmp
->initcwnd
);
1867 if (r
< 0 && r
!= -ENODATA
) {
1868 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initcwnd, ignoring: %m");
1872 r
= sd_netlink_message_read_u32(message
, RTAX_INITRWND
, &tmp
->initrwnd
);
1873 if (r
< 0 && r
!= -ENODATA
) {
1874 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initrwnd, ignoring: %m");
1878 r
= sd_netlink_message_read_u32(message
, RTAX_ADVMSS
, &tmp
->advmss
);
1879 if (r
< 0 && r
!= -ENODATA
) {
1880 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid advmss, ignoring: %m");
1884 r
= sd_netlink_message_exit_container(message
);
1886 log_link_error_errno(link
, r
, "rtnl: Could not exit from RTA_METRICS container, ignoring: %m");
1891 r
= sd_netlink_message_read_data(message
, RTA_MULTIPATH
, &rta_len
, &rta_multipath
);
1892 if (r
< 0 && r
!= -ENODATA
) {
1893 log_link_warning_errno(link
, r
, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
1895 } else if (r
>= 0) {
1896 r
= rtattr_read_nexthop(rta_multipath
, rta_len
, tmp
->family
, &tmp
->multipath_routes
);
1898 log_link_warning_errno(link
, r
, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
1903 r
= sd_netlink_message_read(message
, RTA_CACHEINFO
, sizeof(cacheinfo
), &cacheinfo
);
1904 if (r
< 0 && r
!= -ENODATA
) {
1905 log_link_warning_errno(link
, r
, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1908 has_cacheinfo
= r
>= 0;
1910 /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
1911 * fib6_nh_init() in net/ipv6/route.c. However, we'd like to manage them by Manager. Hence, set
1912 * link to NULL here. */
1913 if (route_type_is_reject(tmp
))
1916 if (!route_needs_convert(tmp
))
1917 return process_route_one(m
, link
, type
, TAKE_PTR(tmp
), has_cacheinfo
? &cacheinfo
: NULL
);
1919 r
= route_convert(m
, tmp
, &converted
);
1921 log_link_warning_errno(link
, r
, "rtnl: failed to convert received route, ignoring: %m");
1928 for (size_t i
= 0; i
< converted
->n
; i
++)
1929 (void) process_route_one(m
,
1930 converted
->links
[i
] ?: link
,
1932 TAKE_PTR(converted
->routes
[i
]),
1933 has_cacheinfo
? &cacheinfo
: NULL
);
1938 int network_add_ipv4ll_route(Network
*network
) {
1939 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
1940 unsigned section_line
;
1945 if (!network
->ipv4ll_route
)
1948 r
= hashmap_by_section_find_unused_line(network
->routes_by_section
, network
->filename
, §ion_line
);
1952 /* IPv4LLRoute= is in [Network] section. */
1953 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
1957 r
= in_addr_from_string(AF_INET
, "169.254.0.0", &n
->dst
);
1961 n
->family
= AF_INET
;
1962 n
->dst_prefixlen
= 16;
1963 n
->scope
= RT_SCOPE_LINK
;
1964 n
->scope_set
= true;
1965 n
->table_set
= true;
1966 n
->priority
= IPV4LL_ROUTE_METRIC
;
1967 n
->protocol
= RTPROT_STATIC
;
1973 int network_add_default_route_on_device(Network
*network
) {
1974 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
1975 unsigned section_line
;
1980 if (!network
->default_route_on_device
)
1983 r
= hashmap_by_section_find_unused_line(network
->routes_by_section
, network
->filename
, §ion_line
);
1987 /* DefaultRouteOnDevice= is in [Network] section. */
1988 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
1992 n
->family
= AF_INET
;
1993 n
->scope
= RT_SCOPE_LINK
;
1994 n
->scope_set
= true;
1995 n
->protocol
= RTPROT_STATIC
;
2001 int config_parse_gateway(
2003 const char *filename
,
2005 const char *section
,
2006 unsigned section_line
,
2013 Network
*network
= userdata
;
2014 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2023 if (streq(section
, "Network")) {
2024 /* we are not in an Route section, so use line number instead */
2025 r
= route_new_static(network
, filename
, line
, &n
);
2029 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2030 "Failed to allocate route, ignoring assignment: %m");
2034 r
= route_new_static(network
, filename
, section_line
, &n
);
2038 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2039 "Failed to allocate route, ignoring assignment: %m");
2043 if (isempty(rvalue
)) {
2044 n
->gateway_from_dhcp_or_ra
= false;
2045 n
->gw_family
= AF_UNSPEC
;
2046 n
->gw
= IN_ADDR_NULL
;
2051 if (streq(rvalue
, "_dhcp")) {
2052 n
->gateway_from_dhcp_or_ra
= true;
2057 if (streq(rvalue
, "_dhcp4")) {
2058 n
->gw_family
= AF_INET
;
2059 n
->gateway_from_dhcp_or_ra
= true;
2064 if (streq(rvalue
, "_ipv6ra")) {
2065 n
->gw_family
= AF_INET6
;
2066 n
->gateway_from_dhcp_or_ra
= true;
2072 r
= in_addr_from_string_auto(rvalue
, &n
->gw_family
, &n
->gw
);
2074 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2075 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2079 n
->gateway_from_dhcp_or_ra
= false;
2084 int config_parse_preferred_src(
2086 const char *filename
,
2088 const char *section
,
2089 unsigned section_line
,
2096 Network
*network
= userdata
;
2097 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2106 r
= route_new_static(network
, filename
, section_line
, &n
);
2110 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2111 "Failed to allocate route, ignoring assignment: %m");
2115 if (n
->family
== AF_UNSPEC
)
2116 r
= in_addr_from_string_auto(rvalue
, &n
->family
, &n
->prefsrc
);
2118 r
= in_addr_from_string(n
->family
, rvalue
, &n
->prefsrc
);
2120 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2121 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2129 int config_parse_destination(
2131 const char *filename
,
2133 const char *section
,
2134 unsigned section_line
,
2141 Network
*network
= userdata
;
2142 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2143 union in_addr_union
*buffer
;
2144 unsigned char *prefixlen
;
2153 r
= route_new_static(network
, filename
, section_line
, &n
);
2157 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2158 "Failed to allocate route, ignoring assignment: %m");
2162 if (streq(lvalue
, "Destination")) {
2164 prefixlen
= &n
->dst_prefixlen
;
2165 } else if (streq(lvalue
, "Source")) {
2167 prefixlen
= &n
->src_prefixlen
;
2169 assert_not_reached();
2171 if (n
->family
== AF_UNSPEC
)
2172 r
= in_addr_prefix_from_string_auto(rvalue
, &n
->family
, buffer
, prefixlen
);
2174 r
= in_addr_prefix_from_string(rvalue
, n
->family
, buffer
, prefixlen
);
2176 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2177 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2181 (void) in_addr_mask(n
->family
, buffer
, *prefixlen
);
2187 int config_parse_route_priority(
2189 const char *filename
,
2191 const char *section
,
2192 unsigned section_line
,
2199 Network
*network
= userdata
;
2200 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2209 r
= route_new_static(network
, filename
, section_line
, &n
);
2213 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2214 "Failed to allocate route, ignoring assignment: %m");
2218 r
= safe_atou32(rvalue
, &n
->priority
);
2220 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2221 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue
);
2225 n
->priority_set
= true;
2230 int config_parse_route_scope(
2232 const char *filename
,
2234 const char *section
,
2235 unsigned section_line
,
2242 Network
*network
= userdata
;
2243 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2252 r
= route_new_static(network
, filename
, section_line
, &n
);
2256 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2257 "Failed to allocate route, ignoring assignment: %m");
2261 r
= route_scope_from_string(rvalue
);
2263 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Unknown route scope: %s", rvalue
);
2268 n
->scope_set
= true;
2273 int config_parse_route_nexthop(
2275 const char *filename
,
2277 const char *section
,
2278 unsigned section_line
,
2285 Network
*network
= userdata
;
2286 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2296 r
= route_new_static(network
, filename
, section_line
, &n
);
2300 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2301 "Failed to allocate route, ignoring assignment: %m");
2305 if (isempty(rvalue
)) {
2311 r
= safe_atou32(rvalue
, &id
);
2313 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue
);
2317 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue
);
2326 int config_parse_route_table(
2328 const char *filename
,
2330 const char *section
,
2331 unsigned section_line
,
2338 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2339 Network
*network
= userdata
;
2348 r
= route_new_static(network
, filename
, section_line
, &n
);
2352 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2353 "Failed to allocate route, ignoring assignment: %m");
2357 r
= manager_get_route_table_from_string(network
->manager
, rvalue
, &n
->table
);
2359 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2360 "Could not parse route table \"%s\", ignoring assignment: %m", rvalue
);
2364 n
->table_set
= true;
2369 int config_parse_route_boolean(
2371 const char *filename
,
2373 const char *section
,
2374 unsigned section_line
,
2381 Network
*network
= userdata
;
2382 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2391 r
= route_new_static(network
, filename
, section_line
, &n
);
2395 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2396 "Failed to allocate route, ignoring assignment: %m");
2400 r
= parse_boolean(rvalue
);
2402 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2403 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2407 if (STR_IN_SET(lvalue
, "GatewayOnLink", "GatewayOnlink"))
2408 n
->gateway_onlink
= r
;
2409 else if (streq(lvalue
, "QuickAck"))
2411 else if (streq(lvalue
, "FastOpenNoCookie"))
2412 n
->fast_open_no_cookie
= r
;
2414 assert_not_reached();
2420 int config_parse_ipv6_route_preference(
2422 const char *filename
,
2424 const char *section
,
2425 unsigned section_line
,
2432 Network
*network
= userdata
;
2433 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2436 r
= route_new_static(network
, filename
, section_line
, &n
);
2440 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2441 "Failed to allocate route, ignoring assignment: %m");
2445 if (streq(rvalue
, "low"))
2446 n
->pref
= ICMPV6_ROUTER_PREF_LOW
;
2447 else if (streq(rvalue
, "medium"))
2448 n
->pref
= ICMPV6_ROUTER_PREF_MEDIUM
;
2449 else if (streq(rvalue
, "high"))
2450 n
->pref
= ICMPV6_ROUTER_PREF_HIGH
;
2452 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown route preference: %s", rvalue
);
2461 int config_parse_route_protocol(
2463 const char *filename
,
2465 const char *section
,
2466 unsigned section_line
,
2473 Network
*network
= userdata
;
2474 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2477 r
= route_new_static(network
, filename
, section_line
, &n
);
2481 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2482 "Failed to allocate route, ignoring assignment: %m");
2486 r
= route_protocol_from_string(rvalue
);
2488 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2489 "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue
);
2499 int config_parse_route_type(
2501 const char *filename
,
2503 const char *section
,
2504 unsigned section_line
,
2511 Network
*network
= userdata
;
2512 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2515 r
= route_new_static(network
, filename
, section_line
, &n
);
2519 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2520 "Failed to allocate route, ignoring assignment: %m");
2524 t
= route_type_from_string(rvalue
);
2526 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2527 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue
);
2531 n
->type
= (unsigned char) t
;
2537 int config_parse_route_hop_limit(
2539 const char *filename
,
2541 const char *section
,
2542 unsigned section_line
,
2549 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2550 Network
*network
= userdata
;
2560 r
= route_new_static(network
, filename
, section_line
, &n
);
2564 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2565 "Failed to allocate route, ignoring assignment: %m");
2569 if (isempty(rvalue
)) {
2575 r
= safe_atou32(rvalue
, &k
);
2577 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2578 "Could not parse per route hop limit, ignoring assignment: %s", rvalue
);
2582 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2583 "Specified per route hop limit \"%s\" is too large, ignoring assignment: %m", rvalue
);
2587 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2588 "Invalid per route hop limit \"%s\", ignoring assignment: %m", rvalue
);
2598 int config_parse_tcp_congestion(
2600 const char *filename
,
2602 const char *section
,
2603 unsigned section_line
,
2610 Network
*network
= userdata
;
2611 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2620 r
= route_new_static(network
, filename
, section_line
, &n
);
2624 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2625 "Failed to allocate route, ignoring assignment: %m");
2629 r
= config_parse_string(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
,
2630 rvalue
, &n
->tcp_congestion_control_algo
, userdata
);
2638 int config_parse_tcp_advmss(
2640 const char *filename
,
2642 const char *section
,
2643 unsigned section_line
,
2650 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2651 Network
*network
= userdata
;
2661 r
= route_new_static(network
, filename
, section_line
, &n
);
2665 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2666 "Failed to allocate route, ignoring assignment: %m");
2670 if (isempty(rvalue
)) {
2676 r
= parse_size(rvalue
, 1024, &u
);
2678 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2679 "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2683 if (u
== 0 || u
> UINT32_MAX
) {
2684 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2685 "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2695 int config_parse_tcp_window(
2697 const char *filename
,
2699 const char *section
,
2700 unsigned section_line
,
2707 uint32_t *window
= ASSERT_PTR(data
);
2717 r
= safe_atou32(rvalue
, &k
);
2719 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2720 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2724 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2725 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue
, rvalue
);
2729 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2730 "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2738 int config_parse_route_tcp_window(
2740 const char *filename
,
2742 const char *section
,
2743 unsigned section_line
,
2750 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2751 Network
*network
= userdata
;
2761 r
= route_new_static(network
, filename
, section_line
, &n
);
2765 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2766 "Failed to allocate route, ignoring assignment: %m");
2770 if (streq(lvalue
, "InitialCongestionWindow"))
2772 else if (streq(lvalue
, "InitialAdvertisedReceiveWindow"))
2775 assert_not_reached();
2777 r
= config_parse_tcp_window(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, d
, userdata
);
2785 int config_parse_route_mtu(
2787 const char *filename
,
2789 const char *section
,
2790 unsigned section_line
,
2797 Network
*network
= userdata
;
2798 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2807 r
= route_new_static(network
, filename
, section_line
, &n
);
2811 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2812 "Failed to allocate route, ignoring assignment: %m");
2816 r
= config_parse_mtu(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &n
->mtu
, userdata
);
2824 int config_parse_route_tcp_rto(
2826 const char *filename
,
2828 const char *section
,
2829 unsigned section_line
,
2836 Network
*network
= userdata
;
2837 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2847 r
= route_new_static(network
, filename
, section_line
, &n
);
2851 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2852 "Failed to allocate route, ignoring assignment: %m");
2856 r
= parse_sec(rvalue
, &usec
);
2858 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2859 "Failed to parse route TCP retransmission timeout (RTO), ignoring assignment: %s", rvalue
);
2863 if (!timestamp_is_set(usec
) ||
2864 DIV_ROUND_UP(usec
, USEC_PER_MSEC
) > UINT32_MAX
) {
2865 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2866 "Route TCP retransmission timeout (RTO) must be in the range 0…%"PRIu32
"ms, ignoring assignment: %s", UINT32_MAX
, rvalue
);
2870 n
->tcp_rto_usec
= usec
;
2876 int config_parse_multipath_route(
2878 const char *filename
,
2880 const char *section
,
2881 unsigned section_line
,
2888 _cleanup_(multipath_route_freep
) MultipathRoute
*m
= NULL
;
2889 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2890 _cleanup_free_
char *word
= NULL
;
2891 Network
*network
= userdata
;
2892 union in_addr_union a
;
2903 r
= route_new_static(network
, filename
, section_line
, &n
);
2907 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2908 "Failed to allocate route, ignoring assignment: %m");
2912 if (isempty(rvalue
)) {
2913 n
->multipath_routes
= ordered_set_free_with_destructor(n
->multipath_routes
, multipath_route_free
);
2917 m
= new0(MultipathRoute
, 1);
2922 r
= extract_first_word(&p
, &word
, NULL
, 0);
2926 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2927 "Invalid multipath route option, ignoring assignment: %s", rvalue
);
2931 dev
= strchr(word
, '@');
2935 r
= parse_ifindex(dev
);
2939 if (!ifname_valid_full(dev
, IFNAME_VALID_ALTERNATIVE
)) {
2940 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2941 "Invalid interface name '%s' in %s=, ignoring: %s", dev
, lvalue
, rvalue
);
2945 m
->ifname
= strdup(dev
);
2951 r
= in_addr_from_string_auto(word
, &family
, &a
);
2953 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2954 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue
);
2957 m
->gateway
.address
= a
;
2958 m
->gateway
.family
= family
;
2961 r
= safe_atou32(p
, &m
->weight
);
2963 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2964 "Invalid multipath route weight, ignoring assignment: %s", p
);
2967 /* ip command takes weight in the range 1…255, while kernel takes the value in the
2968 * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip
2969 * command uses, then networkd decreases by one and stores it to match the range which
2971 if (m
->weight
== 0 || m
->weight
> 256) {
2972 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2973 "Invalid multipath route weight, ignoring assignment: %s", p
);
2979 r
= ordered_set_ensure_put(&n
->multipath_routes
, NULL
, m
);
2983 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2984 "Failed to store multipath route, ignoring assignment: %m");
2993 static int route_section_verify(Route
*route
, Network
*network
) {
2994 if (section_is_invalid(route
->section
))
2997 /* Currently, we do not support static route with finite lifetime. */
2998 assert(route
->lifetime_usec
== USEC_INFINITY
);
3000 if (route
->gateway_from_dhcp_or_ra
) {
3001 if (route
->gw_family
== AF_UNSPEC
) {
3002 /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
3003 switch (route
->family
) {
3005 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3006 "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
3007 route
->section
->filename
, route
->section
->line
);
3008 route
->family
= AF_INET
;
3012 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3013 "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
3014 route
->section
->filename
, route
->section
->line
, route
->family
== AF_INET
? "_dhcp4" : "_ipv6ra");
3017 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3018 "%s: Invalid route family. Ignoring [Route] section from line %u.",
3019 route
->section
->filename
, route
->section
->line
);
3021 route
->gw_family
= route
->family
;
3024 if (route
->gw_family
== AF_INET
&& !FLAGS_SET(network
->dhcp
, ADDRESS_FAMILY_IPV4
))
3025 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3026 "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
3027 "Ignoring [Route] section from line %u.",
3028 route
->section
->filename
, route
->section
->line
);
3030 if (route
->gw_family
== AF_INET6
&& !network
->ipv6_accept_ra
)
3031 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3032 "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
3033 "Ignoring [Route] section from line %u.",
3034 route
->section
->filename
, route
->section
->line
);
3037 /* When only Gateway= is specified, assume the route family based on the Gateway address. */
3038 if (route
->family
== AF_UNSPEC
)
3039 route
->family
= route
->gw_family
;
3041 if (route
->family
== AF_UNSPEC
) {
3042 assert(route
->section
);
3044 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3045 "%s: Route section without Gateway=, Destination=, Source=, "
3046 "or PreferredSource= field configured. "
3047 "Ignoring [Route] section from line %u.",
3048 route
->section
->filename
, route
->section
->line
);
3051 if (route
->family
== AF_INET6
&& route
->gw_family
== AF_INET
)
3052 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3053 "%s: IPv4 gateway is configured for IPv6 route. "
3054 "Ignoring [Route] section from line %u.",
3055 route
->section
->filename
, route
->section
->line
);
3057 if (!route
->table_set
&& network
->vrf
) {
3058 route
->table
= VRF(network
->vrf
)->table
;
3059 route
->table_set
= true;
3062 if (!route
->table_set
&& IN_SET(route
->type
, RTN_LOCAL
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_NAT
))
3063 route
->table
= RT_TABLE_LOCAL
;
3065 if (!route
->scope_set
&& route
->family
!= AF_INET6
) {
3066 if (IN_SET(route
->type
, RTN_LOCAL
, RTN_NAT
))
3067 route
->scope
= RT_SCOPE_HOST
;
3068 else if (IN_SET(route
->type
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_MULTICAST
))
3069 route
->scope
= RT_SCOPE_LINK
;
3070 else if (IN_SET(route
->type
, RTN_UNICAST
, RTN_UNSPEC
) &&
3071 !route
->gateway_from_dhcp_or_ra
&&
3072 !in_addr_is_set(route
->gw_family
, &route
->gw
) &&
3073 ordered_set_isempty(route
->multipath_routes
) &&
3074 route
->nexthop_id
== 0)
3075 route
->scope
= RT_SCOPE_LINK
;
3078 if (route
->scope
!= RT_SCOPE_UNIVERSE
&& route
->family
== AF_INET6
) {
3079 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route
->section
->filename
);
3080 route
->scope
= RT_SCOPE_UNIVERSE
;
3083 if (route
->family
== AF_INET6
&& route
->priority
== 0)
3084 route
->priority
= IP6_RT_PRIO_USER
;
3086 if (route
->gateway_onlink
< 0 && in_addr_is_set(route
->gw_family
, &route
->gw
) &&
3087 ordered_hashmap_isempty(network
->addresses_by_section
)) {
3088 /* If no address is configured, in most cases the gateway cannot be reachable.
3089 * TODO: we may need to improve the condition above. */
3090 log_warning("%s: Gateway= without static address configured. "
3091 "Enabling GatewayOnLink= option.",
3093 route
->gateway_onlink
= true;
3096 if (route
->gateway_onlink
>= 0)
3097 SET_FLAG(route
->flags
, RTNH_F_ONLINK
, route
->gateway_onlink
);
3099 if (route
->family
== AF_INET6
) {
3102 ORDERED_SET_FOREACH(m
, route
->multipath_routes
)
3103 if (m
->gateway
.family
== AF_INET
)
3104 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3105 "%s: IPv4 multipath route is specified for IPv6 route. "
3106 "Ignoring [Route] section from line %u.",
3107 route
->section
->filename
, route
->section
->line
);
3110 if ((route
->gateway_from_dhcp_or_ra
||
3111 in_addr_is_set(route
->gw_family
, &route
->gw
)) &&
3112 !ordered_set_isempty(route
->multipath_routes
))
3113 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3114 "%s: Gateway= cannot be specified with MultiPathRoute=. "
3115 "Ignoring [Route] section from line %u.",
3116 route
->section
->filename
, route
->section
->line
);
3118 if (route
->nexthop_id
> 0 &&
3119 (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: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
3124 "Ignoring [Route] section from line %u.",
3125 route
->section
->filename
, route
->section
->line
);
3130 void network_drop_invalid_routes(Network
*network
) {
3135 HASHMAP_FOREACH(route
, network
->routes_by_section
)
3136 if (route_section_verify(route
, network
) < 0)