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 "netlink-util.h"
9 #include "networkd-ipv4ll.h"
10 #include "networkd-manager.h"
11 #include "networkd-network.h"
12 #include "networkd-nexthop.h"
13 #include "networkd-queue.h"
14 #include "networkd-route.h"
15 #include "parse-util.h"
16 #include "socket-netlink.h"
17 #include "string-table.h"
18 #include "string-util.h"
21 #include "sysctl-util.h"
24 #define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
26 static uint32_t link_get_vrf_table(const Link
*link
) {
27 return link
->network
->vrf
? VRF(link
->network
->vrf
)->table
: RT_TABLE_MAIN
;
30 uint32_t link_get_dhcp_route_table(const Link
*link
) {
31 /* When the interface is part of an VRF use the VRFs routing table, unless
32 * another table is explicitly specified. */
33 if (link
->network
->dhcp_route_table_set
)
34 return link
->network
->dhcp_route_table
;
35 return link_get_vrf_table(link
);
38 uint32_t link_get_ipv6_accept_ra_route_table(const Link
*link
) {
39 if (link
->network
->ipv6_accept_ra_route_table_set
)
40 return link
->network
->ipv6_accept_ra_route_table
;
41 return link_get_vrf_table(link
);
44 static const char * const route_type_table
[__RTN_MAX
] = {
45 [RTN_UNICAST
] = "unicast",
46 [RTN_LOCAL
] = "local",
47 [RTN_BROADCAST
] = "broadcast",
48 [RTN_ANYCAST
] = "anycast",
49 [RTN_MULTICAST
] = "multicast",
50 [RTN_BLACKHOLE
] = "blackhole",
51 [RTN_UNREACHABLE
] = "unreachable",
52 [RTN_PROHIBIT
] = "prohibit",
53 [RTN_THROW
] = "throw",
55 [RTN_XRESOLVE
] = "xresolve",
58 assert_cc(__RTN_MAX
<= UCHAR_MAX
);
59 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_type
, int);
61 static const char * const route_scope_table
[] = {
62 [RT_SCOPE_UNIVERSE
] = "global",
63 [RT_SCOPE_SITE
] = "site",
64 [RT_SCOPE_LINK
] = "link",
65 [RT_SCOPE_HOST
] = "host",
66 [RT_SCOPE_NOWHERE
] = "nowhere",
69 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_scope
, int);
70 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(route_scope
, int, UINT8_MAX
);
72 static const char * const route_table_table
[] = {
73 [RT_TABLE_DEFAULT
] = "default",
74 [RT_TABLE_MAIN
] = "main",
75 [RT_TABLE_LOCAL
] = "local",
78 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table
, int);
80 int manager_get_route_table_from_string(const Manager
*m
, const char *s
, uint32_t *ret
) {
88 r
= route_table_from_string(s
);
94 t
= PTR_TO_UINT32(hashmap_get(m
->route_table_numbers_by_name
, s
));
100 r
= safe_atou32(s
, &t
);
111 int manager_get_route_table_to_string(const Manager
*m
, uint32_t table
, char **ret
) {
112 _cleanup_free_
char *str
= NULL
;
121 s
= route_table_to_string(table
);
123 s
= hashmap_get(m
->route_table_names_by_number
, UINT32_TO_PTR(table
));
126 /* Currently, this is only used in debugging logs. To not confuse any bug
127 * reports, let's include the table number. */
128 if (asprintf(&str
, "%s(%" PRIu32
")", s
, table
) < 0)
131 *ret
= TAKE_PTR(str
);
135 if (asprintf(&str
, "%" PRIu32
, table
) < 0)
138 *ret
= TAKE_PTR(str
);
142 static const char * const route_protocol_table
[] = {
143 [RTPROT_KERNEL
] = "kernel",
144 [RTPROT_BOOT
] = "boot",
145 [RTPROT_STATIC
] = "static",
148 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(route_protocol
, int, UINT8_MAX
);
150 static const char * const route_protocol_full_table
[] = {
151 [RTPROT_REDIRECT
] = "redirect",
152 [RTPROT_KERNEL
] = "kernel",
153 [RTPROT_BOOT
] = "boot",
154 [RTPROT_STATIC
] = "static",
155 [RTPROT_GATED
] = "gated",
157 [RTPROT_MRT
] = "mrt",
158 [RTPROT_ZEBRA
] = "zebra",
159 [RTPROT_BIRD
] = "bird",
160 [RTPROT_DNROUTED
] = "dnrouted",
161 [RTPROT_XORP
] = "xorp",
162 [RTPROT_NTK
] = "ntk",
163 [RTPROT_DHCP
] = "dhcp",
164 [RTPROT_MROUTED
] = "mrouted",
165 [RTPROT_BABEL
] = "babel",
166 [RTPROT_BGP
] = "bgp",
167 [RTPROT_ISIS
] = "isis",
168 [RTPROT_OSPF
] = "ospf",
169 [RTPROT_RIP
] = "rip",
170 [RTPROT_EIGRP
] = "eigrp",
173 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(route_protocol_full
, int, UINT8_MAX
);
175 static unsigned routes_max(void) {
176 static thread_local
unsigned cached
= 0;
177 _cleanup_free_
char *s4
= NULL
, *s6
= NULL
;
178 unsigned val4
= ROUTES_DEFAULT_MAX_PER_FAMILY
, val6
= ROUTES_DEFAULT_MAX_PER_FAMILY
;
183 if (sysctl_read_ip_property(AF_INET
, NULL
, "route/max_size", &s4
) >= 0)
184 if (safe_atou(s4
, &val4
) >= 0 && val4
== 2147483647U)
185 /* This is the default "no limit" value in the kernel */
186 val4
= ROUTES_DEFAULT_MAX_PER_FAMILY
;
188 if (sysctl_read_ip_property(AF_INET6
, NULL
, "route/max_size", &s6
) >= 0)
189 (void) safe_atou(s6
, &val6
);
191 cached
= MAX(ROUTES_DEFAULT_MAX_PER_FAMILY
, val4
) +
192 MAX(ROUTES_DEFAULT_MAX_PER_FAMILY
, val6
);
196 int route_new(Route
**ret
) {
197 _cleanup_(route_freep
) Route
*route
= NULL
;
199 route
= new(Route
, 1);
205 .scope
= RT_SCOPE_UNIVERSE
,
206 .protocol
= RTPROT_UNSPEC
,
208 .table
= RT_TABLE_MAIN
,
209 .lifetime
= USEC_INFINITY
,
211 .fast_open_no_cookie
= -1,
212 .gateway_onlink
= -1,
216 *ret
= TAKE_PTR(route
);
221 static int route_new_static(Network
*network
, const char *filename
, unsigned section_line
, Route
**ret
) {
222 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
223 _cleanup_(route_freep
) Route
*route
= NULL
;
229 assert(section_line
> 0);
231 r
= network_config_section_new(filename
, section_line
, &n
);
235 route
= hashmap_get(network
->routes_by_section
, n
);
237 *ret
= TAKE_PTR(route
);
241 if (hashmap_size(network
->routes_by_section
) >= routes_max())
244 r
= route_new(&route
);
248 route
->protocol
= RTPROT_STATIC
;
249 route
->network
= network
;
250 route
->section
= TAKE_PTR(n
);
252 r
= hashmap_ensure_put(&network
->routes_by_section
, &network_config_hash_ops
, route
->section
, route
);
256 *ret
= TAKE_PTR(route
);
260 Route
*route_free(Route
*route
) {
264 if (route
->network
) {
265 assert(route
->section
);
266 hashmap_remove(route
->network
->routes_by_section
, route
->section
);
269 network_config_section_free(route
->section
);
274 set_remove(route
->link
->routes
, route
);
275 set_remove(route
->link
->routes_foreign
, route
);
276 set_remove(route
->link
->dhcp_routes
, route
);
277 set_remove(route
->link
->dhcp_routes_old
, route
);
278 set_remove(route
->link
->dhcp6_routes
, route
);
279 set_remove(route
->link
->dhcp6_routes_old
, route
);
280 set_remove(route
->link
->dhcp6_pd_routes
, route
);
281 set_remove(route
->link
->dhcp6_pd_routes_old
, route
);
282 SET_FOREACH(n
, route
->link
->ndisc_routes
)
283 if (n
->route
== route
)
284 free(set_remove(route
->link
->ndisc_routes
, n
));
287 if (route
->manager
) {
288 set_remove(route
->manager
->routes
, route
);
289 set_remove(route
->manager
->routes_foreign
, route
);
292 ordered_set_free_with_destructor(route
->multipath_routes
, multipath_route_free
);
294 sd_event_source_unref(route
->expire
);
299 void route_hash_func(const Route
*route
, struct siphash
*state
) {
302 siphash24_compress(&route
->family
, sizeof(route
->family
), state
);
304 switch (route
->family
) {
307 siphash24_compress(&route
->dst_prefixlen
, sizeof(route
->dst_prefixlen
), state
);
308 siphash24_compress(&route
->dst
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
310 siphash24_compress(&route
->src_prefixlen
, sizeof(route
->src_prefixlen
), state
);
311 siphash24_compress(&route
->src
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
313 siphash24_compress(&route
->gw_family
, sizeof(route
->gw_family
), state
);
314 if (IN_SET(route
->gw_family
, AF_INET
, AF_INET6
)) {
315 siphash24_compress(&route
->gw
, FAMILY_ADDRESS_SIZE(route
->gw_family
), state
);
316 siphash24_compress(&route
->gw_weight
, sizeof(route
->gw_weight
), state
);
319 siphash24_compress(&route
->prefsrc
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
321 siphash24_compress(&route
->tos
, sizeof(route
->tos
), state
);
322 siphash24_compress(&route
->priority
, sizeof(route
->priority
), state
);
323 siphash24_compress(&route
->table
, sizeof(route
->table
), state
);
324 siphash24_compress(&route
->protocol
, sizeof(route
->protocol
), state
);
325 siphash24_compress(&route
->scope
, sizeof(route
->scope
), state
);
326 siphash24_compress(&route
->type
, sizeof(route
->type
), state
);
328 siphash24_compress(&route
->initcwnd
, sizeof(route
->initcwnd
), state
);
329 siphash24_compress(&route
->initrwnd
, sizeof(route
->initrwnd
), state
);
331 siphash24_compress(&route
->advmss
, sizeof(route
->advmss
), state
);
332 siphash24_compress(&route
->nexthop_id
, sizeof(route
->nexthop_id
), state
);
336 /* treat any other address family as AF_UNSPEC */
341 int route_compare_func(const Route
*a
, const Route
*b
) {
344 r
= CMP(a
->family
, b
->family
);
351 r
= CMP(a
->dst_prefixlen
, b
->dst_prefixlen
);
355 r
= memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
359 r
= CMP(a
->src_prefixlen
, b
->src_prefixlen
);
363 r
= memcmp(&a
->src
, &b
->src
, FAMILY_ADDRESS_SIZE(a
->family
));
367 r
= CMP(a
->gw_family
, b
->gw_family
);
371 if (IN_SET(a
->gw_family
, AF_INET
, AF_INET6
)) {
372 r
= memcmp(&a
->gw
, &b
->gw
, FAMILY_ADDRESS_SIZE(a
->family
));
376 r
= CMP(a
->gw_weight
, b
->gw_weight
);
381 r
= memcmp(&a
->prefsrc
, &b
->prefsrc
, FAMILY_ADDRESS_SIZE(a
->family
));
385 r
= CMP(a
->tos
, b
->tos
);
389 r
= CMP(a
->priority
, b
->priority
);
393 r
= CMP(a
->table
, b
->table
);
397 r
= CMP(a
->protocol
, b
->protocol
);
401 r
= CMP(a
->scope
, b
->scope
);
405 r
= CMP(a
->type
, b
->type
);
409 r
= CMP(a
->initcwnd
, b
->initcwnd
);
413 r
= CMP(a
->initrwnd
, b
->initrwnd
);
417 r
= CMP(a
->advmss
, b
->advmss
);
421 r
= CMP(a
->nexthop_id
, b
->nexthop_id
);
427 /* treat any other address family as AF_UNSPEC */
432 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
439 static bool route_equal(const Route
*r1
, const Route
*r2
) {
446 return route_compare_func(r1
, r2
) == 0;
449 static int route_get(const Manager
*manager
, const Link
*link
, const Route
*in
, Route
**ret
) {
452 assert(manager
|| link
);
455 existing
= set_get(link
? link
->routes
: manager
->routes
, in
);
462 existing
= set_get(link
? link
->routes_foreign
: manager
->routes_foreign
, in
);
472 static void route_copy(Route
*dest
, const Route
*src
, const MultipathRoute
*m
, const NextHop
*nh
, uint8_t nh_weight
) {
476 /* This only copies entries used by the above hash and compare functions. */
478 dest
->family
= src
->family
;
479 dest
->src
= src
->src
;
480 dest
->src_prefixlen
= src
->src_prefixlen
;
481 dest
->dst
= src
->dst
;
482 dest
->dst_prefixlen
= src
->dst_prefixlen
;
483 dest
->prefsrc
= src
->prefsrc
;
484 dest
->scope
= src
->scope
;
485 dest
->protocol
= src
->protocol
;
486 if (nh
&& nh
->blackhole
)
487 dest
->type
= RTN_BLACKHOLE
;
489 dest
->type
= src
->type
;
490 dest
->tos
= src
->tos
;
491 dest
->priority
= src
->priority
;
492 dest
->table
= src
->table
;
493 dest
->initcwnd
= src
->initcwnd
;
494 dest
->initrwnd
= src
->initrwnd
;
495 dest
->lifetime
= src
->lifetime
;
496 dest
->advmss
= src
->advmss
;
497 dest
->nexthop_id
= src
->nexthop_id
;
500 assert(hashmap_isempty(nh
->group
));
502 dest
->gw_family
= nh
->family
;
504 dest
->gw_weight
= nh_weight
!= UINT8_MAX
? nh_weight
: src
->gw_weight
;
506 dest
->gw_family
= m
->gateway
.family
;
507 dest
->gw
= m
->gateway
.address
;
508 dest
->gw_weight
= m
->weight
;
510 dest
->gw_family
= src
->gw_family
;
512 dest
->gw_weight
= src
->gw_weight
;
516 int route_dup(const Route
*src
, Route
**ret
) {
517 _cleanup_(route_freep
) Route
*dest
= NULL
;
524 dest
= newdup(Route
, src
, 1);
528 /* Unset all pointers */
529 dest
->network
= NULL
;
530 dest
->section
= NULL
;
532 dest
->manager
= NULL
;
533 dest
->multipath_routes
= NULL
;
536 ORDERED_SET_FOREACH(m
, src
->multipath_routes
) {
537 _cleanup_(multipath_route_freep
) MultipathRoute
*n
= NULL
;
539 r
= multipath_route_dup(m
, &n
);
543 r
= ordered_set_ensure_put(&dest
->multipath_routes
, NULL
, n
);
550 *ret
= TAKE_PTR(dest
);
554 static int route_add_internal(Manager
*manager
, Link
*link
, Set
**routes
, const Route
*in
, Route
**ret
) {
555 _cleanup_(route_freep
) Route
*route
= NULL
;
558 assert(manager
|| link
);
562 r
= route_new(&route
);
566 route_copy(route
, in
, NULL
, NULL
, UINT8_MAX
);
568 r
= set_ensure_put(routes
, &route_hash_ops
, route
);
575 route
->manager
= manager
;
585 static int route_add_foreign(Manager
*manager
, Link
*link
, const Route
*in
, Route
**ret
) {
586 assert(manager
|| link
);
587 return route_add_internal(manager
, link
, link
? &link
->routes_foreign
: &manager
->routes_foreign
, in
, ret
);
590 static int route_add(Manager
*manager
, Link
*link
, const Route
*in
, const MultipathRoute
*m
, const NextHop
*nh
, uint8_t nh_weight
, Route
**ret
) {
591 _cleanup_(route_freep
) Route
*tmp
= NULL
;
595 assert(manager
|| link
);
599 assert(hashmap_isempty(nh
->group
));
605 route_copy(tmp
, in
, NULL
, nh
, nh_weight
);
608 assert(link
&& (m
->ifindex
== 0 || m
->ifindex
== link
->ifindex
));
614 route_copy(tmp
, in
, m
, NULL
, UINT8_MAX
);
618 r
= route_get(manager
, link
, in
, &route
);
620 /* Route does not exist, create a new one */
621 r
= route_add_internal(manager
, link
, link
? &link
->routes
: &manager
->routes
, in
, &route
);
625 /* Take over a foreign route */
626 r
= set_ensure_put(link
? &link
->routes
: &manager
->routes
, &route_hash_ops
, route
);
630 set_remove(link
? link
->routes_foreign
: manager
->routes_foreign
, route
);
632 /* Route exists, do nothing */
642 static bool route_type_is_reject(const Route
*route
) {
645 return IN_SET(route
->type
, RTN_UNREACHABLE
, RTN_PROHIBIT
, RTN_BLACKHOLE
, RTN_THROW
);
648 static int link_has_route_one(Link
*link
, const Route
*route
, const NextHop
*nh
, uint8_t nh_weight
) {
649 _cleanup_(route_freep
) Route
*tmp
= NULL
;
660 route_copy(tmp
, route
, NULL
, nh
, nh_weight
);
662 if (route_type_is_reject(route
) || (nh
&& nh
->blackhole
))
663 return route_get(link
->manager
, NULL
, tmp
, NULL
) >= 0;
665 return route_get(NULL
, link
, tmp
, NULL
) >= 0;
668 int link_has_route(Link
*link
, const Route
*route
) {
675 if (route
->nexthop_id
> 0) {
676 struct nexthop_grp
*nhg
;
679 if (manager_get_nexthop_by_id(link
->manager
, route
->nexthop_id
, &nh
) < 0)
682 if (hashmap_isempty(nh
->group
))
683 return link_has_route_one(link
, route
, nh
, UINT8_MAX
);
685 HASHMAP_FOREACH(nhg
, nh
->group
) {
688 if (manager_get_nexthop_by_id(link
->manager
, nhg
->id
, &h
) < 0)
691 r
= link_has_route_one(link
, route
, h
, nhg
->weight
);
699 if (ordered_set_isempty(route
->multipath_routes
)) {
700 if (route_type_is_reject(route
))
701 return route_get(link
->manager
, NULL
, route
, NULL
) >= 0;
703 return route_get(NULL
, link
, route
, NULL
) >= 0;
706 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
707 _cleanup_(route_freep
) Route
*tmp
= NULL
;
711 r
= resolve_interface(&link
->manager
->rtnl
, m
->ifname
);
716 if (link_get(link
->manager
, m
->ifindex
, &l
) < 0)
725 route_copy(tmp
, route
, m
, NULL
, UINT8_MAX
);
727 if (route_get(NULL
, l
, tmp
, NULL
) < 0)
734 static bool route_address_is_reachable(const Route
*route
, int family
, const union in_addr_union
*address
) {
736 assert(IN_SET(family
, AF_INET
, AF_INET6
));
739 if (route
->family
!= family
)
742 if (!in_addr_is_set(route
->family
, &route
->dst
))
745 return in_addr_prefix_intersect(
748 route
->dst_prefixlen
,
750 FAMILY_ADDRESS_SIZE(family
) * 8) > 0;
753 bool manager_address_is_reachable(Manager
*manager
, int family
, const union in_addr_union
*address
) {
757 assert(IN_SET(family
, AF_INET
, AF_INET6
));
760 HASHMAP_FOREACH(link
, manager
->links
) {
763 SET_FOREACH(route
, link
->routes
)
764 if (route_address_is_reachable(route
, family
, address
))
766 SET_FOREACH(route
, link
->routes_foreign
)
767 if (route_address_is_reachable(route
, family
, address
))
774 static Route
*routes_get_default_gateway(Set
*routes
, int family
, Route
*gw
) {
777 SET_FOREACH(route
, routes
) {
778 if (family
!= AF_UNSPEC
&& route
->family
!= family
)
780 if (route
->dst_prefixlen
!= 0)
782 if (route
->src_prefixlen
!= 0)
784 if (route
->table
!= RT_TABLE_MAIN
)
786 if (route
->type
!= RTN_UNICAST
)
788 if (route
->scope
!= RT_SCOPE_UNIVERSE
)
790 if (!in_addr_is_set(route
->gw_family
, &route
->gw
))
793 if (route
->gw_weight
> gw
->gw_weight
)
795 if (route
->priority
>= gw
->priority
)
804 int manager_find_uplink(Manager
*m
, int family
, Link
*exclude
, Link
**ret
) {
809 assert(IN_SET(family
, AF_UNSPEC
, AF_INET
, AF_INET6
));
811 /* Looks for a suitable "uplink", via black magic: an interface that is up and where the
812 * default route with the highest priority points to. */
814 HASHMAP_FOREACH(link
, m
->links
) {
818 if (link
->state
!= LINK_STATE_CONFIGURED
)
821 gw
= routes_get_default_gateway(link
->routes
, family
, gw
);
822 gw
= routes_get_default_gateway(link
->routes_foreign
, family
, gw
);
833 static void log_route_debug(const Route
*route
, const char *str
, const Link
*link
, const Manager
*manager
) {
834 _cleanup_free_
char *dst
= NULL
, *src
= NULL
, *gw_alloc
= NULL
, *prefsrc
= NULL
,
835 *table
= NULL
, *scope
= NULL
, *proto
= NULL
;
836 const char *gw
= NULL
;
842 /* link may be NULL. */
847 if (in_addr_is_set(route
->family
, &route
->dst
))
848 (void) in_addr_prefix_to_string(route
->family
, &route
->dst
, route
->dst_prefixlen
, &dst
);
849 if (in_addr_is_set(route
->family
, &route
->src
))
850 (void) in_addr_to_string(route
->family
, &route
->src
, &src
);
851 if (in_addr_is_set(route
->gw_family
, &route
->gw
)) {
852 (void) in_addr_to_string(route
->gw_family
, &route
->gw
, &gw_alloc
);
854 } else if (route
->gateway_from_dhcp_or_ra
) {
855 if (route
->gw_family
== AF_INET
)
857 else if (route
->gw_family
== AF_INET6
)
862 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
863 _cleanup_free_
char *buf
= NULL
;
864 union in_addr_union a
= m
->gateway
.address
;
866 (void) in_addr_to_string(m
->gateway
.family
, &a
, &buf
);
867 (void) strextend_with_separator(&gw_alloc
, ",", strna(buf
));
869 (void) strextend(&gw_alloc
, "@", m
->ifname
);
870 else if (m
->ifindex
> 0)
871 (void) strextendf(&gw_alloc
, "@%"PRIu32
, m
->ifindex
);
872 /* See comments in config_parse_multipath_route(). */
873 (void) strextendf(&gw_alloc
, ":%"PRIu32
, m
->weight
+ 1);
877 if (in_addr_is_set(route
->family
, &route
->prefsrc
))
878 (void) in_addr_to_string(route
->family
, &route
->prefsrc
, &prefsrc
);
879 (void) route_scope_to_string_alloc(route
->scope
, &scope
);
880 (void) manager_get_route_table_to_string(manager
, route
->table
, &table
);
881 (void) route_protocol_full_to_string_alloc(route
->protocol
, &proto
);
884 "%s route: dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s, nexthop: %"PRIu32
", priority: %"PRIu32
,
885 str
, strna(dst
), strna(src
), strna(gw
), strna(prefsrc
),
886 strna(scope
), strna(table
), strna(proto
),
887 strna(route_type_to_string(route
->type
)),
888 route
->nexthop_id
, route
->priority
);
891 static int route_set_netlink_message(const Route
*route
, sd_netlink_message
*req
, Link
*link
) {
898 /* link may be NULL */
900 if (in_addr_is_set(route
->gw_family
, &route
->gw
) && route
->nexthop_id
== 0) {
901 if (route
->gw_family
== route
->family
) {
902 r
= netlink_message_append_in_addr_union(req
, RTA_GATEWAY
, route
->gw_family
, &route
->gw
);
904 return log_link_error_errno(link
, r
, "Could not append RTA_GATEWAY attribute: %m");
907 .family
= route
->gw_family
,
908 .address
= route
->gw
,
911 r
= sd_netlink_message_append_data(req
, RTA_VIA
, &rtvia
, sizeof(rtvia
));
913 return log_link_error_errno(link
, r
, "Could not append RTA_VIA attribute: %m");
917 if (route
->dst_prefixlen
> 0) {
918 r
= netlink_message_append_in_addr_union(req
, RTA_DST
, route
->family
, &route
->dst
);
920 return log_link_error_errno(link
, r
, "Could not append RTA_DST attribute: %m");
922 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
924 return log_link_error_errno(link
, r
, "Could not set destination prefix length: %m");
927 if (route
->src_prefixlen
> 0) {
928 r
= netlink_message_append_in_addr_union(req
, RTA_SRC
, route
->family
, &route
->src
);
930 return log_link_error_errno(link
, r
, "Could not append RTA_SRC attribute: %m");
932 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
934 return log_link_error_errno(link
, r
, "Could not set source prefix length: %m");
937 if (in_addr_is_set(route
->family
, &route
->prefsrc
)) {
938 r
= netlink_message_append_in_addr_union(req
, RTA_PREFSRC
, route
->family
, &route
->prefsrc
);
940 return log_link_error_errno(link
, r
, "Could not append RTA_PREFSRC attribute: %m");
943 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
945 return log_link_error_errno(link
, r
, "Could not set scope: %m");
947 flags
= route
->flags
;
948 if (route
->gateway_onlink
>= 0)
949 SET_FLAG(flags
, RTNH_F_ONLINK
, route
->gateway_onlink
);
951 r
= sd_rtnl_message_route_set_flags(req
, flags
);
953 return log_link_error_errno(link
, r
, "Could not set flags: %m");
955 if (route
->table
< 256) {
956 r
= sd_rtnl_message_route_set_table(req
, route
->table
);
958 return log_link_error_errno(link
, r
, "Could not set route table: %m");
960 r
= sd_rtnl_message_route_set_table(req
, RT_TABLE_UNSPEC
);
962 return log_link_error_errno(link
, r
, "Could not set route table: %m");
964 /* Table attribute to allow more than 256. */
965 r
= sd_netlink_message_append_data(req
, RTA_TABLE
, &route
->table
, sizeof(route
->table
));
967 return log_link_error_errno(link
, r
, "Could not append RTA_TABLE attribute: %m");
970 if (!route_type_is_reject(route
) && route
->nexthop_id
== 0) {
971 assert(link
); /* Those routes must be attached to a specific link */
973 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
975 return log_link_error_errno(link
, r
, "Could not append RTA_OIF attribute: %m");
978 if (route
->nexthop_id
> 0) {
979 r
= sd_netlink_message_append_u32(req
, RTA_NH_ID
, route
->nexthop_id
);
981 return log_link_error_errno(link
, r
, "Could not append RTA_NH_ID attribute: %m");
984 r
= sd_netlink_message_append_u8(req
, RTA_PREF
, route
->pref
);
986 return log_link_error_errno(link
, r
, "Could not append RTA_PREF attribute: %m");
988 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->priority
);
990 return log_link_error_errno(link
, r
, "Could not append RTA_PRIORITY attribute: %m");
995 static int link_route_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
1000 assert(link
->route_remove_messages
> 0);
1002 link
->route_remove_messages
--;
1004 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
1007 r
= sd_netlink_message_get_errno(m
);
1008 if (r
< 0 && r
!= -ESRCH
)
1009 log_link_message_warning_errno(link
, m
, r
, "Could not drop route, ignoring");
1014 static int manager_route_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Manager
*manager
) {
1019 assert(manager
->route_remove_messages
> 0);
1021 manager
->route_remove_messages
--;
1023 r
= sd_netlink_message_get_errno(m
);
1024 if (r
< 0 && r
!= -ESRCH
)
1025 log_message_warning_errno(m
, r
, "Could not drop route, ignoring");
1030 int route_remove(const Route
*route
, Manager
*manager
, Link
*link
) {
1031 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
1035 assert(link
|| manager
);
1036 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
1039 manager
= link
->manager
;
1041 log_route_debug(route
, "Removing", link
, manager
);
1043 r
= sd_rtnl_message_new_route(manager
->rtnl
, &req
,
1044 RTM_DELROUTE
, route
->family
,
1047 return log_link_error_errno(link
, r
, "Could not create RTM_DELROUTE message: %m");
1049 if (route
->family
== AF_INET
&& route
->nexthop_id
> 0 && route
->type
== RTN_BLACKHOLE
)
1050 /* When IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel
1051 * sends RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type
1052 * fib_rt_info::type may not be blackhole. Thus, we cannot know the internal value.
1053 * Moreover, on route removal, the matching is done with the hidden value if we set
1054 * non-zero type in RTM_DELROUTE message. Note, sd_rtnl_message_new_route() sets
1055 * RTN_UNICAST by default. So, we need to clear the type here. */
1060 r
= sd_rtnl_message_route_set_type(req
, type
);
1062 return log_link_error_errno(link
, r
, "Could not set route type: %m");
1064 r
= route_set_netlink_message(route
, req
, link
);
1069 r
= netlink_call_async(manager
->rtnl
, NULL
, req
,
1070 link_route_remove_handler
,
1071 link_netlink_destroy_callback
, link
);
1073 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
1076 link
->route_remove_messages
++;
1078 r
= netlink_call_async(manager
->rtnl
, NULL
, req
,
1079 manager_route_remove_handler
,
1082 return log_error_errno(r
, "Could not send rtnetlink message: %m");
1084 manager
->route_remove_messages
++;
1090 static bool link_has_static_route(const Link
*link
, const Route
*route
) {
1099 HASHMAP_FOREACH(net_route
, link
->network
->routes_by_section
)
1100 if (route_equal(net_route
, route
))
1106 static bool links_have_static_route(const Manager
*manager
, const Route
*route
, const Link
*except
) {
1111 HASHMAP_FOREACH(link
, manager
->links
) {
1115 if (link_has_static_route(link
, route
))
1122 static int manager_drop_routes_internal(Manager
*manager
, bool foreign
, const Link
*except
) {
1129 routes
= foreign
? manager
->routes_foreign
: manager
->routes
;
1130 SET_FOREACH(route
, routes
) {
1131 if (route
->removing
)
1134 /* Do not touch routes managed by the kernel. */
1135 if (route
->protocol
== RTPROT_KERNEL
)
1138 /* The route will be configured later, or already configured by a link. */
1139 if (links_have_static_route(manager
, route
, except
))
1142 /* The existing links do not have the route. Let's drop this now. It may be
1143 * re-configured later. */
1144 k
= route_remove(route
, manager
, NULL
);
1145 if (k
< 0 && r
>= 0)
1148 route
->removing
= true;
1154 static int manager_drop_foreign_routes(Manager
*manager
) {
1155 return manager_drop_routes_internal(manager
, true, NULL
);
1158 static int manager_drop_routes(Manager
*manager
, const Link
*except
) {
1159 return manager_drop_routes_internal(manager
, false, except
);
1162 int link_drop_foreign_routes(Link
*link
) {
1167 assert(link
->manager
);
1169 SET_FOREACH(route
, link
->routes_foreign
) {
1170 /* do not touch routes managed by the kernel */
1171 if (route
->protocol
== RTPROT_KERNEL
)
1174 /* do not touch multicast route added by kernel */
1175 /* FIXME: Why the kernel adds this route with protocol RTPROT_BOOT??? We need to investigate that.
1176 * https://tools.ietf.org/html/rfc4862#section-5.4 may explain why. */
1177 if (route
->protocol
== RTPROT_BOOT
&&
1178 route
->family
== AF_INET6
&&
1179 route
->dst_prefixlen
== 8 &&
1180 in_addr_equal(AF_INET6
, &route
->dst
, &(union in_addr_union
) { .in6
= {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}} }))
1183 if (route
->protocol
== RTPROT_STATIC
&& link
->network
&&
1184 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_STATIC
))
1187 if (route
->protocol
== RTPROT_DHCP
&& link
->network
&&
1188 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_DHCP
))
1191 if (link_has_static_route(link
, route
))
1192 k
= route_add(NULL
, link
, route
, NULL
, NULL
, UINT8_MAX
, NULL
);
1194 k
= route_remove(route
, NULL
, link
);
1195 if (k
< 0 && r
>= 0)
1199 k
= manager_drop_foreign_routes(link
->manager
);
1200 if (k
< 0 && r
>= 0)
1206 int link_drop_routes(Link
*link
) {
1212 SET_FOREACH(route
, link
->routes
) {
1213 /* do not touch routes managed by the kernel */
1214 if (route
->protocol
== RTPROT_KERNEL
)
1217 k
= route_remove(route
, NULL
, link
);
1218 if (k
< 0 && r
>= 0)
1222 k
= manager_drop_routes(link
->manager
, link
);
1223 if (k
< 0 && r
>= 0)
1229 static int route_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1230 Route
*route
= userdata
;
1235 r
= route_remove(route
, route
->manager
, route
->link
);
1237 log_link_warning_errno(route
->link
, r
, "Could not remove route: %m");
1244 static int route_add_and_setup_timer_one(Link
*link
, const Route
*route
, const MultipathRoute
*m
, const NextHop
*nh
, uint8_t nh_weight
, Route
**ret
) {
1245 _cleanup_(sd_event_source_unrefp
) sd_event_source
*expire
= NULL
;
1250 assert(link
->manager
);
1255 if (route_type_is_reject(route
) || (nh
&& nh
->blackhole
))
1256 r
= route_add(link
->manager
, NULL
, route
, NULL
, nh
, nh_weight
, &nr
);
1259 assert(hashmap_isempty(nh
->group
));
1261 r
= route_add(NULL
, nh
->link
, route
, NULL
, nh
, nh_weight
, &nr
);
1262 } else if (m
&& m
->ifindex
!= 0 && m
->ifindex
!= link
->ifindex
) {
1265 r
= link_get(link
->manager
, m
->ifindex
, &link_gw
);
1267 return log_link_error_errno(link
, r
, "Failed to get link with ifindex %d: %m", m
->ifindex
);
1269 r
= route_add(NULL
, link_gw
, route
, m
, NULL
, UINT8_MAX
, &nr
);
1271 r
= route_add(NULL
, link
, route
, m
, NULL
, UINT8_MAX
, &nr
);
1273 return log_link_error_errno(link
, r
, "Could not add route: %m");
1275 /* TODO: drop expiration handling once it can be pushed into the kernel */
1276 if (nr
->lifetime
!= USEC_INFINITY
&& !kernel_route_expiration_supported()) {
1277 r
= sd_event_add_time(link
->manager
->event
, &expire
, clock_boottime_or_monotonic(),
1278 nr
->lifetime
, 0, route_expire_handler
, nr
);
1280 return log_link_error_errno(link
, r
, "Could not arm expiration timer: %m");
1283 sd_event_source_unref(nr
->expire
);
1284 nr
->expire
= TAKE_PTR(expire
);
1290 static int route_add_and_setup_timer(Link
*link
, const Route
*route
, unsigned *ret_n_routes
, Route
***ret_routes
) {
1291 _cleanup_free_ Route
**routes
= NULL
;
1299 assert(ret_n_routes
);
1302 if (route
->nexthop_id
> 0) {
1303 r
= manager_get_nexthop_by_id(link
->manager
, route
->nexthop_id
, &nh
);
1305 return log_link_error_errno(link
, r
, "Could not get nexthop by ID %"PRIu32
": %m", route
->nexthop_id
);
1309 if (nh
&& !hashmap_isempty(nh
->group
)) {
1310 struct nexthop_grp
*nhg
;
1312 n_routes
= hashmap_size(nh
->group
);
1313 p
= routes
= new(Route
*, n_routes
);
1317 HASHMAP_FOREACH(nhg
, nh
->group
) {
1320 r
= manager_get_nexthop_by_id(link
->manager
, nhg
->id
, &h
);
1322 return log_link_error_errno(link
, r
, "Could not get nexthop group member by ID %"PRIu32
": %m", nhg
->id
);
1324 /* The nexthop h may be a blackhole nexthop. In that case, h->link is NULL. */
1325 r
= route_add_and_setup_timer_one(h
->link
?: link
, route
, NULL
, h
, nhg
->weight
, p
++);
1329 } else if (!ordered_set_isempty(route
->multipath_routes
)) {
1333 assert(!in_addr_is_set(route
->gw_family
, &route
->gw
));
1335 n_routes
= ordered_set_size(route
->multipath_routes
);
1336 p
= routes
= new(Route
*, n_routes
);
1340 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1341 r
= route_add_and_setup_timer_one(link
, route
, m
, NULL
, UINT8_MAX
, p
++);
1347 routes
= new(Route
*, n_routes
);
1351 r
= route_add_and_setup_timer_one(link
, route
, NULL
, nh
, UINT8_MAX
, routes
);
1356 *ret_n_routes
= n_routes
;
1357 *ret_routes
= TAKE_PTR(routes
);
1361 static int append_nexthop_one(const Route
*route
, const MultipathRoute
*m
, struct rtattr
**rta
, size_t offset
) {
1362 struct rtnexthop
*rtnh
;
1363 struct rtattr
*new_rta
;
1371 new_rta
= realloc(*rta
, RTA_ALIGN((*rta
)->rta_len
) + RTA_SPACE(sizeof(struct rtnexthop
)));
1376 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1377 *rtnh
= (struct rtnexthop
) {
1378 .rtnh_len
= sizeof(*rtnh
),
1379 .rtnh_ifindex
= m
->ifindex
,
1380 .rtnh_hops
= m
->weight
,
1383 (*rta
)->rta_len
+= sizeof(struct rtnexthop
);
1385 if (route
->family
== m
->gateway
.family
) {
1386 r
= rtattr_append_attribute(rta
, RTA_GATEWAY
, &m
->gateway
.address
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1389 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1390 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1392 r
= rtattr_append_attribute(rta
, RTA_VIA
, &m
->gateway
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1395 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1396 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1402 (*rta
)->rta_len
-= sizeof(struct rtnexthop
);
1406 static int append_nexthops(const Route
*route
, sd_netlink_message
*req
) {
1407 _cleanup_free_
struct rtattr
*rta
= NULL
;
1408 struct rtnexthop
*rtnh
;
1413 if (ordered_set_isempty(route
->multipath_routes
))
1416 rta
= new(struct rtattr
, 1);
1420 *rta
= (struct rtattr
) {
1421 .rta_type
= RTA_MULTIPATH
,
1422 .rta_len
= RTA_LENGTH(0),
1424 offset
= (uint8_t *) RTA_DATA(rta
) - (uint8_t *) rta
;
1426 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1427 r
= append_nexthop_one(route
, m
, &rta
, offset
);
1431 rtnh
= (struct rtnexthop
*)((uint8_t *) rta
+ offset
);
1432 offset
= (uint8_t *) RTNH_NEXT(rtnh
) - (uint8_t *) rta
;
1435 r
= sd_netlink_message_append_data(req
, RTA_MULTIPATH
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
1442 int route_configure_handler_internal(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
, const char *error_msg
) {
1449 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
1452 r
= sd_netlink_message_get_errno(m
);
1453 if (r
< 0 && r
!= -EEXIST
) {
1454 log_link_message_warning_errno(link
, m
, r
, "Could not set route");
1455 link_enter_failed(link
);
1462 static int route_configure(
1465 link_netlink_message_handler_t callback
,
1466 unsigned *ret_n_routes
,
1467 Route
***ret_routes
) {
1469 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
1470 _cleanup_free_ Route
**routes
= NULL
;
1471 unsigned n_routes
= 0; /* avoid false maybe-uninitialized warning */
1475 assert(link
->manager
);
1476 assert(link
->manager
->rtnl
);
1477 assert(link
->ifindex
> 0);
1478 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
1480 assert(!!ret_n_routes
== !!ret_routes
);
1482 if (route_get(link
->manager
, link
, route
, NULL
) <= 0 &&
1483 set_size(link
->routes
) >= routes_max())
1484 return log_link_error_errno(link
, SYNTHETIC_ERRNO(E2BIG
),
1485 "Too many routes are configured, refusing: %m");
1487 log_route_debug(route
, "Configuring", link
, link
->manager
);
1489 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &req
,
1490 RTM_NEWROUTE
, route
->family
,
1493 return log_link_error_errno(link
, r
, "Could not create RTM_NEWROUTE message: %m");
1495 r
= sd_rtnl_message_route_set_type(req
, route
->type
);
1497 return log_link_error_errno(link
, r
, "Could not set route type: %m");
1499 r
= route_set_netlink_message(route
, req
, link
);
1503 if (route
->lifetime
!= USEC_INFINITY
&& kernel_route_expiration_supported()) {
1504 r
= sd_netlink_message_append_u32(req
, RTA_EXPIRES
,
1505 DIV_ROUND_UP(usec_sub_unsigned(route
->lifetime
, now(clock_boottime_or_monotonic())), USEC_PER_SEC
));
1507 return log_link_error_errno(link
, r
, "Could not append RTA_EXPIRES attribute: %m");
1510 if (route
->ttl_propagate
>= 0) {
1511 r
= sd_netlink_message_append_u8(req
, RTA_TTL_PROPAGATE
, route
->ttl_propagate
);
1513 return log_link_error_errno(link
, r
, "Could not append RTA_TTL_PROPAGATE attribute: %m");
1516 r
= sd_netlink_message_open_container(req
, RTA_METRICS
);
1518 return log_link_error_errno(link
, r
, "Could not append RTA_METRICS attribute: %m");
1520 if (route
->mtu
> 0) {
1521 r
= sd_netlink_message_append_u32(req
, RTAX_MTU
, route
->mtu
);
1523 return log_link_error_errno(link
, r
, "Could not append RTAX_MTU attribute: %m");
1526 if (route
->initcwnd
> 0) {
1527 r
= sd_netlink_message_append_u32(req
, RTAX_INITCWND
, route
->initcwnd
);
1529 return log_link_error_errno(link
, r
, "Could not append RTAX_INITCWND attribute: %m");
1532 if (route
->initrwnd
> 0) {
1533 r
= sd_netlink_message_append_u32(req
, RTAX_INITRWND
, route
->initrwnd
);
1535 return log_link_error_errno(link
, r
, "Could not append RTAX_INITRWND attribute: %m");
1538 if (route
->quickack
>= 0) {
1539 r
= sd_netlink_message_append_u32(req
, RTAX_QUICKACK
, route
->quickack
);
1541 return log_link_error_errno(link
, r
, "Could not append RTAX_QUICKACK attribute: %m");
1544 if (route
->fast_open_no_cookie
>= 0) {
1545 r
= sd_netlink_message_append_u32(req
, RTAX_FASTOPEN_NO_COOKIE
, route
->fast_open_no_cookie
);
1547 return log_link_error_errno(link
, r
, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
1550 if (route
->advmss
> 0) {
1551 r
= sd_netlink_message_append_u32(req
, RTAX_ADVMSS
, route
->advmss
);
1553 return log_link_error_errno(link
, r
, "Could not append RTAX_ADVMSS attribute: %m");
1556 r
= sd_netlink_message_close_container(req
);
1558 return log_link_error_errno(link
, r
, "Could not append RTA_METRICS attribute: %m");
1560 if (!ordered_set_isempty(route
->multipath_routes
)) {
1561 assert(route
->nexthop_id
== 0);
1562 assert(!in_addr_is_set(route
->gw_family
, &route
->gw
));
1564 r
= append_nexthops(route
, req
);
1566 return log_link_error_errno(link
, r
, "Could not append RTA_MULTIPATH attribute: %m");
1569 r
= route_add_and_setup_timer(link
, route
, &n_routes
, &routes
);
1573 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, callback
,
1574 link_netlink_destroy_callback
, link
);
1576 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
1581 *ret_n_routes
= n_routes
;
1582 *ret_routes
= TAKE_PTR(routes
);
1588 static int static_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
1592 assert(link
->static_route_messages
> 0);
1594 link
->static_route_messages
--;
1596 r
= route_configure_handler_internal(rtnl
, m
, link
, "Could not set route");
1600 if (link
->static_route_messages
== 0) {
1601 log_link_debug(link
, "Routes set");
1602 link
->static_routes_configured
= true;
1603 link_check_ready(link
);
1609 int link_request_route(
1612 bool consume_object
,
1613 unsigned *message_counter
,
1614 link_netlink_message_handler_t netlink_handler
,
1618 assert(link
->manager
);
1621 log_route_debug(route
, "Requesting", link
, link
->manager
);
1622 return link_queue_request(link
, REQUEST_TYPE_ROUTE
, route
, consume_object
,
1623 message_counter
, netlink_handler
, ret
);
1626 int link_request_static_routes(Link
*link
, bool only_ipv4
) {
1631 assert(link
->network
);
1633 link
->static_routes_configured
= false;
1635 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
1636 if (route
->gateway_from_dhcp_or_ra
)
1639 if (only_ipv4
&& route
->family
!= AF_INET
)
1642 r
= link_request_route(link
, route
, false, &link
->static_route_messages
,
1643 static_route_handler
, NULL
);
1648 if (link
->static_route_messages
== 0) {
1649 link
->static_routes_configured
= true;
1650 link_check_ready(link
);
1652 log_link_debug(link
, "Requesting routes");
1653 link_set_state(link
, LINK_STATE_CONFIGURING
);
1659 static int route_is_ready_to_configure(const Route
*route
, Link
*link
) {
1667 if (route
->nexthop_id
> 0) {
1668 struct nexthop_grp
*nhg
;
1670 if (manager_get_nexthop_by_id(link
->manager
, route
->nexthop_id
, &nh
) < 0)
1673 HASHMAP_FOREACH(nhg
, nh
->group
)
1674 if (manager_get_nexthop_by_id(link
->manager
, nhg
->id
, NULL
) < 0)
1678 if (route_type_is_reject(route
) || (nh
&& nh
->blackhole
)) {
1679 if (nh
&& link
->manager
->nexthop_remove_messages
> 0)
1681 if (link
->manager
->route_remove_messages
> 0)
1686 HASHMAP_FOREACH(l
, link
->manager
->links
) {
1687 if (l
->address_remove_messages
> 0)
1689 if (l
->nexthop_remove_messages
> 0)
1691 if (l
->route_remove_messages
> 0)
1696 if (in_addr_is_set(route
->family
, &route
->prefsrc
) > 0) {
1697 r
= manager_has_address(link
->manager
, route
->family
, &route
->prefsrc
, route
->family
== AF_INET6
);
1702 if (route
->gateway_onlink
<= 0 &&
1703 in_addr_is_set(route
->gw_family
, &route
->gw
) > 0 &&
1704 !manager_address_is_reachable(link
->manager
, route
->gw_family
, &route
->gw
))
1707 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1708 union in_addr_union a
= m
->gateway
.address
;
1711 if (route
->gateway_onlink
<= 0 &&
1712 !manager_address_is_reachable(link
->manager
, m
->gateway
.family
, &a
))
1716 if (link_get_by_name(link
->manager
, m
->ifname
, &l
) < 0)
1719 m
->ifindex
= l
->ifindex
;
1720 } else if (m
->ifindex
> 0) {
1721 if (link_get(link
->manager
, m
->ifindex
, &l
) < 0)
1724 if (l
&& !link_is_ready_to_configure(l
, true))
1731 int request_process_route(Request
*req
) {
1732 _cleanup_free_ Route
**routes
= NULL
;
1739 assert(req
->type
== REQUEST_TYPE_ROUTE
);
1741 if (!link_is_ready_to_configure(req
->link
, false))
1744 r
= route_is_ready_to_configure(req
->route
, req
->link
);
1748 r
= route_configure(req
->route
, req
->link
, req
->netlink_handler
,
1749 req
->after_configure
? &n_routes
: NULL
,
1750 req
->after_configure
? &routes
: NULL
);
1754 /* To prevent a double decrement on failure in after_configure(). */
1755 req
->message_counter
= NULL
;
1757 if (req
->after_configure
) {
1758 assert(n_routes
> 0);
1760 for (unsigned i
= 0; i
< n_routes
; i
++) {
1761 r
= req
->after_configure(req
, routes
[i
]);
1770 static int process_route_one(Manager
*manager
, Link
*link
, uint16_t type
, const Route
*tmp
, const MultipathRoute
*m
) {
1771 _cleanup_(route_freep
) Route
*nr
= NULL
;
1772 Route
*route
= NULL
;
1778 assert(IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
));
1780 (void) manager_get_nexthop_by_id(manager
, tmp
->nexthop_id
, &nh
);
1782 if (nh
&& hashmap_isempty(nh
->group
)) {
1783 if (link
&& nh
->link
&& link
!= nh
->link
)
1784 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EINVAL
),
1785 "rtnl: received RTA_OIF and ifindex of nexthop corresponding to RTA_NH_ID do not match, ignoring.");
1794 route_copy(nr
, tmp
, NULL
, nh
, UINT8_MAX
);
1799 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EINVAL
),
1800 "rtnl: received route contains both RTA_OIF and RTA_MULTIPATH, ignoring.");
1802 if (m
->ifindex
<= 0)
1803 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
1804 "rtnl: received multipath route with invalid ifindex, ignoring.");
1806 r
= link_get(manager
, m
->ifindex
, &link
);
1808 log_warning_errno(r
, "rtnl: received multipath route for link (%d) we do not know, ignoring: %m", m
->ifindex
);
1816 route_copy(nr
, tmp
, m
, NULL
, UINT8_MAX
);
1821 (void) route_get(manager
, link
, tmp
, &route
);
1826 if (!manager
->manage_foreign_routes
)
1827 log_route_debug(tmp
, "Ignoring received foreign", link
, manager
);
1829 /* A route appeared that we did not request */
1830 log_route_debug(tmp
, "Remembering foreign", link
, manager
);
1831 r
= route_add_foreign(manager
, link
, tmp
, NULL
);
1833 log_link_warning_errno(link
, r
, "Failed to remember foreign route, ignoring: %m");
1838 log_route_debug(tmp
, "Received remembered", link
, manager
);
1843 log_route_debug(tmp
,
1844 route
? "Forgetting" :
1845 manager
->manage_foreign_routes
? "Kernel removed unknown" : "Ignoring received foreign",
1851 assert_not_reached("Received route message with invalid RTNL message type");
1857 int manager_rtnl_process_route(sd_netlink
*rtnl
, sd_netlink_message
*message
, Manager
*m
) {
1858 _cleanup_ordered_set_free_free_ OrderedSet
*multipath_routes
= NULL
;
1859 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1860 _cleanup_free_
void *rta_multipath
= NULL
;
1864 unsigned char table
;
1872 if (sd_netlink_message_is_error(message
)) {
1873 r
= sd_netlink_message_get_errno(message
);
1875 log_message_warning_errno(message
, r
, "rtnl: failed to receive route message, ignoring");
1880 r
= sd_netlink_message_get_type(message
, &type
);
1882 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
1884 } else if (!IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
)) {
1885 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type
);
1889 r
= sd_netlink_message_read_u32(message
, RTA_OIF
, &ifindex
);
1890 if (r
< 0 && r
!= -ENODATA
) {
1891 log_warning_errno(r
, "rtnl: could not get ifindex from route message, ignoring: %m");
1893 } else if (r
>= 0) {
1895 log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex
);
1899 r
= link_get(m
, ifindex
, &link
);
1900 if (r
< 0 || !link
) {
1901 /* when enumerating we might be out of sync, but we will
1902 * get the route again, so just ignore it */
1903 if (!m
->enumerating
)
1904 log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex
);
1909 r
= route_new(&tmp
);
1913 r
= sd_rtnl_message_route_get_family(message
, &tmp
->family
);
1915 log_link_warning(link
, "rtnl: received route message without family, ignoring");
1917 } else if (!IN_SET(tmp
->family
, AF_INET
, AF_INET6
)) {
1918 log_link_debug(link
, "rtnl: received route message with invalid family '%i', ignoring", tmp
->family
);
1922 r
= sd_rtnl_message_route_get_protocol(message
, &tmp
->protocol
);
1924 log_warning_errno(r
, "rtnl: received route message without route protocol: %m");
1928 r
= netlink_message_read_in_addr_union(message
, RTA_DST
, tmp
->family
, &tmp
->dst
);
1929 if (r
< 0 && r
!= -ENODATA
) {
1930 log_link_warning_errno(link
, r
, "rtnl: received route message without valid destination, ignoring: %m");
1934 r
= netlink_message_read_in_addr_union(message
, RTA_GATEWAY
, tmp
->family
, &tmp
->gw
);
1935 if (r
< 0 && r
!= -ENODATA
) {
1936 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1939 tmp
->gw_family
= tmp
->family
;
1940 else if (tmp
->family
== AF_INET
) {
1943 r
= sd_netlink_message_read(message
, RTA_VIA
, sizeof(via
), &via
);
1944 if (r
< 0 && r
!= -ENODATA
) {
1945 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1947 } else if (r
>= 0) {
1948 tmp
->gw_family
= via
.family
;
1949 tmp
->gw
= via
.address
;
1953 r
= netlink_message_read_in_addr_union(message
, RTA_SRC
, tmp
->family
, &tmp
->src
);
1954 if (r
< 0 && r
!= -ENODATA
) {
1955 log_link_warning_errno(link
, r
, "rtnl: received route message without valid source, ignoring: %m");
1959 r
= netlink_message_read_in_addr_union(message
, RTA_PREFSRC
, tmp
->family
, &tmp
->prefsrc
);
1960 if (r
< 0 && r
!= -ENODATA
) {
1961 log_link_warning_errno(link
, r
, "rtnl: received route message without valid preferred source, ignoring: %m");
1965 r
= sd_rtnl_message_route_get_dst_prefixlen(message
, &tmp
->dst_prefixlen
);
1967 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1971 r
= sd_rtnl_message_route_get_src_prefixlen(message
, &tmp
->src_prefixlen
);
1973 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1977 r
= sd_rtnl_message_route_get_scope(message
, &tmp
->scope
);
1979 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid scope, ignoring: %m");
1983 r
= sd_rtnl_message_route_get_tos(message
, &tmp
->tos
);
1985 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid tos, ignoring: %m");
1989 r
= sd_rtnl_message_route_get_type(message
, &tmp
->type
);
1991 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid type, ignoring: %m");
1995 r
= sd_rtnl_message_route_get_table(message
, &table
);
1997 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid table, ignoring: %m");
2002 r
= sd_netlink_message_read_u32(message
, RTA_PRIORITY
, &tmp
->priority
);
2003 if (r
< 0 && r
!= -ENODATA
) {
2004 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid priority, ignoring: %m");
2008 r
= sd_netlink_message_read_u32(message
, RTA_NH_ID
, &tmp
->nexthop_id
);
2009 if (r
< 0 && r
!= -ENODATA
) {
2010 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid nexthop id, ignoring: %m");
2014 r
= sd_netlink_message_enter_container(message
, RTA_METRICS
);
2015 if (r
< 0 && r
!= -ENODATA
) {
2016 log_link_error_errno(link
, r
, "rtnl: Could not enter RTA_METRICS container: %m");
2020 r
= sd_netlink_message_read_u32(message
, RTAX_INITCWND
, &tmp
->initcwnd
);
2021 if (r
< 0 && r
!= -ENODATA
) {
2022 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initcwnd, ignoring: %m");
2026 r
= sd_netlink_message_read_u32(message
, RTAX_INITRWND
, &tmp
->initrwnd
);
2027 if (r
< 0 && r
!= -ENODATA
) {
2028 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initrwnd, ignoring: %m");
2032 r
= sd_netlink_message_read_u32(message
, RTAX_ADVMSS
, &tmp
->advmss
);
2033 if (r
< 0 && r
!= -ENODATA
) {
2034 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid advmss, ignoring: %m");
2038 r
= sd_netlink_message_exit_container(message
);
2040 log_link_error_errno(link
, r
, "rtnl: Could not exit from RTA_METRICS container: %m");
2045 r
= sd_netlink_message_read_data(message
, RTA_MULTIPATH
, &rta_len
, &rta_multipath
);
2046 if (r
< 0 && r
!= -ENODATA
) {
2047 log_link_warning_errno(link
, r
, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
2049 } else if (r
>= 0) {
2050 r
= rtattr_read_nexthop(rta_multipath
, rta_len
, tmp
->family
, &multipath_routes
);
2052 log_link_warning_errno(link
, r
, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
2057 /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
2058 * fib6_nh_init() in net/ipv6/route.c. However, we'd like to manage them by Manager. Hence, set
2059 * link to NULL here. */
2060 if (route_type_is_reject(tmp
))
2063 if (ordered_set_isempty(multipath_routes
))
2064 (void) process_route_one(m
, link
, type
, tmp
, NULL
);
2068 ORDERED_SET_FOREACH(mr
, multipath_routes
) {
2069 r
= process_route_one(m
, link
, type
, tmp
, mr
);
2078 int network_add_ipv4ll_route(Network
*network
) {
2079 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2080 unsigned section_line
;
2085 if (!network
->ipv4ll_route
)
2088 section_line
= hashmap_find_free_section_line(network
->routes_by_section
);
2090 /* IPv4LLRoute= is in [Network] section. */
2091 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
2095 r
= in_addr_from_string(AF_INET
, "169.254.0.0", &n
->dst
);
2099 n
->family
= AF_INET
;
2100 n
->dst_prefixlen
= 16;
2101 n
->scope
= RT_SCOPE_LINK
;
2102 n
->scope_set
= true;
2103 n
->table_set
= true;
2104 n
->priority
= IPV4LL_ROUTE_METRIC
;
2105 n
->protocol
= RTPROT_STATIC
;
2111 int network_add_default_route_on_device(Network
*network
) {
2112 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2113 unsigned section_line
;
2118 if (!network
->default_route_on_device
)
2121 section_line
= hashmap_find_free_section_line(network
->routes_by_section
);
2123 /* DefaultRouteOnDevice= is in [Network] section. */
2124 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
2128 n
->family
= AF_INET
;
2129 n
->scope
= RT_SCOPE_LINK
;
2130 n
->scope_set
= true;
2131 n
->protocol
= RTPROT_STATIC
;
2137 int config_parse_gateway(
2139 const char *filename
,
2141 const char *section
,
2142 unsigned section_line
,
2149 Network
*network
= userdata
;
2150 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2159 if (streq(section
, "Network")) {
2160 /* we are not in an Route section, so use line number instead */
2161 r
= route_new_static(network
, filename
, line
, &n
);
2165 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2166 "Failed to allocate route, ignoring assignment: %m");
2170 r
= route_new_static(network
, filename
, section_line
, &n
);
2174 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2175 "Failed to allocate route, ignoring assignment: %m");
2179 if (isempty(rvalue
)) {
2180 n
->gateway_from_dhcp_or_ra
= false;
2181 n
->gw_family
= AF_UNSPEC
;
2182 n
->gw
= IN_ADDR_NULL
;
2187 if (streq(rvalue
, "_dhcp")) {
2188 n
->gateway_from_dhcp_or_ra
= true;
2193 if (streq(rvalue
, "_dhcp4")) {
2194 n
->gw_family
= AF_INET
;
2195 n
->gateway_from_dhcp_or_ra
= true;
2200 if (streq(rvalue
, "_ipv6ra")) {
2201 n
->gw_family
= AF_INET6
;
2202 n
->gateway_from_dhcp_or_ra
= true;
2208 r
= in_addr_from_string_auto(rvalue
, &n
->gw_family
, &n
->gw
);
2210 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2211 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2215 n
->gateway_from_dhcp_or_ra
= false;
2220 int config_parse_preferred_src(
2222 const char *filename
,
2224 const char *section
,
2225 unsigned section_line
,
2232 Network
*network
= userdata
;
2233 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2242 r
= route_new_static(network
, filename
, section_line
, &n
);
2246 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2247 "Failed to allocate route, ignoring assignment: %m");
2251 if (n
->family
== AF_UNSPEC
)
2252 r
= in_addr_from_string_auto(rvalue
, &n
->family
, &n
->prefsrc
);
2254 r
= in_addr_from_string(n
->family
, rvalue
, &n
->prefsrc
);
2256 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2257 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2265 int config_parse_destination(
2267 const char *filename
,
2269 const char *section
,
2270 unsigned section_line
,
2277 Network
*network
= userdata
;
2278 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2279 union in_addr_union
*buffer
;
2280 unsigned char *prefixlen
;
2289 r
= route_new_static(network
, filename
, section_line
, &n
);
2293 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2294 "Failed to allocate route, ignoring assignment: %m");
2298 if (streq(lvalue
, "Destination")) {
2300 prefixlen
= &n
->dst_prefixlen
;
2301 } else if (streq(lvalue
, "Source")) {
2303 prefixlen
= &n
->src_prefixlen
;
2305 assert_not_reached(lvalue
);
2307 if (n
->family
== AF_UNSPEC
)
2308 r
= in_addr_prefix_from_string_auto(rvalue
, &n
->family
, buffer
, prefixlen
);
2310 r
= in_addr_prefix_from_string(rvalue
, n
->family
, buffer
, prefixlen
);
2312 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2313 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2321 int config_parse_route_priority(
2323 const char *filename
,
2325 const char *section
,
2326 unsigned section_line
,
2333 Network
*network
= userdata
;
2334 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2343 r
= route_new_static(network
, filename
, section_line
, &n
);
2347 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2348 "Failed to allocate route, ignoring assignment: %m");
2352 r
= safe_atou32(rvalue
, &n
->priority
);
2354 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2355 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue
);
2359 n
->priority_set
= true;
2364 int config_parse_route_scope(
2366 const char *filename
,
2368 const char *section
,
2369 unsigned section_line
,
2376 Network
*network
= userdata
;
2377 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2386 r
= route_new_static(network
, filename
, section_line
, &n
);
2390 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2391 "Failed to allocate route, ignoring assignment: %m");
2395 r
= route_scope_from_string(rvalue
);
2397 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Unknown route scope: %s", rvalue
);
2402 n
->scope_set
= true;
2407 int config_parse_route_nexthop(
2409 const char *filename
,
2411 const char *section
,
2412 unsigned section_line
,
2419 Network
*network
= userdata
;
2420 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2430 r
= route_new_static(network
, filename
, section_line
, &n
);
2434 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2435 "Failed to allocate route, ignoring assignment: %m");
2439 if (isempty(rvalue
)) {
2445 r
= safe_atou32(rvalue
, &id
);
2447 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue
);
2451 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue
);
2460 int config_parse_route_table(
2462 const char *filename
,
2464 const char *section
,
2465 unsigned section_line
,
2472 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2473 Network
*network
= userdata
;
2482 r
= route_new_static(network
, filename
, section_line
, &n
);
2486 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2487 "Failed to allocate route, ignoring assignment: %m");
2491 r
= manager_get_route_table_from_string(network
->manager
, rvalue
, &n
->table
);
2493 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2494 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue
);
2498 n
->table_set
= true;
2503 int config_parse_route_boolean(
2505 const char *filename
,
2507 const char *section
,
2508 unsigned section_line
,
2515 Network
*network
= userdata
;
2516 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2525 r
= route_new_static(network
, filename
, section_line
, &n
);
2529 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2530 "Failed to allocate route, ignoring assignment: %m");
2534 r
= parse_boolean(rvalue
);
2536 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2537 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2541 if (STR_IN_SET(lvalue
, "GatewayOnLink", "GatewayOnlink"))
2542 n
->gateway_onlink
= r
;
2543 else if (streq(lvalue
, "QuickAck"))
2545 else if (streq(lvalue
, "FastOpenNoCookie"))
2546 n
->fast_open_no_cookie
= r
;
2547 else if (streq(lvalue
, "TTLPropagate"))
2548 n
->ttl_propagate
= r
;
2550 assert_not_reached("Invalid lvalue");
2556 int config_parse_ipv6_route_preference(
2558 const char *filename
,
2560 const char *section
,
2561 unsigned section_line
,
2568 Network
*network
= userdata
;
2569 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2572 r
= route_new_static(network
, filename
, section_line
, &n
);
2576 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2577 "Failed to allocate route, ignoring assignment: %m");
2581 if (streq(rvalue
, "low"))
2582 n
->pref
= ICMPV6_ROUTER_PREF_LOW
;
2583 else if (streq(rvalue
, "medium"))
2584 n
->pref
= ICMPV6_ROUTER_PREF_MEDIUM
;
2585 else if (streq(rvalue
, "high"))
2586 n
->pref
= ICMPV6_ROUTER_PREF_HIGH
;
2588 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown route preference: %s", rvalue
);
2597 int config_parse_route_protocol(
2599 const char *filename
,
2601 const char *section
,
2602 unsigned section_line
,
2609 Network
*network
= userdata
;
2610 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2613 r
= route_new_static(network
, filename
, section_line
, &n
);
2617 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2618 "Failed to allocate route, ignoring assignment: %m");
2622 r
= route_protocol_from_string(rvalue
);
2624 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2625 "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue
);
2635 int config_parse_route_type(
2637 const char *filename
,
2639 const char *section
,
2640 unsigned section_line
,
2647 Network
*network
= userdata
;
2648 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2651 r
= route_new_static(network
, filename
, section_line
, &n
);
2655 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2656 "Failed to allocate route, ignoring assignment: %m");
2660 t
= route_type_from_string(rvalue
);
2662 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2663 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue
);
2667 n
->type
= (unsigned char) t
;
2673 int config_parse_tcp_advmss(
2675 const char *filename
,
2677 const char *section
,
2678 unsigned section_line
,
2685 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2686 Network
*network
= userdata
;
2696 r
= route_new_static(network
, filename
, section_line
, &n
);
2700 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2701 "Failed to allocate route, ignoring assignment: %m");
2705 if (isempty(rvalue
)) {
2711 r
= parse_size(rvalue
, 1024, &u
);
2713 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2714 "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2718 if (u
== 0 || u
> UINT32_MAX
) {
2719 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2720 "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2730 int config_parse_tcp_window(
2732 const char *filename
,
2734 const char *section
,
2735 unsigned section_line
,
2742 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2743 Network
*network
= userdata
;
2753 r
= route_new_static(network
, filename
, section_line
, &n
);
2757 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2758 "Failed to allocate route, ignoring assignment: %m");
2762 r
= safe_atou32(rvalue
, &k
);
2764 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2765 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2769 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2770 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue
, rvalue
);
2774 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2775 "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2779 if (streq(lvalue
, "InitialCongestionWindow"))
2781 else if (streq(lvalue
, "InitialAdvertisedReceiveWindow"))
2784 assert_not_reached("Invalid TCP window type.");
2790 int config_parse_route_mtu(
2792 const char *filename
,
2794 const char *section
,
2795 unsigned section_line
,
2802 Network
*network
= userdata
;
2803 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2812 r
= route_new_static(network
, filename
, section_line
, &n
);
2816 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2817 "Failed to allocate route, ignoring assignment: %m");
2821 r
= config_parse_mtu(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &n
->mtu
, userdata
);
2829 int config_parse_multipath_route(
2831 const char *filename
,
2833 const char *section
,
2834 unsigned section_line
,
2841 _cleanup_(multipath_route_freep
) MultipathRoute
*m
= NULL
;
2842 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2843 _cleanup_free_
char *word
= NULL
;
2844 Network
*network
= userdata
;
2845 union in_addr_union a
;
2856 r
= route_new_static(network
, filename
, section_line
, &n
);
2860 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2861 "Failed to allocate route, ignoring assignment: %m");
2865 if (isempty(rvalue
)) {
2866 n
->multipath_routes
= ordered_set_free_with_destructor(n
->multipath_routes
, multipath_route_free
);
2870 m
= new0(MultipathRoute
, 1);
2875 r
= extract_first_word(&p
, &word
, NULL
, 0);
2879 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2880 "Invalid multipath route option, ignoring assignment: %s", rvalue
);
2884 dev
= strchr(word
, '@');
2888 r
= parse_ifindex(dev
);
2892 if (!ifname_valid_full(dev
, IFNAME_VALID_ALTERNATIVE
)) {
2893 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2894 "Invalid interface name '%s' in %s=, ignoring: %s", dev
, lvalue
, rvalue
);
2898 m
->ifname
= strdup(dev
);
2904 r
= in_addr_from_string_auto(word
, &family
, &a
);
2906 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2907 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue
);
2910 m
->gateway
.address
= a
;
2911 m
->gateway
.family
= family
;
2914 r
= safe_atou32(p
, &m
->weight
);
2916 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2917 "Invalid multipath route weight, ignoring assignment: %s", p
);
2920 /* ip command takes weight in the range 1…255, while kernel takes the value in the
2921 * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip
2922 * command uses, then networkd decreases by one and stores it to match the range which
2924 if (m
->weight
== 0 || m
->weight
> 256) {
2925 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2926 "Invalid multipath route weight, ignoring assignment: %s", p
);
2932 r
= ordered_set_ensure_put(&n
->multipath_routes
, NULL
, m
);
2936 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2937 "Failed to store multipath route, ignoring assignment: %m");
2946 int config_parse_route_table_names(
2948 const char *filename
,
2950 const char *section
,
2951 unsigned section_line
,
2958 Manager
*m
= userdata
;
2966 if (isempty(rvalue
)) {
2967 m
->route_table_names_by_number
= hashmap_free(m
->route_table_names_by_number
);
2968 m
->route_table_numbers_by_name
= hashmap_free(m
->route_table_numbers_by_name
);
2972 for (const char *p
= rvalue
;;) {
2973 _cleanup_free_
char *name
= NULL
;
2977 r
= extract_first_word(&p
, &name
, NULL
, 0);
2981 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2982 "Invalid RouteTable=, ignoring assignment: %s", rvalue
);
2988 num
= strchr(name
, ':');
2990 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2991 "Invalid route table name and number pair, ignoring assignment: %s", name
);
2997 if (STR_IN_SET(name
, "default", "main", "local")) {
2998 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2999 "Route table name %s already predefined. Ignoring assignment: %s:%s", name
, name
, num
);
3003 r
= safe_atou32(num
, &table
);
3005 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3006 "Failed to parse route table number '%s', ignoring assignment: %s:%s", num
, name
, num
);
3010 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
3011 "Invalid route table number, ignoring assignment: %s:%s", name
, num
);
3015 r
= hashmap_ensure_put(&m
->route_table_numbers_by_name
, &string_hash_ops_free
, name
, UINT32_TO_PTR(table
));
3019 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3020 "Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name
, num
);
3024 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3025 "Failed to store route table name and number pair, ignoring assignment: %s:%s", name
, num
);
3029 /* The entry is duplicated. It should not be added to route_table_names_by_number hashmap. */
3032 r
= hashmap_ensure_put(&m
->route_table_names_by_number
, NULL
, UINT32_TO_PTR(table
), name
);
3034 hashmap_remove(m
->route_table_numbers_by_name
, name
);
3039 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3040 "Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name
, num
);
3042 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3043 "Failed to store route table name and number pair, ignoring assignment: %s:%s", name
, num
);
3052 static int route_section_verify(Route
*route
, Network
*network
) {
3053 if (section_is_invalid(route
->section
))
3056 if (route
->gateway_from_dhcp_or_ra
) {
3057 if (route
->gw_family
== AF_UNSPEC
) {
3058 /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
3059 switch (route
->family
) {
3061 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3062 "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
3063 route
->section
->filename
, route
->section
->line
);
3064 route
->family
= AF_INET
;
3068 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3069 "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
3070 route
->section
->filename
, route
->section
->line
, route
->family
== AF_INET
? "_dhcp4" : "_ipv6ra");
3073 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3074 "%s: Invalid route family. Ignoring [Route] section from line %u.",
3075 route
->section
->filename
, route
->section
->line
);
3077 route
->gw_family
= route
->family
;
3080 if (route
->gw_family
== AF_INET
&& !FLAGS_SET(network
->dhcp
, ADDRESS_FAMILY_IPV4
))
3081 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3082 "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
3083 "Ignoring [Route] section from line %u.",
3084 route
->section
->filename
, route
->section
->line
);
3086 if (route
->gw_family
== AF_INET6
&& !network
->ipv6_accept_ra
)
3087 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3088 "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
3089 "Ignoring [Route] section from line %u.",
3090 route
->section
->filename
, route
->section
->line
);
3093 /* When only Gateway= is specified, assume the route family based on the Gateway address. */
3094 if (route
->family
== AF_UNSPEC
)
3095 route
->family
= route
->gw_family
;
3097 if (route
->family
== AF_UNSPEC
) {
3098 assert(route
->section
);
3100 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3101 "%s: Route section without Gateway=, Destination=, Source=, "
3102 "or PreferredSource= field configured. "
3103 "Ignoring [Route] section from line %u.",
3104 route
->section
->filename
, route
->section
->line
);
3107 if (route
->family
== AF_INET6
&& route
->gw_family
== AF_INET
)
3108 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3109 "%s: IPv4 gateway is configured for IPv6 route. "
3110 "Ignoring [Route] section from line %u.",
3111 route
->section
->filename
, route
->section
->line
);
3113 if (!route
->table_set
&& network
->vrf
) {
3114 route
->table
= VRF(network
->vrf
)->table
;
3115 route
->table_set
= true;
3118 if (!route
->table_set
&& IN_SET(route
->type
, RTN_LOCAL
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_NAT
))
3119 route
->table
= RT_TABLE_LOCAL
;
3121 if (!route
->scope_set
&& route
->family
!= AF_INET6
) {
3122 if (IN_SET(route
->type
, RTN_LOCAL
, RTN_NAT
))
3123 route
->scope
= RT_SCOPE_HOST
;
3124 else if (IN_SET(route
->type
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_MULTICAST
))
3125 route
->scope
= RT_SCOPE_LINK
;
3128 if (route
->scope
!= RT_SCOPE_UNIVERSE
&& route
->family
== AF_INET6
) {
3129 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route
->section
->filename
);
3130 route
->scope
= RT_SCOPE_UNIVERSE
;
3133 if (route
->family
== AF_INET6
&& route
->priority
== 0)
3134 route
->priority
= IP6_RT_PRIO_USER
;
3136 if (route
->gateway_onlink
< 0 && in_addr_is_set(route
->gw_family
, &route
->gw
) &&
3137 ordered_hashmap_isempty(network
->addresses_by_section
)) {
3138 /* If no address is configured, in most cases the gateway cannot be reachable.
3139 * TODO: we may need to improve the condition above. */
3140 log_warning("%s: Gateway= without static address configured. "
3141 "Enabling GatewayOnLink= option.",
3143 route
->gateway_onlink
= true;
3146 if (route
->family
== AF_INET6
) {
3149 ORDERED_SET_FOREACH(m
, route
->multipath_routes
)
3150 if (m
->gateway
.family
== AF_INET
)
3151 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3152 "%s: IPv4 multipath route is specified for IPv6 route. "
3153 "Ignoring [Route] section from line %u.",
3154 route
->section
->filename
, route
->section
->line
);
3157 if ((route
->gateway_from_dhcp_or_ra
||
3158 in_addr_is_set(route
->gw_family
, &route
->gw
)) &&
3159 !ordered_set_isempty(route
->multipath_routes
))
3160 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3161 "%s: Gateway= cannot be specified with MultiPathRoute=. "
3162 "Ignoring [Route] section from line %u.",
3163 route
->section
->filename
, route
->section
->line
);
3165 if (route
->nexthop_id
> 0 &&
3166 (route
->gateway_from_dhcp_or_ra
||
3167 in_addr_is_set(route
->gw_family
, &route
->gw
) ||
3168 !ordered_set_isempty(route
->multipath_routes
)))
3169 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3170 "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
3171 "Ignoring [Route] section from line %u.",
3172 route
->section
->filename
, route
->section
->line
);
3177 void network_drop_invalid_routes(Network
*network
) {
3182 HASHMAP_FOREACH(route
, network
->routes_by_section
)
3183 if (route_section_verify(route
, network
) < 0)