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_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
51 _cleanup_(route_freep
) Route
*route
= NULL
;
57 assert(section_line
> 0);
59 r
= network_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
, &network_config_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 network_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
);
113 void route_hash_func(const Route
*route
, struct siphash
*state
) {
116 siphash24_compress(&route
->family
, sizeof(route
->family
), state
);
118 switch (route
->family
) {
121 siphash24_compress(&route
->dst_prefixlen
, sizeof(route
->dst_prefixlen
), state
);
122 siphash24_compress(&route
->dst
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
124 siphash24_compress(&route
->src_prefixlen
, sizeof(route
->src_prefixlen
), state
);
125 siphash24_compress(&route
->src
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
127 siphash24_compress(&route
->gw_family
, sizeof(route
->gw_family
), state
);
128 if (IN_SET(route
->gw_family
, AF_INET
, AF_INET6
)) {
129 siphash24_compress(&route
->gw
, FAMILY_ADDRESS_SIZE(route
->gw_family
), state
);
130 siphash24_compress(&route
->gw_weight
, sizeof(route
->gw_weight
), state
);
133 siphash24_compress(&route
->prefsrc
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
135 siphash24_compress(&route
->tos
, sizeof(route
->tos
), state
);
136 siphash24_compress(&route
->priority
, sizeof(route
->priority
), state
);
137 siphash24_compress(&route
->table
, sizeof(route
->table
), state
);
138 siphash24_compress(&route
->protocol
, sizeof(route
->protocol
), state
);
139 siphash24_compress(&route
->scope
, sizeof(route
->scope
), state
);
140 siphash24_compress(&route
->type
, sizeof(route
->type
), state
);
142 siphash24_compress(&route
->initcwnd
, sizeof(route
->initcwnd
), state
);
143 siphash24_compress(&route
->initrwnd
, sizeof(route
->initrwnd
), state
);
145 siphash24_compress(&route
->advmss
, sizeof(route
->advmss
), state
);
146 siphash24_compress(&route
->nexthop_id
, sizeof(route
->nexthop_id
), state
);
150 /* treat any other address family as AF_UNSPEC */
155 int route_compare_func(const Route
*a
, const Route
*b
) {
158 r
= CMP(a
->family
, b
->family
);
165 r
= CMP(a
->dst_prefixlen
, b
->dst_prefixlen
);
169 r
= memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
173 r
= CMP(a
->src_prefixlen
, b
->src_prefixlen
);
177 r
= memcmp(&a
->src
, &b
->src
, FAMILY_ADDRESS_SIZE(a
->family
));
181 r
= CMP(a
->gw_family
, b
->gw_family
);
185 if (IN_SET(a
->gw_family
, AF_INET
, AF_INET6
)) {
186 r
= memcmp(&a
->gw
, &b
->gw
, FAMILY_ADDRESS_SIZE(a
->family
));
190 r
= CMP(a
->gw_weight
, b
->gw_weight
);
195 r
= memcmp(&a
->prefsrc
, &b
->prefsrc
, FAMILY_ADDRESS_SIZE(a
->family
));
199 r
= CMP(a
->tos
, b
->tos
);
203 r
= CMP(a
->priority
, b
->priority
);
207 r
= CMP(a
->table
, b
->table
);
211 r
= CMP(a
->protocol
, b
->protocol
);
215 r
= CMP(a
->scope
, b
->scope
);
219 r
= CMP(a
->type
, b
->type
);
223 r
= CMP(a
->initcwnd
, b
->initcwnd
);
227 r
= CMP(a
->initrwnd
, b
->initrwnd
);
231 r
= CMP(a
->advmss
, b
->advmss
);
235 r
= CMP(a
->nexthop_id
, b
->nexthop_id
);
241 /* treat any other address family as AF_UNSPEC */
246 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
253 static bool route_type_is_reject(const Route
*route
) {
256 return IN_SET(route
->type
, RTN_UNREACHABLE
, RTN_PROHIBIT
, RTN_BLACKHOLE
, RTN_THROW
);
259 static bool route_needs_convert(const Route
*route
) {
262 return route
->nexthop_id
> 0 || !ordered_set_isempty(route
->multipath_routes
);
265 static int route_add(Manager
*manager
, Link
*link
, Route
*route
) {
270 if (route_type_is_reject(route
)) {
273 r
= set_ensure_put(&manager
->routes
, &route_hash_ops
, route
);
279 route
->manager
= manager
;
283 r
= set_ensure_put(&link
->routes
, &route_hash_ops
, route
);
295 int route_get(Manager
*manager
, Link
*link
, const Route
*in
, Route
**ret
) {
300 if (route_type_is_reject(in
)) {
304 route
= set_get(manager
->routes
, in
);
309 route
= set_get(link
->routes
, in
);
320 int route_dup(const Route
*src
, Route
**ret
) {
321 _cleanup_(route_freep
) Route
*dest
= NULL
;
323 /* This does not copy mulipath routes. */
328 dest
= newdup(Route
, src
, 1);
332 /* Unset all pointers */
333 dest
->network
= NULL
;
334 dest
->section
= NULL
;
336 dest
->manager
= NULL
;
337 dest
->multipath_routes
= NULL
;
340 *ret
= TAKE_PTR(dest
);
344 static void route_apply_nexthop(Route
*route
, const NextHop
*nh
, uint8_t nh_weight
) {
347 assert(hashmap_isempty(nh
->group
));
349 route
->gw_family
= nh
->family
;
352 if (nh_weight
!= UINT8_MAX
)
353 route
->gw_weight
= nh_weight
;
356 route
->type
= RTN_BLACKHOLE
;
359 static void route_apply_multipath_route(Route
*route
, const MultipathRoute
*m
) {
363 route
->gw_family
= m
->gateway
.family
;
364 route
->gw
= m
->gateway
.address
;
365 route
->gw_weight
= m
->weight
;
368 static int multipath_route_get_link(Manager
*manager
, const MultipathRoute
*m
, Link
**ret
) {
375 r
= link_get_by_name(manager
, m
->ifname
, ret
);
376 return r
< 0 ? r
: 1;
378 } else if (m
->ifindex
> 0) { /* Always ignore ifindex if ifname is set. */
379 r
= link_get_by_index(manager
, m
->ifindex
, ret
);
380 return r
< 0 ? r
: 1;
388 typedef struct ConvertedRoutes
{
394 static ConvertedRoutes
*converted_routes_free(ConvertedRoutes
*c
) {
398 for (size_t i
= 0; i
< c
->n
; i
++)
399 route_free(c
->routes
[i
]);
407 DEFINE_TRIVIAL_CLEANUP_FUNC(ConvertedRoutes
*, converted_routes_free
);
409 static int converted_routes_new(size_t n
, ConvertedRoutes
**ret
) {
410 _cleanup_(converted_routes_freep
) ConvertedRoutes
*c
= NULL
;
411 _cleanup_free_ Route
**routes
= NULL
;
412 _cleanup_free_ Link
**links
= NULL
;
417 routes
= new0(Route
*, n
);
421 links
= new0(Link
*, n
);
425 c
= new(ConvertedRoutes
, 1);
429 *c
= (ConvertedRoutes
) {
431 .routes
= TAKE_PTR(routes
),
432 .links
= TAKE_PTR(links
),
439 static int route_convert(Manager
*manager
, const Route
*route
, ConvertedRoutes
**ret
) {
440 _cleanup_(converted_routes_freep
) ConvertedRoutes
*c
= NULL
;
447 if (!route_needs_convert(route
)) {
452 if (route
->nexthop_id
> 0) {
453 struct nexthop_grp
*nhg
;
456 r
= manager_get_nexthop_by_id(manager
, route
->nexthop_id
, &nh
);
460 if (hashmap_isempty(nh
->group
)) {
461 r
= converted_routes_new(1, &c
);
465 r
= route_dup(route
, &c
->routes
[0]);
469 route_apply_nexthop(c
->routes
[0], nh
, UINT8_MAX
);
470 c
->links
[0] = nh
->link
;
476 r
= converted_routes_new(hashmap_size(nh
->group
), &c
);
481 HASHMAP_FOREACH(nhg
, nh
->group
) {
484 r
= manager_get_nexthop_by_id(manager
, nhg
->id
, &h
);
488 r
= route_dup(route
, &c
->routes
[i
]);
492 route_apply_nexthop(c
->routes
[i
], h
, nhg
->weight
);
493 c
->links
[i
] = h
->link
;
503 assert(!ordered_set_isempty(route
->multipath_routes
));
505 r
= converted_routes_new(ordered_set_size(route
->multipath_routes
), &c
);
511 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
512 r
= route_dup(route
, &c
->routes
[i
]);
516 route_apply_multipath_route(c
->routes
[i
], m
);
518 r
= multipath_route_get_link(manager
, m
, &c
->links
[i
]);
529 void link_mark_routes(Link
*link
, NetworkConfigSource source
, const struct in6_addr
*router
) {
534 SET_FOREACH(route
, link
->routes
) {
535 if (route
->source
!= source
)
538 if (source
== NETWORK_CONFIG_SOURCE_NDISC
&&
539 router
&& !in6_addr_equal(router
, &route
->provider
.in6
))
546 static void log_route_debug(const Route
*route
, const char *str
, const Link
*link
, const Manager
*manager
) {
547 _cleanup_free_
char *state
= NULL
, *dst
= NULL
, *src
= NULL
, *gw_alloc
= NULL
, *prefsrc
= NULL
,
548 *table
= NULL
, *scope
= NULL
, *proto
= NULL
, *flags
= NULL
;
549 const char *gw
= NULL
;
555 /* link may be NULL. */
560 (void) network_config_state_to_string_alloc(route
->state
, &state
);
561 if (in_addr_is_set(route
->family
, &route
->dst
) || route
->dst_prefixlen
> 0)
562 (void) in_addr_prefix_to_string(route
->family
, &route
->dst
, route
->dst_prefixlen
, &dst
);
563 if (in_addr_is_set(route
->family
, &route
->src
) || route
->src_prefixlen
> 0)
564 (void) in_addr_prefix_to_string(route
->family
, &route
->src
, route
->src_prefixlen
, &src
);
565 if (in_addr_is_set(route
->gw_family
, &route
->gw
)) {
566 (void) in_addr_to_string(route
->gw_family
, &route
->gw
, &gw_alloc
);
568 } else if (route
->gateway_from_dhcp_or_ra
) {
569 if (route
->gw_family
== AF_INET
)
571 else if (route
->gw_family
== AF_INET6
)
576 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
577 _cleanup_free_
char *buf
= NULL
;
578 union in_addr_union a
= m
->gateway
.address
;
580 (void) in_addr_to_string(m
->gateway
.family
, &a
, &buf
);
581 (void) strextend_with_separator(&gw_alloc
, ",", strna(buf
));
583 (void) strextend(&gw_alloc
, "@", m
->ifname
);
584 else if (m
->ifindex
> 0)
585 (void) strextendf(&gw_alloc
, "@%"PRIu32
, m
->ifindex
);
586 /* See comments in config_parse_multipath_route(). */
587 (void) strextendf(&gw_alloc
, ":%"PRIu32
, m
->weight
+ 1);
591 if (in_addr_is_set(route
->family
, &route
->prefsrc
))
592 (void) in_addr_to_string(route
->family
, &route
->prefsrc
, &prefsrc
);
593 (void) route_scope_to_string_alloc(route
->scope
, &scope
);
594 (void) manager_get_route_table_to_string(manager
, route
->table
, &table
);
595 (void) route_protocol_full_to_string_alloc(route
->protocol
, &proto
);
596 (void) route_flags_to_string_alloc(route
->flags
, &flags
);
599 "%s %s route (%s): dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, "
600 "proto: %s, type: %s, nexthop: %"PRIu32
", priority: %"PRIu32
", flags: %s",
601 str
, strna(network_config_source_to_string(route
->source
)), strna(state
),
602 strna(dst
), strna(src
), strna(gw
), strna(prefsrc
),
603 strna(scope
), strna(table
), strna(proto
),
604 strna(route_type_to_string(route
->type
)),
605 route
->nexthop_id
, route
->priority
, strna(flags
));
608 static int route_set_netlink_message(const Route
*route
, sd_netlink_message
*req
, Link
*link
) {
614 /* link may be NULL */
616 if (in_addr_is_set(route
->gw_family
, &route
->gw
) && route
->nexthop_id
== 0) {
617 if (route
->gw_family
== route
->family
) {
618 r
= netlink_message_append_in_addr_union(req
, RTA_GATEWAY
, route
->gw_family
, &route
->gw
);
620 return log_link_error_errno(link
, r
, "Could not append RTA_GATEWAY attribute: %m");
623 .family
= route
->gw_family
,
624 .address
= route
->gw
,
627 r
= sd_netlink_message_append_data(req
, RTA_VIA
, &rtvia
, sizeof(rtvia
));
629 return log_link_error_errno(link
, r
, "Could not append RTA_VIA attribute: %m");
633 if (route
->dst_prefixlen
> 0) {
634 r
= netlink_message_append_in_addr_union(req
, RTA_DST
, route
->family
, &route
->dst
);
636 return log_link_error_errno(link
, r
, "Could not append RTA_DST attribute: %m");
638 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
640 return log_link_error_errno(link
, r
, "Could not set destination prefix length: %m");
643 if (route
->src_prefixlen
> 0) {
644 r
= netlink_message_append_in_addr_union(req
, RTA_SRC
, route
->family
, &route
->src
);
646 return log_link_error_errno(link
, r
, "Could not append RTA_SRC attribute: %m");
648 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
650 return log_link_error_errno(link
, r
, "Could not set source prefix length: %m");
653 if (in_addr_is_set(route
->family
, &route
->prefsrc
)) {
654 r
= netlink_message_append_in_addr_union(req
, RTA_PREFSRC
, route
->family
, &route
->prefsrc
);
656 return log_link_error_errno(link
, r
, "Could not append RTA_PREFSRC attribute: %m");
659 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
661 return log_link_error_errno(link
, r
, "Could not set scope: %m");
663 r
= sd_rtnl_message_route_set_flags(req
, route
->flags
& RTNH_F_ONLINK
);
665 return log_link_error_errno(link
, r
, "Could not set flags: %m");
667 if (route
->table
< 256) {
668 r
= sd_rtnl_message_route_set_table(req
, route
->table
);
670 return log_link_error_errno(link
, r
, "Could not set route table: %m");
672 r
= sd_rtnl_message_route_set_table(req
, RT_TABLE_UNSPEC
);
674 return log_link_error_errno(link
, r
, "Could not set route table: %m");
676 /* Table attribute to allow more than 256. */
677 r
= sd_netlink_message_append_u32(req
, RTA_TABLE
, route
->table
);
679 return log_link_error_errno(link
, r
, "Could not append RTA_TABLE attribute: %m");
682 if (!route_type_is_reject(route
) &&
683 route
->nexthop_id
== 0 &&
684 ordered_set_isempty(route
->multipath_routes
)) {
685 assert(link
); /* Those routes must be attached to a specific link */
687 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
689 return log_link_error_errno(link
, r
, "Could not append RTA_OIF attribute: %m");
692 if (route
->nexthop_id
> 0) {
693 r
= sd_netlink_message_append_u32(req
, RTA_NH_ID
, route
->nexthop_id
);
695 return log_link_error_errno(link
, r
, "Could not append RTA_NH_ID attribute: %m");
698 r
= sd_netlink_message_append_u8(req
, RTA_PREF
, route
->pref
);
700 return log_link_error_errno(link
, r
, "Could not append RTA_PREF attribute: %m");
702 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->priority
);
704 return log_link_error_errno(link
, r
, "Could not append RTA_PRIORITY attribute: %m");
709 static int route_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
714 /* link may be NULL. */
716 if (link
&& IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
719 r
= sd_netlink_message_get_errno(m
);
720 if (r
< 0 && r
!= -ESRCH
)
721 log_link_message_warning_errno(link
, m
, r
, "Could not drop route, ignoring");
726 int route_remove(Route
*route
) {
727 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
734 assert(route
->manager
|| (route
->link
&& route
->link
->manager
));
735 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
738 manager
= route
->manager
?: link
->manager
;
740 log_route_debug(route
, "Removing", link
, manager
);
742 r
= sd_rtnl_message_new_route(manager
->rtnl
, &req
,
743 RTM_DELROUTE
, route
->family
,
746 return log_link_error_errno(link
, r
, "Could not create RTM_DELROUTE message: %m");
748 if (route
->family
== AF_INET
&& route
->nexthop_id
> 0 && route
->type
== RTN_BLACKHOLE
)
749 /* When IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel
750 * sends RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type
751 * fib_rt_info::type may not be blackhole. Thus, we cannot know the internal value.
752 * Moreover, on route removal, the matching is done with the hidden value if we set
753 * non-zero type in RTM_DELROUTE message. Note, sd_rtnl_message_new_route() sets
754 * RTN_UNICAST by default. So, we need to clear the type here. */
759 r
= sd_rtnl_message_route_set_type(req
, type
);
761 return log_link_error_errno(link
, r
, "Could not set route type: %m");
763 r
= route_set_netlink_message(route
, req
, link
);
767 r
= netlink_call_async(manager
->rtnl
, NULL
, req
, route_remove_handler
,
768 link
? link_netlink_destroy_callback
: NULL
, link
);
770 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
774 route_enter_removing(route
);
778 static void manager_mark_routes(Manager
*manager
, bool foreign
, const Link
*except
) {
785 /* First, mark all routes. */
786 SET_FOREACH(route
, manager
->routes
) {
787 /* Do not touch routes managed by the kernel. */
788 if (route
->protocol
== RTPROT_KERNEL
)
791 /* When 'foreign' is true, do not remove routes we configured. */
792 if (foreign
&& route
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
)
795 /* Do not touch dynamic routes. They will removed by dhcp_pd_prefix_lost() */
796 if (IN_SET(route
->source
, NETWORK_CONFIG_SOURCE_DHCP4
, NETWORK_CONFIG_SOURCE_DHCP6
))
799 /* Ignore routes not assigned yet or already removed. */
800 if (!route_exists(route
))
806 /* Then, unmark all routes requested by active links. */
807 HASHMAP_FOREACH(link
, manager
->links_by_index
) {
814 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
817 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
818 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
821 r
= route_convert(manager
, route
, &converted
);
825 if (route_get(manager
, NULL
, route
, &existing
) >= 0)
826 route_unmark(existing
);
830 for (size_t i
= 0; i
< converted
->n
; i
++)
831 if (route_get(manager
, NULL
, converted
->routes
[i
], &existing
) >= 0)
832 route_unmark(existing
);
837 static int manager_drop_routes(Manager
*manager
) {
843 SET_FOREACH(route
, manager
->routes
) {
844 if (!route_is_marked(route
))
847 k
= route_remove(route
);
855 static bool route_by_kernel(const Route
*route
) {
858 if (route
->protocol
== RTPROT_KERNEL
)
861 /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
862 * multicast with RTPROT_BOOT. Do not touch it. */
863 if (route
->protocol
== RTPROT_BOOT
&&
864 route
->family
== AF_INET6
&&
865 route
->dst_prefixlen
== 8 &&
866 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 }}}))
872 static void link_unmark_wireguard_routes(Link
*link
) {
873 Route
*route
, *existing
;
879 if (!streq_ptr(link
->kind
, "wireguard"))
882 if (netdev_get(link
->manager
, link
->ifname
, &netdev
) < 0)
885 w
= WIREGUARD(netdev
);
889 SET_FOREACH(route
, w
->routes
)
890 if (route_get(NULL
, link
, route
, &existing
) >= 0)
891 route_unmark(existing
);
894 int link_drop_foreign_routes(Link
*link
) {
899 assert(link
->manager
);
900 assert(link
->network
);
902 SET_FOREACH(route
, link
->routes
) {
903 /* do not touch routes managed by the kernel */
904 if (route_by_kernel(route
))
907 /* Do not remove routes we configured. */
908 if (route
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
)
911 /* Ignore routes not assigned yet or already removed. */
912 if (!route_exists(route
))
915 if (route
->protocol
== RTPROT_STATIC
&&
916 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_STATIC
))
919 if (route
->protocol
== RTPROT_DHCP
&&
920 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_DHCP
))
926 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
927 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
930 r
= route_convert(link
->manager
, route
, &converted
);
934 if (route_get(NULL
, link
, route
, &existing
) >= 0)
935 route_unmark(existing
);
939 for (size_t i
= 0; i
< converted
->n
; i
++)
940 if (route_get(NULL
, link
, converted
->routes
[i
], &existing
) >= 0)
941 route_unmark(existing
);
944 link_unmark_wireguard_routes(link
);
947 SET_FOREACH(route
, link
->routes
) {
948 if (!route_is_marked(route
))
951 k
= route_remove(route
);
956 manager_mark_routes(link
->manager
, /* foreign = */ true, NULL
);
958 k
= manager_drop_routes(link
->manager
);
965 int link_drop_routes(Link
*link
) {
971 SET_FOREACH(route
, link
->routes
) {
972 /* do not touch routes managed by the kernel */
973 if (route_by_kernel(route
))
976 if (!route_exists(route
))
979 k
= route_remove(route
);
984 manager_mark_routes(link
->manager
, /* foreign = */ false, link
);
986 k
= manager_drop_routes(link
->manager
);
993 void link_foreignize_routes(Link
*link
) {
998 SET_FOREACH(route
, link
->routes
)
999 route
->source
= NETWORK_CONFIG_SOURCE_FOREIGN
;
1001 manager_mark_routes(link
->manager
, /* foreign = */ false, link
);
1003 SET_FOREACH(route
, link
->manager
->routes
) {
1004 if (!route_is_marked(route
))
1007 route
->source
= NETWORK_CONFIG_SOURCE_FOREIGN
;
1011 static int route_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1012 Route
*route
= userdata
;
1017 assert(route
->manager
|| (route
->link
&& route
->link
->manager
));
1019 link
= route
->link
; /* This may be NULL. */
1021 r
= route_remove(route
);
1023 log_link_warning_errno(link
, r
, "Could not remove route: %m");
1025 link_enter_failed(link
);
1031 static int route_setup_timer(Route
*route
, const struct rta_cacheinfo
*cacheinfo
) {
1036 assert(route
->manager
|| (route
->link
&& route
->link
->manager
));
1038 manager
= route
->manager
?: route
->link
->manager
;
1040 if (route
->lifetime_usec
== USEC_INFINITY
)
1043 if (cacheinfo
&& cacheinfo
->rta_expires
!= 0)
1044 /* Assume that non-zero rta_expires means kernel will handle the route expiration. */
1047 r
= event_reset_time(manager
->event
, &route
->expire
, clock_boottime_or_monotonic(),
1048 route
->lifetime_usec
, 0, route_expire_handler
, route
, 0, "route-expiration", true);
1055 static int append_nexthop_one(const Link
*link
, const Route
*route
, const MultipathRoute
*m
, struct rtattr
**rta
, size_t offset
) {
1056 struct rtnexthop
*rtnh
;
1057 struct rtattr
*new_rta
;
1065 new_rta
= realloc(*rta
, RTA_ALIGN((*rta
)->rta_len
) + RTA_SPACE(sizeof(struct rtnexthop
)));
1070 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1071 *rtnh
= (struct rtnexthop
) {
1072 .rtnh_len
= sizeof(*rtnh
),
1073 .rtnh_ifindex
= m
->ifindex
> 0 ? m
->ifindex
: link
->ifindex
,
1074 .rtnh_hops
= m
->weight
,
1077 (*rta
)->rta_len
+= sizeof(struct rtnexthop
);
1079 if (route
->family
== m
->gateway
.family
) {
1080 r
= rtattr_append_attribute(rta
, RTA_GATEWAY
, &m
->gateway
.address
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1083 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1084 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1086 r
= rtattr_append_attribute(rta
, RTA_VIA
, &m
->gateway
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1089 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1090 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1096 (*rta
)->rta_len
-= sizeof(struct rtnexthop
);
1100 static int append_nexthops(const Link
*link
, const Route
*route
, sd_netlink_message
*req
) {
1101 _cleanup_free_
struct rtattr
*rta
= NULL
;
1102 struct rtnexthop
*rtnh
;
1111 if (ordered_set_isempty(route
->multipath_routes
))
1114 rta
= new(struct rtattr
, 1);
1118 *rta
= (struct rtattr
) {
1119 .rta_type
= RTA_MULTIPATH
,
1120 .rta_len
= RTA_LENGTH(0),
1122 offset
= (uint8_t *) RTA_DATA(rta
) - (uint8_t *) rta
;
1124 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1125 r
= append_nexthop_one(link
, route
, m
, &rta
, offset
);
1129 rtnh
= (struct rtnexthop
*)((uint8_t *) rta
+ offset
);
1130 offset
= (uint8_t *) RTNH_NEXT(rtnh
) - (uint8_t *) rta
;
1133 r
= sd_netlink_message_append_data(req
, RTA_MULTIPATH
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
1140 int route_configure_handler_internal(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
, const char *error_msg
) {
1147 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
1150 r
= sd_netlink_message_get_errno(m
);
1151 if (r
< 0 && r
!= -EEXIST
) {
1152 log_link_message_warning_errno(link
, m
, r
, "Could not set route");
1153 link_enter_failed(link
);
1160 static int route_configure(
1163 link_netlink_message_handler_t callback
) {
1165 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
1169 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
1171 assert(link
->manager
);
1172 assert(link
->manager
->rtnl
);
1173 assert(link
->ifindex
> 0);
1176 log_route_debug(route
, "Configuring", link
, link
->manager
);
1178 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &req
,
1179 RTM_NEWROUTE
, route
->family
,
1182 return log_link_error_errno(link
, r
, "Could not create RTM_NEWROUTE message: %m");
1184 r
= sd_rtnl_message_route_set_type(req
, route
->type
);
1186 return log_link_error_errno(link
, r
, "Could not set route type: %m");
1188 r
= route_set_netlink_message(route
, req
, link
);
1192 if (route
->lifetime_usec
!= USEC_INFINITY
) {
1193 r
= sd_netlink_message_append_u32(req
, RTA_EXPIRES
,
1194 MIN(DIV_ROUND_UP(usec_sub_unsigned(route
->lifetime_usec
, now(clock_boottime_or_monotonic())), USEC_PER_SEC
), UINT32_MAX
));
1196 return log_link_error_errno(link
, r
, "Could not append RTA_EXPIRES attribute: %m");
1199 if (route
->ttl_propagate
>= 0) {
1200 r
= sd_netlink_message_append_u8(req
, RTA_TTL_PROPAGATE
, route
->ttl_propagate
);
1202 return log_link_error_errno(link
, r
, "Could not append RTA_TTL_PROPAGATE attribute: %m");
1205 r
= sd_netlink_message_open_container(req
, RTA_METRICS
);
1207 return log_link_error_errno(link
, r
, "Could not append RTA_METRICS attribute: %m");
1209 if (route
->mtu
> 0) {
1210 r
= sd_netlink_message_append_u32(req
, RTAX_MTU
, route
->mtu
);
1212 return log_link_error_errno(link
, r
, "Could not append RTAX_MTU attribute: %m");
1215 if (route
->initcwnd
> 0) {
1216 r
= sd_netlink_message_append_u32(req
, RTAX_INITCWND
, route
->initcwnd
);
1218 return log_link_error_errno(link
, r
, "Could not append RTAX_INITCWND attribute: %m");
1221 if (route
->initrwnd
> 0) {
1222 r
= sd_netlink_message_append_u32(req
, RTAX_INITRWND
, route
->initrwnd
);
1224 return log_link_error_errno(link
, r
, "Could not append RTAX_INITRWND attribute: %m");
1227 if (route
->quickack
>= 0) {
1228 r
= sd_netlink_message_append_u32(req
, RTAX_QUICKACK
, route
->quickack
);
1230 return log_link_error_errno(link
, r
, "Could not append RTAX_QUICKACK attribute: %m");
1233 if (route
->fast_open_no_cookie
>= 0) {
1234 r
= sd_netlink_message_append_u32(req
, RTAX_FASTOPEN_NO_COOKIE
, route
->fast_open_no_cookie
);
1236 return log_link_error_errno(link
, r
, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
1239 if (route
->advmss
> 0) {
1240 r
= sd_netlink_message_append_u32(req
, RTAX_ADVMSS
, route
->advmss
);
1242 return log_link_error_errno(link
, r
, "Could not append RTAX_ADVMSS attribute: %m");
1245 r
= sd_netlink_message_close_container(req
);
1247 return log_link_error_errno(link
, r
, "Could not append RTA_METRICS attribute: %m");
1249 if (!ordered_set_isempty(route
->multipath_routes
)) {
1250 assert(route
->nexthop_id
== 0);
1251 assert(!in_addr_is_set(route
->gw_family
, &route
->gw
));
1253 r
= append_nexthops(link
, route
, req
);
1255 return log_link_error_errno(link
, r
, "Could not append RTA_MULTIPATH attribute: %m");
1258 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, callback
,
1259 link_netlink_destroy_callback
, link
);
1261 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
1267 void route_cancel_request(Route
*route
, Link
*link
) {
1272 link
= route
->link
?: link
;
1276 if (!route_is_requesting(route
))
1281 .type
= REQUEST_TYPE_ROUTE
,
1285 request_drop(ordered_set_get(link
->manager
->request_queue
, &req
));
1286 route_cancel_requesting(route
);
1289 static int static_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
1293 assert(link
->static_route_messages
> 0);
1295 link
->static_route_messages
--;
1297 r
= route_configure_handler_internal(rtnl
, m
, link
, "Could not set route");
1301 if (link
->static_route_messages
== 0) {
1302 log_link_debug(link
, "Routes set");
1303 link
->static_routes_configured
= true;
1304 link_check_ready(link
);
1310 int link_request_route(
1313 bool consume_object
,
1314 unsigned *message_counter
,
1315 link_netlink_message_handler_t netlink_handler
,
1322 assert(link
->manager
);
1324 assert(route
->source
!= NETWORK_CONFIG_SOURCE_FOREIGN
);
1325 assert(!route_needs_convert(route
));
1327 if (route_get(link
->manager
, link
, route
, &existing
) < 0) {
1328 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1333 r
= route_dup(route
, &tmp
);
1338 r
= route_add(link
->manager
, link
, tmp
);
1342 existing
= TAKE_PTR(tmp
);
1344 existing
->source
= route
->source
;
1345 existing
->provider
= route
->provider
;
1346 existing
->lifetime_usec
= route
->lifetime_usec
;
1350 if (existing
->expire
) {
1351 /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE
1352 * message, so we need to update the timer here. */
1353 r
= route_setup_timer(existing
, NULL
);
1355 log_link_warning_errno(link
, r
, "Failed to update expiration timer for route, ignoring: %m");
1357 log_route_debug(existing
, "Updated expiration timer for", link
, link
->manager
);
1361 log_route_debug(existing
, "Requesting", link
, link
->manager
);
1362 r
= link_queue_request(link
, REQUEST_TYPE_ROUTE
, existing
, false,
1363 message_counter
, netlink_handler
, ret
);
1367 route_enter_requesting(existing
);
1371 static int link_request_static_route(Link
*link
, Route
*route
) {
1373 assert(link
->manager
);
1376 if (!route_needs_convert(route
))
1377 return link_request_route(link
, route
, false, &link
->static_route_messages
,
1378 static_route_handler
, NULL
);
1380 log_route_debug(route
, "Requesting", link
, link
->manager
);
1381 return link_queue_request(link
, REQUEST_TYPE_ROUTE
, route
, false,
1382 &link
->static_route_messages
, static_route_handler
, NULL
);
1385 static int link_request_wireguard_routes(Link
*link
, bool only_ipv4
) {
1393 if (!streq_ptr(link
->kind
, "wireguard"))
1396 if (netdev_get(link
->manager
, link
->ifname
, &netdev
) < 0)
1399 w
= WIREGUARD(netdev
);
1403 SET_FOREACH(route
, w
->routes
) {
1404 if (only_ipv4
&& route
->family
!= AF_INET
)
1407 r
= link_request_static_route(link
, route
);
1415 int link_request_static_routes(Link
*link
, bool only_ipv4
) {
1420 assert(link
->network
);
1422 link
->static_routes_configured
= false;
1424 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
1425 if (route
->gateway_from_dhcp_or_ra
)
1428 if (only_ipv4
&& route
->family
!= AF_INET
)
1431 r
= link_request_static_route(link
, route
);
1436 r
= link_request_wireguard_routes(link
, only_ipv4
);
1440 if (link
->static_route_messages
== 0) {
1441 link
->static_routes_configured
= true;
1442 link_check_ready(link
);
1444 log_link_debug(link
, "Requesting routes");
1445 link_set_state(link
, LINK_STATE_CONFIGURING
);
1451 static int route_is_ready_to_configure(const Route
*route
, Link
*link
) {
1457 if (!link_is_ready_to_configure(link
, false))
1460 if (set_size(link
->routes
) >= routes_max())
1463 if (route
->nexthop_id
> 0) {
1464 struct nexthop_grp
*nhg
;
1467 if (manager_get_nexthop_by_id(link
->manager
, route
->nexthop_id
, &nh
) < 0)
1470 if (!nexthop_exists(nh
))
1473 HASHMAP_FOREACH(nhg
, nh
->group
) {
1476 if (manager_get_nexthop_by_id(link
->manager
, nhg
->id
, &g
) < 0)
1479 if (!nexthop_exists(g
))
1484 if (in_addr_is_set(route
->family
, &route
->prefsrc
) > 0) {
1485 r
= manager_has_address(link
->manager
, route
->family
, &route
->prefsrc
, route
->family
== AF_INET6
);
1490 if (!gateway_is_ready(link
, FLAGS_SET(route
->flags
, RTNH_F_ONLINK
), route
->gw_family
, &route
->gw
))
1494 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1495 union in_addr_union a
= m
->gateway
.address
;
1498 r
= multipath_route_get_link(link
->manager
, m
, &l
);
1502 if (!link_is_ready_to_configure(l
, true))
1505 m
->ifindex
= l
->ifindex
;
1508 if (!gateway_is_ready(l
?: link
, FLAGS_SET(route
->flags
, RTNH_F_ONLINK
), m
->gateway
.family
, &a
))
1515 int request_process_route(Request
*req
) {
1516 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
1524 assert(req
->type
== REQUEST_TYPE_ROUTE
);
1529 r
= route_is_ready_to_configure(route
, link
);
1531 return log_link_warning_errno(link
, r
, "Failed to check if route is ready to configure: %m");
1535 if (route_needs_convert(route
)) {
1536 r
= route_convert(link
->manager
, route
, &converted
);
1538 return log_link_warning_errno(link
, r
, "Failed to convert route: %m");
1543 for (size_t i
= 0; i
< converted
->n
; i
++) {
1546 if (route_get(link
->manager
, converted
->links
[i
] ?: link
, converted
->routes
[i
], &existing
) < 0) {
1547 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1549 r
= route_dup(converted
->routes
[i
], &tmp
);
1553 r
= route_add(link
->manager
, converted
->links
[i
] ?: link
, tmp
);
1555 return log_link_warning_errno(link
, r
, "Failed to add route: %m");
1559 existing
->source
= converted
->routes
[i
]->source
;
1560 existing
->provider
= converted
->routes
[i
]->provider
;
1565 r
= route_configure(route
, link
, req
->netlink_handler
);
1567 return log_link_warning_errno(link
, r
, "Failed to configure route: %m");
1570 for (size_t i
= 0; i
< converted
->n
; i
++) {
1573 assert_se(route_get(link
->manager
, converted
->links
[i
] ?: link
, converted
->routes
[i
], &existing
) >= 0);
1574 route_enter_configuring(existing
);
1577 route_enter_configuring(route
);
1582 static int process_route_one(
1587 const struct rta_cacheinfo
*cacheinfo
) {
1589 _cleanup_(route_freep
) Route
*tmp
= in
;
1590 Route
*route
= NULL
;
1595 assert(IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
));
1597 /* link may be NULL. This consumes 'in'. */
1599 (void) route_get(manager
, link
, tmp
, &route
);
1604 route
->flags
= tmp
->flags
;
1605 route_enter_configured(route
);
1606 log_route_debug(route
, "Received remembered", link
, manager
);
1608 r
= route_setup_timer(route
, cacheinfo
);
1610 log_link_warning_errno(link
, r
, "Failed to configure expiration timer for route, ignoring: %m");
1612 log_route_debug(route
, "Configured expiration timer for", link
, manager
);
1614 } else if (!manager
->manage_foreign_routes
) {
1615 route_enter_configured(tmp
);
1616 log_route_debug(tmp
, "Ignoring received", link
, manager
);
1619 /* A route appeared that we did not request */
1620 route_enter_configured(tmp
);
1621 log_route_debug(tmp
, "Received new", link
, manager
);
1622 r
= route_add(manager
, link
, tmp
);
1624 log_link_warning_errno(link
, r
, "Failed to remember foreign route, ignoring: %m");
1634 route_enter_removed(route
);
1635 if (route
->state
== 0) {
1636 log_route_debug(route
, "Forgetting", link
, manager
);
1639 log_route_debug(route
, "Removed", link
, manager
);
1641 log_route_debug(tmp
,
1642 manager
->manage_foreign_routes
? "Kernel removed unknown" : "Ignoring received",
1648 assert_not_reached();
1654 int manager_rtnl_process_route(sd_netlink
*rtnl
, sd_netlink_message
*message
, Manager
*m
) {
1655 _cleanup_(converted_routes_freep
) ConvertedRoutes
*converted
= NULL
;
1656 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1657 _cleanup_free_
void *rta_multipath
= NULL
;
1658 struct rta_cacheinfo cacheinfo
;
1670 if (sd_netlink_message_is_error(message
)) {
1671 r
= sd_netlink_message_get_errno(message
);
1673 log_message_warning_errno(message
, r
, "rtnl: failed to receive route message, ignoring");
1678 r
= sd_netlink_message_get_type(message
, &type
);
1680 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
1682 } else if (!IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
)) {
1683 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type
);
1687 r
= sd_netlink_message_read_u32(message
, RTA_OIF
, &ifindex
);
1688 if (r
< 0 && r
!= -ENODATA
) {
1689 log_warning_errno(r
, "rtnl: could not get ifindex from route message, ignoring: %m");
1691 } else if (r
>= 0) {
1693 log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex
);
1697 r
= link_get_by_index(m
, ifindex
, &link
);
1698 if (r
< 0 || !link
) {
1699 /* when enumerating we might be out of sync, but we will
1700 * get the route again, so just ignore it */
1701 if (!m
->enumerating
)
1702 log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex
);
1707 r
= route_new(&tmp
);
1711 r
= sd_rtnl_message_route_get_family(message
, &tmp
->family
);
1713 log_link_warning(link
, "rtnl: received route message without family, ignoring");
1715 } else if (!IN_SET(tmp
->family
, AF_INET
, AF_INET6
)) {
1716 log_link_debug(link
, "rtnl: received route message with invalid family '%i', ignoring", tmp
->family
);
1720 r
= sd_rtnl_message_route_get_protocol(message
, &tmp
->protocol
);
1722 log_warning_errno(r
, "rtnl: received route message without route protocol, ignoring: %m");
1726 r
= sd_rtnl_message_route_get_flags(message
, &tmp
->flags
);
1728 log_warning_errno(r
, "rtnl: received route message without route flags, ignoring: %m");
1732 r
= netlink_message_read_in_addr_union(message
, RTA_DST
, tmp
->family
, &tmp
->dst
);
1733 if (r
< 0 && r
!= -ENODATA
) {
1734 log_link_warning_errno(link
, r
, "rtnl: received route message without valid destination, ignoring: %m");
1738 r
= netlink_message_read_in_addr_union(message
, RTA_GATEWAY
, tmp
->family
, &tmp
->gw
);
1739 if (r
< 0 && r
!= -ENODATA
) {
1740 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1743 tmp
->gw_family
= tmp
->family
;
1744 else if (tmp
->family
== AF_INET
) {
1747 r
= sd_netlink_message_read(message
, RTA_VIA
, sizeof(via
), &via
);
1748 if (r
< 0 && r
!= -ENODATA
) {
1749 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1751 } else if (r
>= 0) {
1752 tmp
->gw_family
= via
.family
;
1753 tmp
->gw
= via
.address
;
1757 r
= netlink_message_read_in_addr_union(message
, RTA_SRC
, tmp
->family
, &tmp
->src
);
1758 if (r
< 0 && r
!= -ENODATA
) {
1759 log_link_warning_errno(link
, r
, "rtnl: received route message without valid source, ignoring: %m");
1763 r
= netlink_message_read_in_addr_union(message
, RTA_PREFSRC
, tmp
->family
, &tmp
->prefsrc
);
1764 if (r
< 0 && r
!= -ENODATA
) {
1765 log_link_warning_errno(link
, r
, "rtnl: received route message without valid preferred source, ignoring: %m");
1769 r
= sd_rtnl_message_route_get_dst_prefixlen(message
, &tmp
->dst_prefixlen
);
1771 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1775 r
= sd_rtnl_message_route_get_src_prefixlen(message
, &tmp
->src_prefixlen
);
1777 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1781 r
= sd_rtnl_message_route_get_scope(message
, &tmp
->scope
);
1783 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid scope, ignoring: %m");
1787 r
= sd_rtnl_message_route_get_tos(message
, &tmp
->tos
);
1789 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid tos, ignoring: %m");
1793 r
= sd_rtnl_message_route_get_type(message
, &tmp
->type
);
1795 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid type, ignoring: %m");
1799 r
= sd_netlink_message_read_u32(message
, RTA_TABLE
, &tmp
->table
);
1800 if (r
== -ENODATA
) {
1801 unsigned char table
;
1803 r
= sd_rtnl_message_route_get_table(message
, &table
);
1808 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid table, ignoring: %m");
1812 r
= sd_netlink_message_read_u32(message
, RTA_PRIORITY
, &tmp
->priority
);
1813 if (r
< 0 && r
!= -ENODATA
) {
1814 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid priority, ignoring: %m");
1818 r
= sd_netlink_message_read_u32(message
, RTA_NH_ID
, &tmp
->nexthop_id
);
1819 if (r
< 0 && r
!= -ENODATA
) {
1820 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid nexthop id, ignoring: %m");
1824 r
= sd_netlink_message_enter_container(message
, RTA_METRICS
);
1825 if (r
< 0 && r
!= -ENODATA
) {
1826 log_link_error_errno(link
, r
, "rtnl: Could not enter RTA_METRICS container, ignoring: %m");
1830 r
= sd_netlink_message_read_u32(message
, RTAX_INITCWND
, &tmp
->initcwnd
);
1831 if (r
< 0 && r
!= -ENODATA
) {
1832 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initcwnd, ignoring: %m");
1836 r
= sd_netlink_message_read_u32(message
, RTAX_INITRWND
, &tmp
->initrwnd
);
1837 if (r
< 0 && r
!= -ENODATA
) {
1838 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initrwnd, ignoring: %m");
1842 r
= sd_netlink_message_read_u32(message
, RTAX_ADVMSS
, &tmp
->advmss
);
1843 if (r
< 0 && r
!= -ENODATA
) {
1844 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid advmss, ignoring: %m");
1848 r
= sd_netlink_message_exit_container(message
);
1850 log_link_error_errno(link
, r
, "rtnl: Could not exit from RTA_METRICS container, ignoring: %m");
1855 r
= sd_netlink_message_read_data(message
, RTA_MULTIPATH
, &rta_len
, &rta_multipath
);
1856 if (r
< 0 && r
!= -ENODATA
) {
1857 log_link_warning_errno(link
, r
, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
1859 } else if (r
>= 0) {
1860 r
= rtattr_read_nexthop(rta_multipath
, rta_len
, tmp
->family
, &tmp
->multipath_routes
);
1862 log_link_warning_errno(link
, r
, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
1867 r
= sd_netlink_message_read(message
, RTA_CACHEINFO
, sizeof(cacheinfo
), &cacheinfo
);
1868 if (r
< 0 && r
!= -ENODATA
) {
1869 log_link_warning_errno(link
, r
, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1872 has_cacheinfo
= r
>= 0;
1874 /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
1875 * fib6_nh_init() in net/ipv6/route.c. However, we'd like to manage them by Manager. Hence, set
1876 * link to NULL here. */
1877 if (route_type_is_reject(tmp
))
1880 if (!route_needs_convert(tmp
))
1881 return process_route_one(m
, link
, type
, TAKE_PTR(tmp
), has_cacheinfo
? &cacheinfo
: NULL
);
1883 r
= route_convert(m
, tmp
, &converted
);
1885 log_link_warning_errno(link
, r
, "rtnl: failed to convert received route, ignoring: %m");
1892 for (size_t i
= 0; i
< converted
->n
; i
++)
1893 (void) process_route_one(m
,
1894 converted
->links
[i
] ?: link
,
1896 TAKE_PTR(converted
->routes
[i
]),
1897 has_cacheinfo
? &cacheinfo
: NULL
);
1902 int network_add_ipv4ll_route(Network
*network
) {
1903 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
1904 unsigned section_line
;
1909 if (!network
->ipv4ll_route
)
1912 section_line
= hashmap_find_free_section_line(network
->routes_by_section
);
1914 /* IPv4LLRoute= is in [Network] section. */
1915 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
1919 r
= in_addr_from_string(AF_INET
, "169.254.0.0", &n
->dst
);
1923 n
->family
= AF_INET
;
1924 n
->dst_prefixlen
= 16;
1925 n
->scope
= RT_SCOPE_LINK
;
1926 n
->scope_set
= true;
1927 n
->table_set
= true;
1928 n
->priority
= IPV4LL_ROUTE_METRIC
;
1929 n
->protocol
= RTPROT_STATIC
;
1935 int network_add_default_route_on_device(Network
*network
) {
1936 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
1937 unsigned section_line
;
1942 if (!network
->default_route_on_device
)
1945 section_line
= hashmap_find_free_section_line(network
->routes_by_section
);
1947 /* DefaultRouteOnDevice= is in [Network] section. */
1948 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
1952 n
->family
= AF_INET
;
1953 n
->scope
= RT_SCOPE_LINK
;
1954 n
->scope_set
= true;
1955 n
->protocol
= RTPROT_STATIC
;
1961 int config_parse_gateway(
1963 const char *filename
,
1965 const char *section
,
1966 unsigned section_line
,
1973 Network
*network
= userdata
;
1974 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
1983 if (streq(section
, "Network")) {
1984 /* we are not in an Route section, so use line number instead */
1985 r
= route_new_static(network
, filename
, line
, &n
);
1989 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1990 "Failed to allocate route, ignoring assignment: %m");
1994 r
= route_new_static(network
, filename
, section_line
, &n
);
1998 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
1999 "Failed to allocate route, ignoring assignment: %m");
2003 if (isempty(rvalue
)) {
2004 n
->gateway_from_dhcp_or_ra
= false;
2005 n
->gw_family
= AF_UNSPEC
;
2006 n
->gw
= IN_ADDR_NULL
;
2011 if (streq(rvalue
, "_dhcp")) {
2012 n
->gateway_from_dhcp_or_ra
= true;
2017 if (streq(rvalue
, "_dhcp4")) {
2018 n
->gw_family
= AF_INET
;
2019 n
->gateway_from_dhcp_or_ra
= true;
2024 if (streq(rvalue
, "_ipv6ra")) {
2025 n
->gw_family
= AF_INET6
;
2026 n
->gateway_from_dhcp_or_ra
= true;
2032 r
= in_addr_from_string_auto(rvalue
, &n
->gw_family
, &n
->gw
);
2034 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2035 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2039 n
->gateway_from_dhcp_or_ra
= false;
2044 int config_parse_preferred_src(
2046 const char *filename
,
2048 const char *section
,
2049 unsigned section_line
,
2056 Network
*network
= userdata
;
2057 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2066 r
= route_new_static(network
, filename
, section_line
, &n
);
2070 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2071 "Failed to allocate route, ignoring assignment: %m");
2075 if (n
->family
== AF_UNSPEC
)
2076 r
= in_addr_from_string_auto(rvalue
, &n
->family
, &n
->prefsrc
);
2078 r
= in_addr_from_string(n
->family
, rvalue
, &n
->prefsrc
);
2080 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2081 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2089 int config_parse_destination(
2091 const char *filename
,
2093 const char *section
,
2094 unsigned section_line
,
2101 Network
*network
= userdata
;
2102 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2103 union in_addr_union
*buffer
;
2104 unsigned char *prefixlen
;
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 (streq(lvalue
, "Destination")) {
2124 prefixlen
= &n
->dst_prefixlen
;
2125 } else if (streq(lvalue
, "Source")) {
2127 prefixlen
= &n
->src_prefixlen
;
2129 assert_not_reached();
2131 if (n
->family
== AF_UNSPEC
)
2132 r
= in_addr_prefix_from_string_auto(rvalue
, &n
->family
, buffer
, prefixlen
);
2134 r
= in_addr_prefix_from_string(rvalue
, n
->family
, buffer
, prefixlen
);
2136 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2137 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2141 (void) in_addr_mask(n
->family
, buffer
, *prefixlen
);
2147 int config_parse_route_priority(
2149 const char *filename
,
2151 const char *section
,
2152 unsigned section_line
,
2159 Network
*network
= userdata
;
2160 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2169 r
= route_new_static(network
, filename
, section_line
, &n
);
2173 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2174 "Failed to allocate route, ignoring assignment: %m");
2178 r
= safe_atou32(rvalue
, &n
->priority
);
2180 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2181 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue
);
2185 n
->priority_set
= true;
2190 int config_parse_route_scope(
2192 const char *filename
,
2194 const char *section
,
2195 unsigned section_line
,
2202 Network
*network
= userdata
;
2203 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2212 r
= route_new_static(network
, filename
, section_line
, &n
);
2216 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2217 "Failed to allocate route, ignoring assignment: %m");
2221 r
= route_scope_from_string(rvalue
);
2223 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Unknown route scope: %s", rvalue
);
2228 n
->scope_set
= true;
2233 int config_parse_route_nexthop(
2235 const char *filename
,
2237 const char *section
,
2238 unsigned section_line
,
2245 Network
*network
= userdata
;
2246 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2256 r
= route_new_static(network
, filename
, section_line
, &n
);
2260 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2261 "Failed to allocate route, ignoring assignment: %m");
2265 if (isempty(rvalue
)) {
2271 r
= safe_atou32(rvalue
, &id
);
2273 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue
);
2277 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue
);
2286 int config_parse_route_table(
2288 const char *filename
,
2290 const char *section
,
2291 unsigned section_line
,
2298 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2299 Network
*network
= userdata
;
2308 r
= route_new_static(network
, filename
, section_line
, &n
);
2312 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2313 "Failed to allocate route, ignoring assignment: %m");
2317 r
= manager_get_route_table_from_string(network
->manager
, rvalue
, &n
->table
);
2319 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2320 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue
);
2324 n
->table_set
= true;
2329 int config_parse_route_boolean(
2331 const char *filename
,
2333 const char *section
,
2334 unsigned section_line
,
2341 Network
*network
= userdata
;
2342 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2351 r
= route_new_static(network
, filename
, section_line
, &n
);
2355 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2356 "Failed to allocate route, ignoring assignment: %m");
2360 r
= parse_boolean(rvalue
);
2362 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2363 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2367 if (STR_IN_SET(lvalue
, "GatewayOnLink", "GatewayOnlink"))
2368 n
->gateway_onlink
= r
;
2369 else if (streq(lvalue
, "QuickAck"))
2371 else if (streq(lvalue
, "FastOpenNoCookie"))
2372 n
->fast_open_no_cookie
= r
;
2373 else if (streq(lvalue
, "TTLPropagate"))
2374 n
->ttl_propagate
= r
;
2376 assert_not_reached();
2382 int config_parse_ipv6_route_preference(
2384 const char *filename
,
2386 const char *section
,
2387 unsigned section_line
,
2394 Network
*network
= userdata
;
2395 _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 if (streq(rvalue
, "low"))
2408 n
->pref
= ICMPV6_ROUTER_PREF_LOW
;
2409 else if (streq(rvalue
, "medium"))
2410 n
->pref
= ICMPV6_ROUTER_PREF_MEDIUM
;
2411 else if (streq(rvalue
, "high"))
2412 n
->pref
= ICMPV6_ROUTER_PREF_HIGH
;
2414 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown route preference: %s", rvalue
);
2423 int config_parse_route_protocol(
2425 const char *filename
,
2427 const char *section
,
2428 unsigned section_line
,
2435 Network
*network
= userdata
;
2436 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2439 r
= route_new_static(network
, filename
, section_line
, &n
);
2443 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2444 "Failed to allocate route, ignoring assignment: %m");
2448 r
= route_protocol_from_string(rvalue
);
2450 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2451 "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue
);
2461 int config_parse_route_type(
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 t
= route_type_from_string(rvalue
);
2488 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2489 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue
);
2493 n
->type
= (unsigned char) t
;
2499 int config_parse_tcp_advmss(
2501 const char *filename
,
2503 const char *section
,
2504 unsigned section_line
,
2511 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2512 Network
*network
= userdata
;
2522 r
= route_new_static(network
, filename
, section_line
, &n
);
2526 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2527 "Failed to allocate route, ignoring assignment: %m");
2531 if (isempty(rvalue
)) {
2537 r
= parse_size(rvalue
, 1024, &u
);
2539 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2540 "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2544 if (u
== 0 || u
> UINT32_MAX
) {
2545 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2546 "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2556 int config_parse_tcp_window(
2558 const char *filename
,
2560 const char *section
,
2561 unsigned section_line
,
2568 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2569 Network
*network
= userdata
;
2579 r
= route_new_static(network
, filename
, section_line
, &n
);
2583 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2584 "Failed to allocate route, ignoring assignment: %m");
2588 r
= safe_atou32(rvalue
, &k
);
2590 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2591 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2595 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2596 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue
, rvalue
);
2600 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2601 "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2605 if (streq(lvalue
, "InitialCongestionWindow"))
2607 else if (streq(lvalue
, "InitialAdvertisedReceiveWindow"))
2610 assert_not_reached();
2616 int config_parse_route_mtu(
2618 const char *filename
,
2620 const char *section
,
2621 unsigned section_line
,
2628 Network
*network
= userdata
;
2629 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2638 r
= route_new_static(network
, filename
, section_line
, &n
);
2642 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2643 "Failed to allocate route, ignoring assignment: %m");
2647 r
= config_parse_mtu(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &n
->mtu
, userdata
);
2655 int config_parse_multipath_route(
2657 const char *filename
,
2659 const char *section
,
2660 unsigned section_line
,
2667 _cleanup_(multipath_route_freep
) MultipathRoute
*m
= NULL
;
2668 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2669 _cleanup_free_
char *word
= NULL
;
2670 Network
*network
= userdata
;
2671 union in_addr_union a
;
2682 r
= route_new_static(network
, filename
, section_line
, &n
);
2686 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2687 "Failed to allocate route, ignoring assignment: %m");
2691 if (isempty(rvalue
)) {
2692 n
->multipath_routes
= ordered_set_free_with_destructor(n
->multipath_routes
, multipath_route_free
);
2696 m
= new0(MultipathRoute
, 1);
2701 r
= extract_first_word(&p
, &word
, NULL
, 0);
2705 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2706 "Invalid multipath route option, ignoring assignment: %s", rvalue
);
2710 dev
= strchr(word
, '@');
2714 r
= parse_ifindex(dev
);
2718 if (!ifname_valid_full(dev
, IFNAME_VALID_ALTERNATIVE
)) {
2719 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2720 "Invalid interface name '%s' in %s=, ignoring: %s", dev
, lvalue
, rvalue
);
2724 m
->ifname
= strdup(dev
);
2730 r
= in_addr_from_string_auto(word
, &family
, &a
);
2732 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2733 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue
);
2736 m
->gateway
.address
= a
;
2737 m
->gateway
.family
= family
;
2740 r
= safe_atou32(p
, &m
->weight
);
2742 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2743 "Invalid multipath route weight, ignoring assignment: %s", p
);
2746 /* ip command takes weight in the range 1…255, while kernel takes the value in the
2747 * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip
2748 * command uses, then networkd decreases by one and stores it to match the range which
2750 if (m
->weight
== 0 || m
->weight
> 256) {
2751 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2752 "Invalid multipath route weight, ignoring assignment: %s", p
);
2758 r
= ordered_set_ensure_put(&n
->multipath_routes
, NULL
, m
);
2762 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2763 "Failed to store multipath route, ignoring assignment: %m");
2772 static int route_section_verify(Route
*route
, Network
*network
) {
2773 if (section_is_invalid(route
->section
))
2776 /* Currently, we do not support static route with finite lifetime. */
2777 assert(route
->lifetime_usec
== USEC_INFINITY
);
2779 if (route
->gateway_from_dhcp_or_ra
) {
2780 if (route
->gw_family
== AF_UNSPEC
) {
2781 /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
2782 switch (route
->family
) {
2784 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
2785 "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
2786 route
->section
->filename
, route
->section
->line
);
2787 route
->family
= AF_INET
;
2791 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
2792 "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
2793 route
->section
->filename
, route
->section
->line
, route
->family
== AF_INET
? "_dhcp4" : "_ipv6ra");
2796 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
2797 "%s: Invalid route family. Ignoring [Route] section from line %u.",
2798 route
->section
->filename
, route
->section
->line
);
2800 route
->gw_family
= route
->family
;
2803 if (route
->gw_family
== AF_INET
&& !FLAGS_SET(network
->dhcp
, ADDRESS_FAMILY_IPV4
))
2804 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
2805 "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
2806 "Ignoring [Route] section from line %u.",
2807 route
->section
->filename
, route
->section
->line
);
2809 if (route
->gw_family
== AF_INET6
&& !network
->ipv6_accept_ra
)
2810 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
2811 "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
2812 "Ignoring [Route] section from line %u.",
2813 route
->section
->filename
, route
->section
->line
);
2816 /* When only Gateway= is specified, assume the route family based on the Gateway address. */
2817 if (route
->family
== AF_UNSPEC
)
2818 route
->family
= route
->gw_family
;
2820 if (route
->family
== AF_UNSPEC
) {
2821 assert(route
->section
);
2823 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
2824 "%s: Route section without Gateway=, Destination=, Source=, "
2825 "or PreferredSource= field configured. "
2826 "Ignoring [Route] section from line %u.",
2827 route
->section
->filename
, route
->section
->line
);
2830 if (route
->family
== AF_INET6
&& route
->gw_family
== AF_INET
)
2831 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
2832 "%s: IPv4 gateway is configured for IPv6 route. "
2833 "Ignoring [Route] section from line %u.",
2834 route
->section
->filename
, route
->section
->line
);
2836 if (!route
->table_set
&& network
->vrf
) {
2837 route
->table
= VRF(network
->vrf
)->table
;
2838 route
->table_set
= true;
2841 if (!route
->table_set
&& IN_SET(route
->type
, RTN_LOCAL
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_NAT
))
2842 route
->table
= RT_TABLE_LOCAL
;
2844 if (!route
->scope_set
&& route
->family
!= AF_INET6
) {
2845 if (IN_SET(route
->type
, RTN_LOCAL
, RTN_NAT
))
2846 route
->scope
= RT_SCOPE_HOST
;
2847 else if (IN_SET(route
->type
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_MULTICAST
))
2848 route
->scope
= RT_SCOPE_LINK
;
2851 if (route
->scope
!= RT_SCOPE_UNIVERSE
&& route
->family
== AF_INET6
) {
2852 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route
->section
->filename
);
2853 route
->scope
= RT_SCOPE_UNIVERSE
;
2856 if (route
->family
== AF_INET6
&& route
->priority
== 0)
2857 route
->priority
= IP6_RT_PRIO_USER
;
2859 if (route
->gateway_onlink
< 0 && in_addr_is_set(route
->gw_family
, &route
->gw
) &&
2860 ordered_hashmap_isempty(network
->addresses_by_section
)) {
2861 /* If no address is configured, in most cases the gateway cannot be reachable.
2862 * TODO: we may need to improve the condition above. */
2863 log_warning("%s: Gateway= without static address configured. "
2864 "Enabling GatewayOnLink= option.",
2866 route
->gateway_onlink
= true;
2869 if (route
->gateway_onlink
>= 0)
2870 SET_FLAG(route
->flags
, RTNH_F_ONLINK
, route
->gateway_onlink
);
2872 if (route
->family
== AF_INET6
) {
2875 ORDERED_SET_FOREACH(m
, route
->multipath_routes
)
2876 if (m
->gateway
.family
== AF_INET
)
2877 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
2878 "%s: IPv4 multipath route is specified for IPv6 route. "
2879 "Ignoring [Route] section from line %u.",
2880 route
->section
->filename
, route
->section
->line
);
2883 if ((route
->gateway_from_dhcp_or_ra
||
2884 in_addr_is_set(route
->gw_family
, &route
->gw
)) &&
2885 !ordered_set_isempty(route
->multipath_routes
))
2886 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
2887 "%s: Gateway= cannot be specified with MultiPathRoute=. "
2888 "Ignoring [Route] section from line %u.",
2889 route
->section
->filename
, route
->section
->line
);
2891 if (route
->nexthop_id
> 0 &&
2892 (route
->gateway_from_dhcp_or_ra
||
2893 in_addr_is_set(route
->gw_family
, &route
->gw
) ||
2894 !ordered_set_isempty(route
->multipath_routes
)))
2895 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
2896 "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
2897 "Ignoring [Route] section from line %u.",
2898 route
->section
->filename
, route
->section
->line
);
2903 void network_drop_invalid_routes(Network
*network
) {
2908 HASHMAP_FOREACH(route
, network
->routes_by_section
)
2909 if (route_section_verify(route
, network
) < 0)