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 "string-table.h"
17 #include "string-util.h"
20 #include "sysctl-util.h"
23 #define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
25 static uint32_t link_get_vrf_table(const Link
*link
) {
26 return link
->network
->vrf
? VRF(link
->network
->vrf
)->table
: RT_TABLE_MAIN
;
29 uint32_t link_get_dhcp_route_table(const Link
*link
) {
30 /* When the interface is part of an VRF use the VRFs routing table, unless
31 * another table is explicitly specified. */
32 if (link
->network
->dhcp_route_table_set
)
33 return link
->network
->dhcp_route_table
;
34 return link_get_vrf_table(link
);
37 uint32_t link_get_ipv6_accept_ra_route_table(const Link
*link
) {
38 if (link
->network
->ipv6_accept_ra_route_table_set
)
39 return link
->network
->ipv6_accept_ra_route_table
;
40 return link_get_vrf_table(link
);
43 static const char * const route_type_table
[__RTN_MAX
] = {
44 [RTN_UNICAST
] = "unicast",
45 [RTN_LOCAL
] = "local",
46 [RTN_BROADCAST
] = "broadcast",
47 [RTN_ANYCAST
] = "anycast",
48 [RTN_MULTICAST
] = "multicast",
49 [RTN_BLACKHOLE
] = "blackhole",
50 [RTN_UNREACHABLE
] = "unreachable",
51 [RTN_PROHIBIT
] = "prohibit",
52 [RTN_THROW
] = "throw",
54 [RTN_XRESOLVE
] = "xresolve",
57 assert_cc(__RTN_MAX
<= UCHAR_MAX
);
58 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_type
, int);
60 static const char * const route_scope_table
[] = {
61 [RT_SCOPE_UNIVERSE
] = "global",
62 [RT_SCOPE_SITE
] = "site",
63 [RT_SCOPE_LINK
] = "link",
64 [RT_SCOPE_HOST
] = "host",
65 [RT_SCOPE_NOWHERE
] = "nowhere",
68 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_scope
, int);
69 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(route_scope
, int, UINT8_MAX
);
71 static const char * const route_table_table
[] = {
72 [RT_TABLE_DEFAULT
] = "default",
73 [RT_TABLE_MAIN
] = "main",
74 [RT_TABLE_LOCAL
] = "local",
77 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table
, int);
79 int manager_get_route_table_from_string(const Manager
*m
, const char *s
, uint32_t *ret
) {
87 r
= route_table_from_string(s
);
93 t
= PTR_TO_UINT32(hashmap_get(m
->route_table_numbers_by_name
, s
));
99 r
= safe_atou32(s
, &t
);
110 int manager_get_route_table_to_string(const Manager
*m
, uint32_t table
, char **ret
) {
111 _cleanup_free_
char *str
= NULL
;
120 s
= route_table_to_string(table
);
122 s
= hashmap_get(m
->route_table_names_by_number
, UINT32_TO_PTR(table
));
125 /* Currently, this is only used in debugging logs. To not confuse any bug
126 * reports, let's include the table number. */
127 if (asprintf(&str
, "%s(%" PRIu32
")", s
, table
) < 0)
130 *ret
= TAKE_PTR(str
);
134 if (asprintf(&str
, "%" PRIu32
, table
) < 0)
137 *ret
= TAKE_PTR(str
);
141 static const char * const route_protocol_table
[] = {
142 [RTPROT_KERNEL
] = "kernel",
143 [RTPROT_BOOT
] = "boot",
144 [RTPROT_STATIC
] = "static",
147 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(route_protocol
, int, UINT8_MAX
);
149 static const char * const route_protocol_full_table
[] = {
150 [RTPROT_REDIRECT
] = "redirect",
151 [RTPROT_KERNEL
] = "kernel",
152 [RTPROT_BOOT
] = "boot",
153 [RTPROT_STATIC
] = "static",
154 [RTPROT_GATED
] = "gated",
156 [RTPROT_MRT
] = "mrt",
157 [RTPROT_ZEBRA
] = "zebra",
158 [RTPROT_BIRD
] = "bird",
159 [RTPROT_DNROUTED
] = "dnrouted",
160 [RTPROT_XORP
] = "xorp",
161 [RTPROT_NTK
] = "ntk",
162 [RTPROT_DHCP
] = "dhcp",
163 [RTPROT_MROUTED
] = "mrouted",
164 [RTPROT_BABEL
] = "babel",
165 [RTPROT_BGP
] = "bgp",
166 [RTPROT_ISIS
] = "isis",
167 [RTPROT_OSPF
] = "ospf",
168 [RTPROT_RIP
] = "rip",
169 [RTPROT_EIGRP
] = "eigrp",
172 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(route_protocol_full
, int, UINT8_MAX
);
174 static unsigned routes_max(void) {
175 static thread_local
unsigned cached
= 0;
176 _cleanup_free_
char *s4
= NULL
, *s6
= NULL
;
177 unsigned val4
= ROUTES_DEFAULT_MAX_PER_FAMILY
, val6
= ROUTES_DEFAULT_MAX_PER_FAMILY
;
182 if (sysctl_read_ip_property(AF_INET
, NULL
, "route/max_size", &s4
) >= 0)
183 if (safe_atou(s4
, &val4
) >= 0 && val4
== 2147483647U)
184 /* This is the default "no limit" value in the kernel */
185 val4
= ROUTES_DEFAULT_MAX_PER_FAMILY
;
187 if (sysctl_read_ip_property(AF_INET6
, NULL
, "route/max_size", &s6
) >= 0)
188 (void) safe_atou(s6
, &val6
);
190 cached
= MAX(ROUTES_DEFAULT_MAX_PER_FAMILY
, val4
) +
191 MAX(ROUTES_DEFAULT_MAX_PER_FAMILY
, val6
);
195 int route_new(Route
**ret
) {
196 _cleanup_(route_freep
) Route
*route
= NULL
;
198 route
= new(Route
, 1);
204 .scope
= RT_SCOPE_UNIVERSE
,
205 .protocol
= RTPROT_UNSPEC
,
207 .table
= RT_TABLE_MAIN
,
208 .lifetime
= USEC_INFINITY
,
210 .fast_open_no_cookie
= -1,
211 .gateway_onlink
= -1,
215 *ret
= TAKE_PTR(route
);
220 static int route_new_static(Network
*network
, const char *filename
, unsigned section_line
, Route
**ret
) {
221 _cleanup_(network_config_section_freep
) NetworkConfigSection
*n
= NULL
;
222 _cleanup_(route_freep
) Route
*route
= NULL
;
228 assert(section_line
> 0);
230 r
= network_config_section_new(filename
, section_line
, &n
);
234 route
= hashmap_get(network
->routes_by_section
, n
);
236 *ret
= TAKE_PTR(route
);
240 if (hashmap_size(network
->routes_by_section
) >= routes_max())
243 r
= route_new(&route
);
247 route
->protocol
= RTPROT_STATIC
;
248 route
->network
= network
;
249 route
->section
= TAKE_PTR(n
);
251 r
= hashmap_ensure_put(&network
->routes_by_section
, &network_config_hash_ops
, route
->section
, route
);
255 *ret
= TAKE_PTR(route
);
259 Route
*route_free(Route
*route
) {
263 if (route
->network
) {
264 assert(route
->section
);
265 hashmap_remove(route
->network
->routes_by_section
, route
->section
);
268 network_config_section_free(route
->section
);
273 set_remove(route
->link
->routes
, route
);
274 set_remove(route
->link
->routes_foreign
, route
);
275 set_remove(route
->link
->dhcp_routes
, route
);
276 set_remove(route
->link
->dhcp_routes_old
, route
);
277 set_remove(route
->link
->dhcp6_routes
, route
);
278 set_remove(route
->link
->dhcp6_routes_old
, route
);
279 set_remove(route
->link
->dhcp6_pd_routes
, route
);
280 set_remove(route
->link
->dhcp6_pd_routes_old
, route
);
281 SET_FOREACH(n
, route
->link
->ndisc_routes
)
282 if (n
->route
== route
)
283 free(set_remove(route
->link
->ndisc_routes
, n
));
286 if (route
->manager
) {
287 set_remove(route
->manager
->routes
, route
);
288 set_remove(route
->manager
->routes_foreign
, route
);
291 ordered_set_free_with_destructor(route
->multipath_routes
, multipath_route_free
);
293 sd_event_source_unref(route
->expire
);
298 void route_hash_func(const Route
*route
, struct siphash
*state
) {
301 siphash24_compress(&route
->family
, sizeof(route
->family
), state
);
303 switch (route
->family
) {
306 siphash24_compress(&route
->dst_prefixlen
, sizeof(route
->dst_prefixlen
), state
);
307 siphash24_compress(&route
->dst
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
309 siphash24_compress(&route
->src_prefixlen
, sizeof(route
->src_prefixlen
), state
);
310 siphash24_compress(&route
->src
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
312 siphash24_compress(&route
->gw_family
, sizeof(route
->gw_family
), state
);
313 if (IN_SET(route
->gw_family
, AF_INET
, AF_INET6
)) {
314 siphash24_compress(&route
->gw
, FAMILY_ADDRESS_SIZE(route
->gw_family
), state
);
315 siphash24_compress(&route
->gw_weight
, sizeof(route
->gw_weight
), state
);
318 siphash24_compress(&route
->prefsrc
, FAMILY_ADDRESS_SIZE(route
->family
), state
);
320 siphash24_compress(&route
->tos
, sizeof(route
->tos
), state
);
321 siphash24_compress(&route
->priority
, sizeof(route
->priority
), state
);
322 siphash24_compress(&route
->table
, sizeof(route
->table
), state
);
323 siphash24_compress(&route
->protocol
, sizeof(route
->protocol
), state
);
324 siphash24_compress(&route
->scope
, sizeof(route
->scope
), state
);
325 siphash24_compress(&route
->type
, sizeof(route
->type
), state
);
327 siphash24_compress(&route
->initcwnd
, sizeof(route
->initcwnd
), state
);
328 siphash24_compress(&route
->initrwnd
, sizeof(route
->initrwnd
), state
);
330 siphash24_compress(&route
->advmss
, sizeof(route
->advmss
), state
);
331 siphash24_compress(&route
->nexthop_id
, sizeof(route
->nexthop_id
), state
);
335 /* treat any other address family as AF_UNSPEC */
340 int route_compare_func(const Route
*a
, const Route
*b
) {
343 r
= CMP(a
->family
, b
->family
);
350 r
= CMP(a
->dst_prefixlen
, b
->dst_prefixlen
);
354 r
= memcmp(&a
->dst
, &b
->dst
, FAMILY_ADDRESS_SIZE(a
->family
));
358 r
= CMP(a
->src_prefixlen
, b
->src_prefixlen
);
362 r
= memcmp(&a
->src
, &b
->src
, FAMILY_ADDRESS_SIZE(a
->family
));
366 r
= CMP(a
->gw_family
, b
->gw_family
);
370 if (IN_SET(a
->gw_family
, AF_INET
, AF_INET6
)) {
371 r
= memcmp(&a
->gw
, &b
->gw
, FAMILY_ADDRESS_SIZE(a
->family
));
375 r
= CMP(a
->gw_weight
, b
->gw_weight
);
380 r
= memcmp(&a
->prefsrc
, &b
->prefsrc
, FAMILY_ADDRESS_SIZE(a
->family
));
384 r
= CMP(a
->tos
, b
->tos
);
388 r
= CMP(a
->priority
, b
->priority
);
392 r
= CMP(a
->table
, b
->table
);
396 r
= CMP(a
->protocol
, b
->protocol
);
400 r
= CMP(a
->scope
, b
->scope
);
404 r
= CMP(a
->type
, b
->type
);
408 r
= CMP(a
->initcwnd
, b
->initcwnd
);
412 r
= CMP(a
->initrwnd
, b
->initrwnd
);
416 r
= CMP(a
->advmss
, b
->advmss
);
420 r
= CMP(a
->nexthop_id
, b
->nexthop_id
);
426 /* treat any other address family as AF_UNSPEC */
431 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
438 static bool route_equal(const Route
*r1
, const Route
*r2
) {
445 return route_compare_func(r1
, r2
) == 0;
448 static int route_get(const Manager
*manager
, const Link
*link
, const Route
*in
, Route
**ret
) {
451 assert(manager
|| link
);
454 existing
= set_get(link
? link
->routes
: manager
->routes
, in
);
461 existing
= set_get(link
? link
->routes_foreign
: manager
->routes_foreign
, in
);
471 static void route_copy(Route
*dest
, const Route
*src
, const MultipathRoute
*m
, const NextHop
*nh
, uint8_t nh_weight
) {
475 /* This only copies entries used by the above hash and compare functions. */
477 dest
->family
= src
->family
;
478 dest
->src
= src
->src
;
479 dest
->src_prefixlen
= src
->src_prefixlen
;
480 dest
->dst
= src
->dst
;
481 dest
->dst_prefixlen
= src
->dst_prefixlen
;
482 dest
->prefsrc
= src
->prefsrc
;
483 dest
->scope
= src
->scope
;
484 dest
->protocol
= src
->protocol
;
485 if (nh
&& nh
->blackhole
)
486 dest
->type
= RTN_BLACKHOLE
;
488 dest
->type
= src
->type
;
489 dest
->tos
= src
->tos
;
490 dest
->priority
= src
->priority
;
491 dest
->table
= src
->table
;
492 dest
->initcwnd
= src
->initcwnd
;
493 dest
->initrwnd
= src
->initrwnd
;
494 dest
->lifetime
= src
->lifetime
;
495 dest
->advmss
= src
->advmss
;
496 dest
->nexthop_id
= src
->nexthop_id
;
499 assert(hashmap_isempty(nh
->group
));
501 dest
->gw_family
= nh
->family
;
503 dest
->gw_weight
= nh_weight
!= UINT8_MAX
? nh_weight
: src
->gw_weight
;
505 dest
->gw_family
= m
->gateway
.family
;
506 dest
->gw
= m
->gateway
.address
;
507 dest
->gw_weight
= m
->weight
;
509 dest
->gw_family
= src
->gw_family
;
511 dest
->gw_weight
= src
->gw_weight
;
515 int route_dup(const Route
*src
, Route
**ret
) {
516 _cleanup_(route_freep
) Route
*dest
= NULL
;
523 dest
= newdup(Route
, src
, 1);
527 /* Unset all pointers */
528 dest
->network
= NULL
;
529 dest
->section
= NULL
;
531 dest
->manager
= NULL
;
532 dest
->multipath_routes
= NULL
;
535 ORDERED_SET_FOREACH(m
, src
->multipath_routes
) {
536 _cleanup_(multipath_route_freep
) MultipathRoute
*n
= NULL
;
538 r
= multipath_route_dup(m
, &n
);
542 r
= ordered_set_ensure_put(&dest
->multipath_routes
, NULL
, n
);
549 *ret
= TAKE_PTR(dest
);
553 static int route_add_internal(Manager
*manager
, Link
*link
, Set
**routes
, const Route
*in
, Route
**ret
) {
554 _cleanup_(route_freep
) Route
*route
= NULL
;
557 assert(manager
|| link
);
561 r
= route_new(&route
);
565 route_copy(route
, in
, NULL
, NULL
, UINT8_MAX
);
567 r
= set_ensure_put(routes
, &route_hash_ops
, route
);
574 route
->manager
= manager
;
584 static int route_add_foreign(Manager
*manager
, Link
*link
, const Route
*in
, Route
**ret
) {
585 assert(manager
|| link
);
586 return route_add_internal(manager
, link
, link
? &link
->routes_foreign
: &manager
->routes_foreign
, in
, ret
);
589 static int route_add(Manager
*manager
, Link
*link
, const Route
*in
, const MultipathRoute
*m
, const NextHop
*nh
, uint8_t nh_weight
, Route
**ret
) {
590 _cleanup_(route_freep
) Route
*tmp
= NULL
;
594 assert(manager
|| link
);
598 assert(hashmap_isempty(nh
->group
));
604 route_copy(tmp
, in
, NULL
, nh
, nh_weight
);
607 assert(link
&& (m
->ifindex
== 0 || m
->ifindex
== link
->ifindex
));
613 route_copy(tmp
, in
, m
, NULL
, UINT8_MAX
);
617 r
= route_get(manager
, link
, in
, &route
);
619 /* Route does not exist, create a new one */
620 r
= route_add_internal(manager
, link
, link
? &link
->routes
: &manager
->routes
, in
, &route
);
624 /* Take over a foreign route */
625 r
= set_ensure_put(link
? &link
->routes
: &manager
->routes
, &route_hash_ops
, route
);
629 set_remove(link
? link
->routes_foreign
: manager
->routes_foreign
, route
);
631 /* Route exists, do nothing */
641 static bool route_type_is_reject(const Route
*route
) {
644 return IN_SET(route
->type
, RTN_UNREACHABLE
, RTN_PROHIBIT
, RTN_BLACKHOLE
, RTN_THROW
);
647 static int link_has_route_one(Link
*link
, const Route
*route
, const NextHop
*nh
, uint8_t nh_weight
) {
648 _cleanup_(route_freep
) Route
*tmp
= NULL
;
659 route_copy(tmp
, route
, NULL
, nh
, nh_weight
);
661 if (route_type_is_reject(route
) || (nh
&& nh
->blackhole
))
662 return route_get(link
->manager
, NULL
, tmp
, NULL
) >= 0;
664 return route_get(NULL
, link
, tmp
, NULL
) >= 0;
667 int link_has_route(Link
*link
, const Route
*route
) {
674 if (route
->nexthop_id
> 0) {
675 struct nexthop_grp
*nhg
;
678 if (manager_get_nexthop_by_id(link
->manager
, route
->nexthop_id
, &nh
) < 0)
681 if (hashmap_isempty(nh
->group
))
682 return link_has_route_one(link
, route
, nh
, UINT8_MAX
);
684 HASHMAP_FOREACH(nhg
, nh
->group
) {
687 if (manager_get_nexthop_by_id(link
->manager
, nhg
->id
, &h
) < 0)
690 r
= link_has_route_one(link
, route
, h
, nhg
->weight
);
698 if (ordered_set_isempty(route
->multipath_routes
)) {
699 if (route_type_is_reject(route
))
700 return route_get(link
->manager
, NULL
, route
, NULL
) >= 0;
702 return route_get(NULL
, link
, route
, NULL
) >= 0;
705 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
706 _cleanup_(route_freep
) Route
*tmp
= NULL
;
710 if (link_get_by_name(link
->manager
, m
->ifname
, &l
) < 0)
713 m
->ifindex
= l
->ifindex
;
721 route_copy(tmp
, route
, m
, NULL
, UINT8_MAX
);
723 if (route_get(NULL
, l
, tmp
, NULL
) < 0)
730 static bool route_address_is_reachable(const Route
*route
, int family
, const union in_addr_union
*address
) {
732 assert(IN_SET(family
, AF_INET
, AF_INET6
));
735 if (route
->family
!= family
)
738 if (!in_addr_is_set(route
->family
, &route
->dst
))
741 return in_addr_prefix_intersect(
744 route
->dst_prefixlen
,
746 FAMILY_ADDRESS_SIZE(family
) * 8) > 0;
749 bool manager_address_is_reachable(Manager
*manager
, int family
, const union in_addr_union
*address
) {
753 assert(IN_SET(family
, AF_INET
, AF_INET6
));
756 HASHMAP_FOREACH(link
, manager
->links
) {
759 SET_FOREACH(route
, link
->routes
)
760 if (route_address_is_reachable(route
, family
, address
))
762 SET_FOREACH(route
, link
->routes_foreign
)
763 if (route_address_is_reachable(route
, family
, address
))
770 static Route
*routes_get_default_gateway(Set
*routes
, int family
, Route
*gw
) {
773 SET_FOREACH(route
, routes
) {
774 if (family
!= AF_UNSPEC
&& route
->family
!= family
)
776 if (route
->dst_prefixlen
!= 0)
778 if (route
->src_prefixlen
!= 0)
780 if (route
->table
!= RT_TABLE_MAIN
)
782 if (route
->type
!= RTN_UNICAST
)
784 if (route
->scope
!= RT_SCOPE_UNIVERSE
)
786 if (!in_addr_is_set(route
->gw_family
, &route
->gw
))
789 if (route
->gw_weight
> gw
->gw_weight
)
791 if (route
->priority
>= gw
->priority
)
800 int manager_find_uplink(Manager
*m
, int family
, Link
*exclude
, Link
**ret
) {
805 assert(IN_SET(family
, AF_UNSPEC
, AF_INET
, AF_INET6
));
807 /* Looks for a suitable "uplink", via black magic: an interface that is up and where the
808 * default route with the highest priority points to. */
810 HASHMAP_FOREACH(link
, m
->links
) {
814 if (link
->state
!= LINK_STATE_CONFIGURED
)
817 gw
= routes_get_default_gateway(link
->routes
, family
, gw
);
818 gw
= routes_get_default_gateway(link
->routes_foreign
, family
, gw
);
829 static void log_route_debug(const Route
*route
, const char *str
, const Link
*link
, const Manager
*manager
) {
830 _cleanup_free_
char *dst
= NULL
, *src
= NULL
, *gw_alloc
= NULL
, *prefsrc
= NULL
,
831 *table
= NULL
, *scope
= NULL
, *proto
= NULL
;
832 const char *gw
= NULL
;
838 /* link may be NULL. */
843 if (in_addr_is_set(route
->family
, &route
->dst
))
844 (void) in_addr_prefix_to_string(route
->family
, &route
->dst
, route
->dst_prefixlen
, &dst
);
845 if (in_addr_is_set(route
->family
, &route
->src
))
846 (void) in_addr_to_string(route
->family
, &route
->src
, &src
);
847 if (in_addr_is_set(route
->gw_family
, &route
->gw
)) {
848 (void) in_addr_to_string(route
->gw_family
, &route
->gw
, &gw_alloc
);
850 } else if (route
->gateway_from_dhcp_or_ra
) {
851 if (route
->gw_family
== AF_INET
)
853 else if (route
->gw_family
== AF_INET6
)
858 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
859 _cleanup_free_
char *buf
= NULL
;
860 union in_addr_union a
= m
->gateway
.address
;
862 (void) in_addr_to_string(m
->gateway
.family
, &a
, &buf
);
863 (void) strextend_with_separator(&gw_alloc
, ",", strna(buf
));
865 (void) strextend(&gw_alloc
, "@", m
->ifname
);
866 else if (m
->ifindex
> 0)
867 (void) strextendf(&gw_alloc
, "@%"PRIu32
, m
->ifindex
);
868 /* See comments in config_parse_multipath_route(). */
869 (void) strextendf(&gw_alloc
, ":%"PRIu32
, m
->weight
+ 1);
873 if (in_addr_is_set(route
->family
, &route
->prefsrc
))
874 (void) in_addr_to_string(route
->family
, &route
->prefsrc
, &prefsrc
);
875 (void) route_scope_to_string_alloc(route
->scope
, &scope
);
876 (void) manager_get_route_table_to_string(manager
, route
->table
, &table
);
877 (void) route_protocol_full_to_string_alloc(route
->protocol
, &proto
);
880 "%s route: dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s, nexthop: %"PRIu32
", priority: %"PRIu32
,
881 str
, strna(dst
), strna(src
), strna(gw
), strna(prefsrc
),
882 strna(scope
), strna(table
), strna(proto
),
883 strna(route_type_to_string(route
->type
)),
884 route
->nexthop_id
, route
->priority
);
887 static int route_set_netlink_message(const Route
*route
, sd_netlink_message
*req
, Link
*link
) {
894 /* link may be NULL */
896 if (in_addr_is_set(route
->gw_family
, &route
->gw
) && route
->nexthop_id
== 0) {
897 if (route
->gw_family
== route
->family
) {
898 r
= netlink_message_append_in_addr_union(req
, RTA_GATEWAY
, route
->gw_family
, &route
->gw
);
900 return log_link_error_errno(link
, r
, "Could not append RTA_GATEWAY attribute: %m");
903 .family
= route
->gw_family
,
904 .address
= route
->gw
,
907 r
= sd_netlink_message_append_data(req
, RTA_VIA
, &rtvia
, sizeof(rtvia
));
909 return log_link_error_errno(link
, r
, "Could not append RTA_VIA attribute: %m");
913 if (route
->dst_prefixlen
> 0) {
914 r
= netlink_message_append_in_addr_union(req
, RTA_DST
, route
->family
, &route
->dst
);
916 return log_link_error_errno(link
, r
, "Could not append RTA_DST attribute: %m");
918 r
= sd_rtnl_message_route_set_dst_prefixlen(req
, route
->dst_prefixlen
);
920 return log_link_error_errno(link
, r
, "Could not set destination prefix length: %m");
923 if (route
->src_prefixlen
> 0) {
924 r
= netlink_message_append_in_addr_union(req
, RTA_SRC
, route
->family
, &route
->src
);
926 return log_link_error_errno(link
, r
, "Could not append RTA_SRC attribute: %m");
928 r
= sd_rtnl_message_route_set_src_prefixlen(req
, route
->src_prefixlen
);
930 return log_link_error_errno(link
, r
, "Could not set source prefix length: %m");
933 if (in_addr_is_set(route
->family
, &route
->prefsrc
)) {
934 r
= netlink_message_append_in_addr_union(req
, RTA_PREFSRC
, route
->family
, &route
->prefsrc
);
936 return log_link_error_errno(link
, r
, "Could not append RTA_PREFSRC attribute: %m");
939 r
= sd_rtnl_message_route_set_scope(req
, route
->scope
);
941 return log_link_error_errno(link
, r
, "Could not set scope: %m");
943 flags
= route
->flags
;
944 if (route
->gateway_onlink
>= 0)
945 SET_FLAG(flags
, RTNH_F_ONLINK
, route
->gateway_onlink
);
947 r
= sd_rtnl_message_route_set_flags(req
, flags
);
949 return log_link_error_errno(link
, r
, "Could not set flags: %m");
951 if (route
->table
< 256) {
952 r
= sd_rtnl_message_route_set_table(req
, route
->table
);
954 return log_link_error_errno(link
, r
, "Could not set route table: %m");
956 r
= sd_rtnl_message_route_set_table(req
, RT_TABLE_UNSPEC
);
958 return log_link_error_errno(link
, r
, "Could not set route table: %m");
960 /* Table attribute to allow more than 256. */
961 r
= sd_netlink_message_append_data(req
, RTA_TABLE
, &route
->table
, sizeof(route
->table
));
963 return log_link_error_errno(link
, r
, "Could not append RTA_TABLE attribute: %m");
966 if (!route_type_is_reject(route
) &&
967 route
->nexthop_id
== 0 &&
968 ordered_set_isempty(route
->multipath_routes
)) {
969 assert(link
); /* Those routes must be attached to a specific link */
971 r
= sd_netlink_message_append_u32(req
, RTA_OIF
, link
->ifindex
);
973 return log_link_error_errno(link
, r
, "Could not append RTA_OIF attribute: %m");
976 if (route
->nexthop_id
> 0) {
977 r
= sd_netlink_message_append_u32(req
, RTA_NH_ID
, route
->nexthop_id
);
979 return log_link_error_errno(link
, r
, "Could not append RTA_NH_ID attribute: %m");
982 r
= sd_netlink_message_append_u8(req
, RTA_PREF
, route
->pref
);
984 return log_link_error_errno(link
, r
, "Could not append RTA_PREF attribute: %m");
986 r
= sd_netlink_message_append_u32(req
, RTA_PRIORITY
, route
->priority
);
988 return log_link_error_errno(link
, r
, "Could not append RTA_PRIORITY attribute: %m");
993 static int link_route_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
998 assert(link
->route_remove_messages
> 0);
1000 link
->route_remove_messages
--;
1002 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
1005 r
= sd_netlink_message_get_errno(m
);
1006 if (r
< 0 && r
!= -ESRCH
)
1007 log_link_message_warning_errno(link
, m
, r
, "Could not drop route, ignoring");
1012 static int manager_route_remove_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Manager
*manager
) {
1017 assert(manager
->route_remove_messages
> 0);
1019 manager
->route_remove_messages
--;
1021 r
= sd_netlink_message_get_errno(m
);
1022 if (r
< 0 && r
!= -ESRCH
)
1023 log_message_warning_errno(m
, r
, "Could not drop route, ignoring");
1028 int route_remove(const Route
*route
, Manager
*manager
, Link
*link
) {
1029 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
1033 assert(link
|| manager
);
1034 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
1037 manager
= link
->manager
;
1039 log_route_debug(route
, "Removing", link
, manager
);
1041 r
= sd_rtnl_message_new_route(manager
->rtnl
, &req
,
1042 RTM_DELROUTE
, route
->family
,
1045 return log_link_error_errno(link
, r
, "Could not create RTM_DELROUTE message: %m");
1047 if (route
->family
== AF_INET
&& route
->nexthop_id
> 0 && route
->type
== RTN_BLACKHOLE
)
1048 /* When IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel
1049 * sends RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type
1050 * fib_rt_info::type may not be blackhole. Thus, we cannot know the internal value.
1051 * Moreover, on route removal, the matching is done with the hidden value if we set
1052 * non-zero type in RTM_DELROUTE message. Note, sd_rtnl_message_new_route() sets
1053 * RTN_UNICAST by default. So, we need to clear the type here. */
1058 r
= sd_rtnl_message_route_set_type(req
, type
);
1060 return log_link_error_errno(link
, r
, "Could not set route type: %m");
1062 r
= route_set_netlink_message(route
, req
, link
);
1067 r
= netlink_call_async(manager
->rtnl
, NULL
, req
,
1068 link_route_remove_handler
,
1069 link_netlink_destroy_callback
, link
);
1071 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
1074 link
->route_remove_messages
++;
1076 r
= netlink_call_async(manager
->rtnl
, NULL
, req
,
1077 manager_route_remove_handler
,
1080 return log_error_errno(r
, "Could not send rtnetlink message: %m");
1082 manager
->route_remove_messages
++;
1088 static bool link_has_static_route(const Link
*link
, const Route
*route
) {
1097 HASHMAP_FOREACH(net_route
, link
->network
->routes_by_section
)
1098 if (route_equal(net_route
, route
))
1104 static bool links_have_static_route(const Manager
*manager
, const Route
*route
, const Link
*except
) {
1109 HASHMAP_FOREACH(link
, manager
->links
) {
1113 if (link_has_static_route(link
, route
))
1120 static int manager_drop_routes_internal(Manager
*manager
, bool foreign
, const Link
*except
) {
1127 routes
= foreign
? manager
->routes_foreign
: manager
->routes
;
1128 SET_FOREACH(route
, routes
) {
1129 if (route
->removing
)
1132 /* Do not touch routes managed by the kernel. */
1133 if (route
->protocol
== RTPROT_KERNEL
)
1136 /* The route will be configured later, or already configured by a link. */
1137 if (links_have_static_route(manager
, route
, except
))
1140 /* The existing links do not have the route. Let's drop this now. It may be
1141 * re-configured later. */
1142 k
= route_remove(route
, manager
, NULL
);
1143 if (k
< 0 && r
>= 0)
1146 route
->removing
= true;
1152 static int manager_drop_foreign_routes(Manager
*manager
) {
1153 return manager_drop_routes_internal(manager
, true, NULL
);
1156 static int manager_drop_routes(Manager
*manager
, const Link
*except
) {
1157 return manager_drop_routes_internal(manager
, false, except
);
1160 int link_drop_foreign_routes(Link
*link
) {
1165 assert(link
->manager
);
1167 SET_FOREACH(route
, link
->routes_foreign
) {
1168 /* do not touch routes managed by the kernel */
1169 if (route
->protocol
== RTPROT_KERNEL
)
1172 /* do not touch multicast route added by kernel */
1173 /* FIXME: Why the kernel adds this route with protocol RTPROT_BOOT??? We need to investigate that.
1174 * https://tools.ietf.org/html/rfc4862#section-5.4 may explain why. */
1175 if (route
->protocol
== RTPROT_BOOT
&&
1176 route
->family
== AF_INET6
&&
1177 route
->dst_prefixlen
== 8 &&
1178 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 }}} }))
1181 if (route
->protocol
== RTPROT_STATIC
&& link
->network
&&
1182 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_STATIC
))
1185 if (route
->protocol
== RTPROT_DHCP
&& link
->network
&&
1186 FLAGS_SET(link
->network
->keep_configuration
, KEEP_CONFIGURATION_DHCP
))
1189 if (link_has_static_route(link
, route
))
1190 k
= route_add(NULL
, link
, route
, NULL
, NULL
, UINT8_MAX
, NULL
);
1192 k
= route_remove(route
, NULL
, link
);
1193 if (k
< 0 && r
>= 0)
1197 k
= manager_drop_foreign_routes(link
->manager
);
1198 if (k
< 0 && r
>= 0)
1204 int link_drop_routes(Link
*link
) {
1210 SET_FOREACH(route
, link
->routes
) {
1211 /* do not touch routes managed by the kernel */
1212 if (route
->protocol
== RTPROT_KERNEL
)
1215 k
= route_remove(route
, NULL
, link
);
1216 if (k
< 0 && r
>= 0)
1220 k
= manager_drop_routes(link
->manager
, link
);
1221 if (k
< 0 && r
>= 0)
1227 static int route_expire_handler(sd_event_source
*s
, uint64_t usec
, void *userdata
) {
1228 Route
*route
= userdata
;
1233 r
= route_remove(route
, route
->manager
, route
->link
);
1235 log_link_warning_errno(route
->link
, r
, "Could not remove route: %m");
1242 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
) {
1243 _cleanup_(sd_event_source_unrefp
) sd_event_source
*expire
= NULL
;
1248 assert(link
->manager
);
1253 if (route_type_is_reject(route
) || (nh
&& nh
->blackhole
))
1254 r
= route_add(link
->manager
, NULL
, route
, NULL
, nh
, nh_weight
, &nr
);
1257 assert(hashmap_isempty(nh
->group
));
1259 r
= route_add(NULL
, nh
->link
, route
, NULL
, nh
, nh_weight
, &nr
);
1260 } else if (m
&& m
->ifindex
!= 0 && m
->ifindex
!= link
->ifindex
) {
1263 r
= link_get(link
->manager
, m
->ifindex
, &link_gw
);
1265 return log_link_error_errno(link
, r
, "Failed to get link with ifindex %d: %m", m
->ifindex
);
1267 r
= route_add(NULL
, link_gw
, route
, m
, NULL
, UINT8_MAX
, &nr
);
1269 r
= route_add(NULL
, link
, route
, m
, NULL
, UINT8_MAX
, &nr
);
1271 return log_link_error_errno(link
, r
, "Could not add route: %m");
1273 /* TODO: drop expiration handling once it can be pushed into the kernel */
1274 if (nr
->lifetime
!= USEC_INFINITY
&& !kernel_route_expiration_supported()) {
1275 r
= sd_event_add_time(link
->manager
->event
, &expire
, clock_boottime_or_monotonic(),
1276 nr
->lifetime
, 0, route_expire_handler
, nr
);
1278 return log_link_error_errno(link
, r
, "Could not arm expiration timer: %m");
1281 sd_event_source_unref(nr
->expire
);
1282 nr
->expire
= TAKE_PTR(expire
);
1288 static int route_add_and_setup_timer(Link
*link
, const Route
*route
, unsigned *ret_n_routes
, Route
***ret_routes
) {
1289 _cleanup_free_ Route
**routes
= NULL
;
1297 assert(ret_n_routes
);
1300 if (route
->nexthop_id
> 0) {
1301 r
= manager_get_nexthop_by_id(link
->manager
, route
->nexthop_id
, &nh
);
1303 return log_link_error_errno(link
, r
, "Could not get nexthop by ID %"PRIu32
": %m", route
->nexthop_id
);
1307 if (nh
&& !hashmap_isempty(nh
->group
)) {
1308 struct nexthop_grp
*nhg
;
1310 n_routes
= hashmap_size(nh
->group
);
1311 p
= routes
= new(Route
*, n_routes
);
1315 HASHMAP_FOREACH(nhg
, nh
->group
) {
1318 r
= manager_get_nexthop_by_id(link
->manager
, nhg
->id
, &h
);
1320 return log_link_error_errno(link
, r
, "Could not get nexthop group member by ID %"PRIu32
": %m", nhg
->id
);
1322 /* The nexthop h may be a blackhole nexthop. In that case, h->link is NULL. */
1323 r
= route_add_and_setup_timer_one(h
->link
?: link
, route
, NULL
, h
, nhg
->weight
, p
++);
1327 } else if (!ordered_set_isempty(route
->multipath_routes
)) {
1331 assert(!in_addr_is_set(route
->gw_family
, &route
->gw
));
1333 n_routes
= ordered_set_size(route
->multipath_routes
);
1334 p
= routes
= new(Route
*, n_routes
);
1338 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1339 r
= route_add_and_setup_timer_one(link
, route
, m
, NULL
, UINT8_MAX
, p
++);
1345 routes
= new(Route
*, n_routes
);
1349 r
= route_add_and_setup_timer_one(link
, route
, NULL
, nh
, UINT8_MAX
, routes
);
1354 *ret_n_routes
= n_routes
;
1355 *ret_routes
= TAKE_PTR(routes
);
1359 static int append_nexthop_one(const Link
*link
, const Route
*route
, const MultipathRoute
*m
, struct rtattr
**rta
, size_t offset
) {
1360 struct rtnexthop
*rtnh
;
1361 struct rtattr
*new_rta
;
1369 new_rta
= realloc(*rta
, RTA_ALIGN((*rta
)->rta_len
) + RTA_SPACE(sizeof(struct rtnexthop
)));
1374 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1375 *rtnh
= (struct rtnexthop
) {
1376 .rtnh_len
= sizeof(*rtnh
),
1377 .rtnh_ifindex
= m
->ifindex
> 0 ? m
->ifindex
: link
->ifindex
,
1378 .rtnh_hops
= m
->weight
,
1381 (*rta
)->rta_len
+= sizeof(struct rtnexthop
);
1383 if (route
->family
== m
->gateway
.family
) {
1384 r
= rtattr_append_attribute(rta
, RTA_GATEWAY
, &m
->gateway
.address
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1387 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1388 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
));
1390 r
= rtattr_append_attribute(rta
, RTA_VIA
, &m
->gateway
, FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1393 rtnh
= (struct rtnexthop
*)((uint8_t *) *rta
+ offset
);
1394 rtnh
->rtnh_len
+= RTA_SPACE(FAMILY_ADDRESS_SIZE(m
->gateway
.family
) + sizeof(m
->gateway
.family
));
1400 (*rta
)->rta_len
-= sizeof(struct rtnexthop
);
1404 static int append_nexthops(const Link
*link
, const Route
*route
, sd_netlink_message
*req
) {
1405 _cleanup_free_
struct rtattr
*rta
= NULL
;
1406 struct rtnexthop
*rtnh
;
1415 if (ordered_set_isempty(route
->multipath_routes
))
1418 rta
= new(struct rtattr
, 1);
1422 *rta
= (struct rtattr
) {
1423 .rta_type
= RTA_MULTIPATH
,
1424 .rta_len
= RTA_LENGTH(0),
1426 offset
= (uint8_t *) RTA_DATA(rta
) - (uint8_t *) rta
;
1428 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1429 r
= append_nexthop_one(link
, route
, m
, &rta
, offset
);
1433 rtnh
= (struct rtnexthop
*)((uint8_t *) rta
+ offset
);
1434 offset
= (uint8_t *) RTNH_NEXT(rtnh
) - (uint8_t *) rta
;
1437 r
= sd_netlink_message_append_data(req
, RTA_MULTIPATH
, RTA_DATA(rta
), RTA_PAYLOAD(rta
));
1444 int route_configure_handler_internal(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
, const char *error_msg
) {
1451 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
1454 r
= sd_netlink_message_get_errno(m
);
1455 if (r
< 0 && r
!= -EEXIST
) {
1456 log_link_message_warning_errno(link
, m
, r
, "Could not set route");
1457 link_enter_failed(link
);
1464 static int route_configure(
1467 link_netlink_message_handler_t callback
,
1468 unsigned *ret_n_routes
,
1469 Route
***ret_routes
) {
1471 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
1472 _cleanup_free_ Route
**routes
= NULL
;
1473 unsigned n_routes
= 0; /* avoid false maybe-uninitialized warning */
1477 assert(link
->manager
);
1478 assert(link
->manager
->rtnl
);
1479 assert(link
->ifindex
> 0);
1480 assert(IN_SET(route
->family
, AF_INET
, AF_INET6
));
1482 assert(!!ret_n_routes
== !!ret_routes
);
1484 if (route_get(link
->manager
, link
, route
, NULL
) <= 0 &&
1485 set_size(link
->routes
) >= routes_max())
1486 return log_link_error_errno(link
, SYNTHETIC_ERRNO(E2BIG
),
1487 "Too many routes are configured, refusing: %m");
1489 log_route_debug(route
, "Configuring", link
, link
->manager
);
1491 r
= sd_rtnl_message_new_route(link
->manager
->rtnl
, &req
,
1492 RTM_NEWROUTE
, route
->family
,
1495 return log_link_error_errno(link
, r
, "Could not create RTM_NEWROUTE message: %m");
1497 r
= sd_rtnl_message_route_set_type(req
, route
->type
);
1499 return log_link_error_errno(link
, r
, "Could not set route type: %m");
1501 r
= route_set_netlink_message(route
, req
, link
);
1505 if (route
->lifetime
!= USEC_INFINITY
&& kernel_route_expiration_supported()) {
1506 r
= sd_netlink_message_append_u32(req
, RTA_EXPIRES
,
1507 DIV_ROUND_UP(usec_sub_unsigned(route
->lifetime
, now(clock_boottime_or_monotonic())), USEC_PER_SEC
));
1509 return log_link_error_errno(link
, r
, "Could not append RTA_EXPIRES attribute: %m");
1512 if (route
->ttl_propagate
>= 0) {
1513 r
= sd_netlink_message_append_u8(req
, RTA_TTL_PROPAGATE
, route
->ttl_propagate
);
1515 return log_link_error_errno(link
, r
, "Could not append RTA_TTL_PROPAGATE attribute: %m");
1518 r
= sd_netlink_message_open_container(req
, RTA_METRICS
);
1520 return log_link_error_errno(link
, r
, "Could not append RTA_METRICS attribute: %m");
1522 if (route
->mtu
> 0) {
1523 r
= sd_netlink_message_append_u32(req
, RTAX_MTU
, route
->mtu
);
1525 return log_link_error_errno(link
, r
, "Could not append RTAX_MTU attribute: %m");
1528 if (route
->initcwnd
> 0) {
1529 r
= sd_netlink_message_append_u32(req
, RTAX_INITCWND
, route
->initcwnd
);
1531 return log_link_error_errno(link
, r
, "Could not append RTAX_INITCWND attribute: %m");
1534 if (route
->initrwnd
> 0) {
1535 r
= sd_netlink_message_append_u32(req
, RTAX_INITRWND
, route
->initrwnd
);
1537 return log_link_error_errno(link
, r
, "Could not append RTAX_INITRWND attribute: %m");
1540 if (route
->quickack
>= 0) {
1541 r
= sd_netlink_message_append_u32(req
, RTAX_QUICKACK
, route
->quickack
);
1543 return log_link_error_errno(link
, r
, "Could not append RTAX_QUICKACK attribute: %m");
1546 if (route
->fast_open_no_cookie
>= 0) {
1547 r
= sd_netlink_message_append_u32(req
, RTAX_FASTOPEN_NO_COOKIE
, route
->fast_open_no_cookie
);
1549 return log_link_error_errno(link
, r
, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
1552 if (route
->advmss
> 0) {
1553 r
= sd_netlink_message_append_u32(req
, RTAX_ADVMSS
, route
->advmss
);
1555 return log_link_error_errno(link
, r
, "Could not append RTAX_ADVMSS attribute: %m");
1558 r
= sd_netlink_message_close_container(req
);
1560 return log_link_error_errno(link
, r
, "Could not append RTA_METRICS attribute: %m");
1562 if (!ordered_set_isempty(route
->multipath_routes
)) {
1563 assert(route
->nexthop_id
== 0);
1564 assert(!in_addr_is_set(route
->gw_family
, &route
->gw
));
1566 r
= append_nexthops(link
, route
, req
);
1568 return log_link_error_errno(link
, r
, "Could not append RTA_MULTIPATH attribute: %m");
1571 r
= route_add_and_setup_timer(link
, route
, &n_routes
, &routes
);
1575 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, callback
,
1576 link_netlink_destroy_callback
, link
);
1578 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
1583 *ret_n_routes
= n_routes
;
1584 *ret_routes
= TAKE_PTR(routes
);
1590 static int static_route_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
1594 assert(link
->static_route_messages
> 0);
1596 link
->static_route_messages
--;
1598 r
= route_configure_handler_internal(rtnl
, m
, link
, "Could not set route");
1602 if (link
->static_route_messages
== 0) {
1603 log_link_debug(link
, "Routes set");
1604 link
->static_routes_configured
= true;
1605 link_check_ready(link
);
1611 int link_request_route(
1614 bool consume_object
,
1615 unsigned *message_counter
,
1616 link_netlink_message_handler_t netlink_handler
,
1620 assert(link
->manager
);
1623 log_route_debug(route
, "Requesting", link
, link
->manager
);
1624 return link_queue_request(link
, REQUEST_TYPE_ROUTE
, route
, consume_object
,
1625 message_counter
, netlink_handler
, ret
);
1628 int link_request_static_routes(Link
*link
, bool only_ipv4
) {
1633 assert(link
->network
);
1635 link
->static_routes_configured
= false;
1637 HASHMAP_FOREACH(route
, link
->network
->routes_by_section
) {
1638 if (route
->gateway_from_dhcp_or_ra
)
1641 if (only_ipv4
&& route
->family
!= AF_INET
)
1644 r
= link_request_route(link
, route
, false, &link
->static_route_messages
,
1645 static_route_handler
, NULL
);
1650 if (link
->static_route_messages
== 0) {
1651 link
->static_routes_configured
= true;
1652 link_check_ready(link
);
1654 log_link_debug(link
, "Requesting routes");
1655 link_set_state(link
, LINK_STATE_CONFIGURING
);
1661 static int route_is_ready_to_configure(const Route
*route
, Link
*link
) {
1669 if (route
->nexthop_id
> 0) {
1670 struct nexthop_grp
*nhg
;
1672 if (manager_get_nexthop_by_id(link
->manager
, route
->nexthop_id
, &nh
) < 0)
1675 HASHMAP_FOREACH(nhg
, nh
->group
)
1676 if (manager_get_nexthop_by_id(link
->manager
, nhg
->id
, NULL
) < 0)
1680 if (route_type_is_reject(route
) || (nh
&& nh
->blackhole
)) {
1681 if (nh
&& link
->manager
->nexthop_remove_messages
> 0)
1683 if (link
->manager
->route_remove_messages
> 0)
1688 HASHMAP_FOREACH(l
, link
->manager
->links
) {
1689 if (l
->address_remove_messages
> 0)
1691 if (l
->nexthop_remove_messages
> 0)
1693 if (l
->route_remove_messages
> 0)
1698 if (in_addr_is_set(route
->family
, &route
->prefsrc
) > 0) {
1699 r
= manager_has_address(link
->manager
, route
->family
, &route
->prefsrc
, route
->family
== AF_INET6
);
1704 if (route
->gateway_onlink
<= 0 &&
1705 in_addr_is_set(route
->gw_family
, &route
->gw
) > 0 &&
1706 !manager_address_is_reachable(link
->manager
, route
->gw_family
, &route
->gw
))
1709 ORDERED_SET_FOREACH(m
, route
->multipath_routes
) {
1710 union in_addr_union a
= m
->gateway
.address
;
1713 if (route
->gateway_onlink
<= 0 &&
1714 !manager_address_is_reachable(link
->manager
, m
->gateway
.family
, &a
))
1718 if (link_get_by_name(link
->manager
, m
->ifname
, &l
) < 0)
1721 m
->ifindex
= l
->ifindex
;
1722 } else if (m
->ifindex
> 0) {
1723 if (link_get(link
->manager
, m
->ifindex
, &l
) < 0)
1726 if (l
&& !link_is_ready_to_configure(l
, true))
1733 int request_process_route(Request
*req
) {
1734 _cleanup_free_ Route
**routes
= NULL
;
1741 assert(req
->type
== REQUEST_TYPE_ROUTE
);
1743 if (!link_is_ready_to_configure(req
->link
, false))
1746 r
= route_is_ready_to_configure(req
->route
, req
->link
);
1750 r
= route_configure(req
->route
, req
->link
, req
->netlink_handler
,
1751 req
->after_configure
? &n_routes
: NULL
,
1752 req
->after_configure
? &routes
: NULL
);
1756 /* To prevent a double decrement on failure in after_configure(). */
1757 req
->message_counter
= NULL
;
1759 if (req
->after_configure
) {
1760 assert(n_routes
> 0);
1762 for (unsigned i
= 0; i
< n_routes
; i
++) {
1763 r
= req
->after_configure(req
, routes
[i
]);
1772 static int process_route_one(Manager
*manager
, Link
*link
, uint16_t type
, const Route
*tmp
, const MultipathRoute
*m
) {
1773 _cleanup_(route_freep
) Route
*nr
= NULL
;
1774 Route
*route
= NULL
;
1780 assert(IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
));
1782 (void) manager_get_nexthop_by_id(manager
, tmp
->nexthop_id
, &nh
);
1784 if (nh
&& hashmap_isempty(nh
->group
)) {
1785 if (link
&& nh
->link
&& link
!= nh
->link
)
1786 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EINVAL
),
1787 "rtnl: received RTA_OIF and ifindex of nexthop corresponding to RTA_NH_ID do not match, ignoring.");
1796 route_copy(nr
, tmp
, NULL
, nh
, UINT8_MAX
);
1801 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EINVAL
),
1802 "rtnl: received route contains both RTA_OIF and RTA_MULTIPATH, ignoring.");
1804 if (m
->ifindex
<= 0)
1805 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
1806 "rtnl: received multipath route with invalid ifindex, ignoring.");
1808 r
= link_get(manager
, m
->ifindex
, &link
);
1810 log_warning_errno(r
, "rtnl: received multipath route for link (%d) we do not know, ignoring: %m", m
->ifindex
);
1818 route_copy(nr
, tmp
, m
, NULL
, UINT8_MAX
);
1823 (void) route_get(manager
, link
, tmp
, &route
);
1828 if (!manager
->manage_foreign_routes
)
1829 log_route_debug(tmp
, "Ignoring received foreign", link
, manager
);
1831 /* A route appeared that we did not request */
1832 log_route_debug(tmp
, "Remembering foreign", link
, manager
);
1833 r
= route_add_foreign(manager
, link
, tmp
, NULL
);
1835 log_link_warning_errno(link
, r
, "Failed to remember foreign route, ignoring: %m");
1840 log_route_debug(tmp
, "Received remembered", link
, manager
);
1845 log_route_debug(tmp
,
1846 route
? "Forgetting" :
1847 manager
->manage_foreign_routes
? "Kernel removed unknown" : "Ignoring received foreign",
1853 assert_not_reached("Received route message with invalid RTNL message type");
1859 int manager_rtnl_process_route(sd_netlink
*rtnl
, sd_netlink_message
*message
, Manager
*m
) {
1860 _cleanup_ordered_set_free_free_ OrderedSet
*multipath_routes
= NULL
;
1861 _cleanup_(route_freep
) Route
*tmp
= NULL
;
1862 _cleanup_free_
void *rta_multipath
= NULL
;
1866 unsigned char table
;
1874 if (sd_netlink_message_is_error(message
)) {
1875 r
= sd_netlink_message_get_errno(message
);
1877 log_message_warning_errno(message
, r
, "rtnl: failed to receive route message, ignoring");
1882 r
= sd_netlink_message_get_type(message
, &type
);
1884 log_warning_errno(r
, "rtnl: could not get message type, ignoring: %m");
1886 } else if (!IN_SET(type
, RTM_NEWROUTE
, RTM_DELROUTE
)) {
1887 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type
);
1891 r
= sd_netlink_message_read_u32(message
, RTA_OIF
, &ifindex
);
1892 if (r
< 0 && r
!= -ENODATA
) {
1893 log_warning_errno(r
, "rtnl: could not get ifindex from route message, ignoring: %m");
1895 } else if (r
>= 0) {
1897 log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex
);
1901 r
= link_get(m
, ifindex
, &link
);
1902 if (r
< 0 || !link
) {
1903 /* when enumerating we might be out of sync, but we will
1904 * get the route again, so just ignore it */
1905 if (!m
->enumerating
)
1906 log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex
);
1911 r
= route_new(&tmp
);
1915 r
= sd_rtnl_message_route_get_family(message
, &tmp
->family
);
1917 log_link_warning(link
, "rtnl: received route message without family, ignoring");
1919 } else if (!IN_SET(tmp
->family
, AF_INET
, AF_INET6
)) {
1920 log_link_debug(link
, "rtnl: received route message with invalid family '%i', ignoring", tmp
->family
);
1924 r
= sd_rtnl_message_route_get_protocol(message
, &tmp
->protocol
);
1926 log_warning_errno(r
, "rtnl: received route message without route protocol: %m");
1930 r
= netlink_message_read_in_addr_union(message
, RTA_DST
, tmp
->family
, &tmp
->dst
);
1931 if (r
< 0 && r
!= -ENODATA
) {
1932 log_link_warning_errno(link
, r
, "rtnl: received route message without valid destination, ignoring: %m");
1936 r
= netlink_message_read_in_addr_union(message
, RTA_GATEWAY
, tmp
->family
, &tmp
->gw
);
1937 if (r
< 0 && r
!= -ENODATA
) {
1938 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1941 tmp
->gw_family
= tmp
->family
;
1942 else if (tmp
->family
== AF_INET
) {
1945 r
= sd_netlink_message_read(message
, RTA_VIA
, sizeof(via
), &via
);
1946 if (r
< 0 && r
!= -ENODATA
) {
1947 log_link_warning_errno(link
, r
, "rtnl: received route message without valid gateway, ignoring: %m");
1949 } else if (r
>= 0) {
1950 tmp
->gw_family
= via
.family
;
1951 tmp
->gw
= via
.address
;
1955 r
= netlink_message_read_in_addr_union(message
, RTA_SRC
, tmp
->family
, &tmp
->src
);
1956 if (r
< 0 && r
!= -ENODATA
) {
1957 log_link_warning_errno(link
, r
, "rtnl: received route message without valid source, ignoring: %m");
1961 r
= netlink_message_read_in_addr_union(message
, RTA_PREFSRC
, tmp
->family
, &tmp
->prefsrc
);
1962 if (r
< 0 && r
!= -ENODATA
) {
1963 log_link_warning_errno(link
, r
, "rtnl: received route message without valid preferred source, ignoring: %m");
1967 r
= sd_rtnl_message_route_get_dst_prefixlen(message
, &tmp
->dst_prefixlen
);
1969 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1973 r
= sd_rtnl_message_route_get_src_prefixlen(message
, &tmp
->src_prefixlen
);
1975 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1979 r
= sd_rtnl_message_route_get_scope(message
, &tmp
->scope
);
1981 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid scope, ignoring: %m");
1985 r
= sd_rtnl_message_route_get_tos(message
, &tmp
->tos
);
1987 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid tos, ignoring: %m");
1991 r
= sd_rtnl_message_route_get_type(message
, &tmp
->type
);
1993 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid type, ignoring: %m");
1997 r
= sd_rtnl_message_route_get_table(message
, &table
);
1999 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid table, ignoring: %m");
2004 r
= sd_netlink_message_read_u32(message
, RTA_PRIORITY
, &tmp
->priority
);
2005 if (r
< 0 && r
!= -ENODATA
) {
2006 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid priority, ignoring: %m");
2010 r
= sd_netlink_message_read_u32(message
, RTA_NH_ID
, &tmp
->nexthop_id
);
2011 if (r
< 0 && r
!= -ENODATA
) {
2012 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid nexthop id, ignoring: %m");
2016 r
= sd_netlink_message_enter_container(message
, RTA_METRICS
);
2017 if (r
< 0 && r
!= -ENODATA
) {
2018 log_link_error_errno(link
, r
, "rtnl: Could not enter RTA_METRICS container: %m");
2022 r
= sd_netlink_message_read_u32(message
, RTAX_INITCWND
, &tmp
->initcwnd
);
2023 if (r
< 0 && r
!= -ENODATA
) {
2024 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initcwnd, ignoring: %m");
2028 r
= sd_netlink_message_read_u32(message
, RTAX_INITRWND
, &tmp
->initrwnd
);
2029 if (r
< 0 && r
!= -ENODATA
) {
2030 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid initrwnd, ignoring: %m");
2034 r
= sd_netlink_message_read_u32(message
, RTAX_ADVMSS
, &tmp
->advmss
);
2035 if (r
< 0 && r
!= -ENODATA
) {
2036 log_link_warning_errno(link
, r
, "rtnl: received route message with invalid advmss, ignoring: %m");
2040 r
= sd_netlink_message_exit_container(message
);
2042 log_link_error_errno(link
, r
, "rtnl: Could not exit from RTA_METRICS container: %m");
2047 r
= sd_netlink_message_read_data(message
, RTA_MULTIPATH
, &rta_len
, &rta_multipath
);
2048 if (r
< 0 && r
!= -ENODATA
) {
2049 log_link_warning_errno(link
, r
, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
2051 } else if (r
>= 0) {
2052 r
= rtattr_read_nexthop(rta_multipath
, rta_len
, tmp
->family
, &multipath_routes
);
2054 log_link_warning_errno(link
, r
, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
2059 /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
2060 * fib6_nh_init() in net/ipv6/route.c. However, we'd like to manage them by Manager. Hence, set
2061 * link to NULL here. */
2062 if (route_type_is_reject(tmp
))
2065 if (ordered_set_isempty(multipath_routes
))
2066 (void) process_route_one(m
, link
, type
, tmp
, NULL
);
2070 ORDERED_SET_FOREACH(mr
, multipath_routes
) {
2071 r
= process_route_one(m
, link
, type
, tmp
, mr
);
2080 int network_add_ipv4ll_route(Network
*network
) {
2081 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2082 unsigned section_line
;
2087 if (!network
->ipv4ll_route
)
2090 section_line
= hashmap_find_free_section_line(network
->routes_by_section
);
2092 /* IPv4LLRoute= is in [Network] section. */
2093 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
2097 r
= in_addr_from_string(AF_INET
, "169.254.0.0", &n
->dst
);
2101 n
->family
= AF_INET
;
2102 n
->dst_prefixlen
= 16;
2103 n
->scope
= RT_SCOPE_LINK
;
2104 n
->scope_set
= true;
2105 n
->table_set
= true;
2106 n
->priority
= IPV4LL_ROUTE_METRIC
;
2107 n
->protocol
= RTPROT_STATIC
;
2113 int network_add_default_route_on_device(Network
*network
) {
2114 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2115 unsigned section_line
;
2120 if (!network
->default_route_on_device
)
2123 section_line
= hashmap_find_free_section_line(network
->routes_by_section
);
2125 /* DefaultRouteOnDevice= is in [Network] section. */
2126 r
= route_new_static(network
, network
->filename
, section_line
, &n
);
2130 n
->family
= AF_INET
;
2131 n
->scope
= RT_SCOPE_LINK
;
2132 n
->scope_set
= true;
2133 n
->protocol
= RTPROT_STATIC
;
2139 int config_parse_gateway(
2141 const char *filename
,
2143 const char *section
,
2144 unsigned section_line
,
2151 Network
*network
= userdata
;
2152 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2161 if (streq(section
, "Network")) {
2162 /* we are not in an Route section, so use line number instead */
2163 r
= route_new_static(network
, filename
, line
, &n
);
2167 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2168 "Failed to allocate route, ignoring assignment: %m");
2172 r
= route_new_static(network
, filename
, section_line
, &n
);
2176 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2177 "Failed to allocate route, ignoring assignment: %m");
2181 if (isempty(rvalue
)) {
2182 n
->gateway_from_dhcp_or_ra
= false;
2183 n
->gw_family
= AF_UNSPEC
;
2184 n
->gw
= IN_ADDR_NULL
;
2189 if (streq(rvalue
, "_dhcp")) {
2190 n
->gateway_from_dhcp_or_ra
= true;
2195 if (streq(rvalue
, "_dhcp4")) {
2196 n
->gw_family
= AF_INET
;
2197 n
->gateway_from_dhcp_or_ra
= true;
2202 if (streq(rvalue
, "_ipv6ra")) {
2203 n
->gw_family
= AF_INET6
;
2204 n
->gateway_from_dhcp_or_ra
= true;
2210 r
= in_addr_from_string_auto(rvalue
, &n
->gw_family
, &n
->gw
);
2212 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2213 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2217 n
->gateway_from_dhcp_or_ra
= false;
2222 int config_parse_preferred_src(
2224 const char *filename
,
2226 const char *section
,
2227 unsigned section_line
,
2234 Network
*network
= userdata
;
2235 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2244 r
= route_new_static(network
, filename
, section_line
, &n
);
2248 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2249 "Failed to allocate route, ignoring assignment: %m");
2253 if (n
->family
== AF_UNSPEC
)
2254 r
= in_addr_from_string_auto(rvalue
, &n
->family
, &n
->prefsrc
);
2256 r
= in_addr_from_string(n
->family
, rvalue
, &n
->prefsrc
);
2258 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2259 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2267 int config_parse_destination(
2269 const char *filename
,
2271 const char *section
,
2272 unsigned section_line
,
2279 Network
*network
= userdata
;
2280 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2281 union in_addr_union
*buffer
;
2282 unsigned char *prefixlen
;
2291 r
= route_new_static(network
, filename
, section_line
, &n
);
2295 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2296 "Failed to allocate route, ignoring assignment: %m");
2300 if (streq(lvalue
, "Destination")) {
2302 prefixlen
= &n
->dst_prefixlen
;
2303 } else if (streq(lvalue
, "Source")) {
2305 prefixlen
= &n
->src_prefixlen
;
2307 assert_not_reached(lvalue
);
2309 if (n
->family
== AF_UNSPEC
)
2310 r
= in_addr_prefix_from_string_auto(rvalue
, &n
->family
, buffer
, prefixlen
);
2312 r
= in_addr_prefix_from_string(rvalue
, n
->family
, buffer
, prefixlen
);
2314 log_syntax(unit
, LOG_WARNING
, filename
, line
, EINVAL
,
2315 "Invalid %s='%s', ignoring assignment: %m", lvalue
, rvalue
);
2323 int config_parse_route_priority(
2325 const char *filename
,
2327 const char *section
,
2328 unsigned section_line
,
2335 Network
*network
= userdata
;
2336 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2345 r
= route_new_static(network
, filename
, section_line
, &n
);
2349 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2350 "Failed to allocate route, ignoring assignment: %m");
2354 r
= safe_atou32(rvalue
, &n
->priority
);
2356 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2357 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue
);
2361 n
->priority_set
= true;
2366 int config_parse_route_scope(
2368 const char *filename
,
2370 const char *section
,
2371 unsigned section_line
,
2378 Network
*network
= userdata
;
2379 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2388 r
= route_new_static(network
, filename
, section_line
, &n
);
2392 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2393 "Failed to allocate route, ignoring assignment: %m");
2397 r
= route_scope_from_string(rvalue
);
2399 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Unknown route scope: %s", rvalue
);
2404 n
->scope_set
= true;
2409 int config_parse_route_nexthop(
2411 const char *filename
,
2413 const char *section
,
2414 unsigned section_line
,
2421 Network
*network
= userdata
;
2422 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2432 r
= route_new_static(network
, filename
, section_line
, &n
);
2436 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2437 "Failed to allocate route, ignoring assignment: %m");
2441 if (isempty(rvalue
)) {
2447 r
= safe_atou32(rvalue
, &id
);
2449 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue
);
2453 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue
);
2462 int config_parse_route_table(
2464 const char *filename
,
2466 const char *section
,
2467 unsigned section_line
,
2474 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2475 Network
*network
= userdata
;
2484 r
= route_new_static(network
, filename
, section_line
, &n
);
2488 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2489 "Failed to allocate route, ignoring assignment: %m");
2493 r
= manager_get_route_table_from_string(network
->manager
, rvalue
, &n
->table
);
2495 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2496 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue
);
2500 n
->table_set
= true;
2505 int config_parse_route_boolean(
2507 const char *filename
,
2509 const char *section
,
2510 unsigned section_line
,
2517 Network
*network
= userdata
;
2518 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2527 r
= route_new_static(network
, filename
, section_line
, &n
);
2531 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2532 "Failed to allocate route, ignoring assignment: %m");
2536 r
= parse_boolean(rvalue
);
2538 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2539 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2543 if (STR_IN_SET(lvalue
, "GatewayOnLink", "GatewayOnlink"))
2544 n
->gateway_onlink
= r
;
2545 else if (streq(lvalue
, "QuickAck"))
2547 else if (streq(lvalue
, "FastOpenNoCookie"))
2548 n
->fast_open_no_cookie
= r
;
2549 else if (streq(lvalue
, "TTLPropagate"))
2550 n
->ttl_propagate
= r
;
2552 assert_not_reached("Invalid lvalue");
2558 int config_parse_ipv6_route_preference(
2560 const char *filename
,
2562 const char *section
,
2563 unsigned section_line
,
2570 Network
*network
= userdata
;
2571 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2574 r
= route_new_static(network
, filename
, section_line
, &n
);
2578 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2579 "Failed to allocate route, ignoring assignment: %m");
2583 if (streq(rvalue
, "low"))
2584 n
->pref
= ICMPV6_ROUTER_PREF_LOW
;
2585 else if (streq(rvalue
, "medium"))
2586 n
->pref
= ICMPV6_ROUTER_PREF_MEDIUM
;
2587 else if (streq(rvalue
, "high"))
2588 n
->pref
= ICMPV6_ROUTER_PREF_HIGH
;
2590 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Unknown route preference: %s", rvalue
);
2599 int config_parse_route_protocol(
2601 const char *filename
,
2603 const char *section
,
2604 unsigned section_line
,
2611 Network
*network
= userdata
;
2612 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2615 r
= route_new_static(network
, filename
, section_line
, &n
);
2619 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2620 "Failed to allocate route, ignoring assignment: %m");
2624 r
= route_protocol_from_string(rvalue
);
2626 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2627 "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue
);
2637 int config_parse_route_type(
2639 const char *filename
,
2641 const char *section
,
2642 unsigned section_line
,
2649 Network
*network
= userdata
;
2650 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2653 r
= route_new_static(network
, filename
, section_line
, &n
);
2657 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2658 "Failed to allocate route, ignoring assignment: %m");
2662 t
= route_type_from_string(rvalue
);
2664 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2665 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue
);
2669 n
->type
= (unsigned char) t
;
2675 int config_parse_tcp_advmss(
2677 const char *filename
,
2679 const char *section
,
2680 unsigned section_line
,
2687 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2688 Network
*network
= userdata
;
2698 r
= route_new_static(network
, filename
, section_line
, &n
);
2702 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2703 "Failed to allocate route, ignoring assignment: %m");
2707 if (isempty(rvalue
)) {
2713 r
= parse_size(rvalue
, 1024, &u
);
2715 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2716 "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2720 if (u
== 0 || u
> UINT32_MAX
) {
2721 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2722 "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue
);
2732 int config_parse_tcp_window(
2734 const char *filename
,
2736 const char *section
,
2737 unsigned section_line
,
2744 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2745 Network
*network
= userdata
;
2755 r
= route_new_static(network
, filename
, section_line
, &n
);
2759 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2760 "Failed to allocate route, ignoring assignment: %m");
2764 r
= safe_atou32(rvalue
, &k
);
2766 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2767 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2771 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2772 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue
, rvalue
);
2776 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2777 "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue
, rvalue
);
2781 if (streq(lvalue
, "InitialCongestionWindow"))
2783 else if (streq(lvalue
, "InitialAdvertisedReceiveWindow"))
2786 assert_not_reached("Invalid TCP window type.");
2792 int config_parse_route_mtu(
2794 const char *filename
,
2796 const char *section
,
2797 unsigned section_line
,
2804 Network
*network
= userdata
;
2805 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2814 r
= route_new_static(network
, filename
, section_line
, &n
);
2818 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2819 "Failed to allocate route, ignoring assignment: %m");
2823 r
= config_parse_mtu(unit
, filename
, line
, section
, section_line
, lvalue
, ltype
, rvalue
, &n
->mtu
, userdata
);
2831 int config_parse_multipath_route(
2833 const char *filename
,
2835 const char *section
,
2836 unsigned section_line
,
2843 _cleanup_(multipath_route_freep
) MultipathRoute
*m
= NULL
;
2844 _cleanup_(route_free_or_set_invalidp
) Route
*n
= NULL
;
2845 _cleanup_free_
char *word
= NULL
;
2846 Network
*network
= userdata
;
2847 union in_addr_union a
;
2858 r
= route_new_static(network
, filename
, section_line
, &n
);
2862 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2863 "Failed to allocate route, ignoring assignment: %m");
2867 if (isempty(rvalue
)) {
2868 n
->multipath_routes
= ordered_set_free_with_destructor(n
->multipath_routes
, multipath_route_free
);
2872 m
= new0(MultipathRoute
, 1);
2877 r
= extract_first_word(&p
, &word
, NULL
, 0);
2881 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2882 "Invalid multipath route option, ignoring assignment: %s", rvalue
);
2886 dev
= strchr(word
, '@');
2890 r
= parse_ifindex(dev
);
2894 if (!ifname_valid_full(dev
, IFNAME_VALID_ALTERNATIVE
)) {
2895 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2896 "Invalid interface name '%s' in %s=, ignoring: %s", dev
, lvalue
, rvalue
);
2900 m
->ifname
= strdup(dev
);
2906 r
= in_addr_from_string_auto(word
, &family
, &a
);
2908 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2909 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue
);
2912 m
->gateway
.address
= a
;
2913 m
->gateway
.family
= family
;
2916 r
= safe_atou32(p
, &m
->weight
);
2918 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2919 "Invalid multipath route weight, ignoring assignment: %s", p
);
2922 /* ip command takes weight in the range 1…255, while kernel takes the value in the
2923 * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip
2924 * command uses, then networkd decreases by one and stores it to match the range which
2926 if (m
->weight
== 0 || m
->weight
> 256) {
2927 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2928 "Invalid multipath route weight, ignoring assignment: %s", p
);
2934 r
= ordered_set_ensure_put(&n
->multipath_routes
, NULL
, m
);
2938 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2939 "Failed to store multipath route, ignoring assignment: %m");
2948 int config_parse_route_table_names(
2950 const char *filename
,
2952 const char *section
,
2953 unsigned section_line
,
2960 Manager
*m
= userdata
;
2968 if (isempty(rvalue
)) {
2969 m
->route_table_names_by_number
= hashmap_free(m
->route_table_names_by_number
);
2970 m
->route_table_numbers_by_name
= hashmap_free(m
->route_table_numbers_by_name
);
2974 for (const char *p
= rvalue
;;) {
2975 _cleanup_free_
char *name
= NULL
;
2979 r
= extract_first_word(&p
, &name
, NULL
, 0);
2983 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
2984 "Invalid RouteTable=, ignoring assignment: %s", rvalue
);
2990 num
= strchr(name
, ':');
2992 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
2993 "Invalid route table name and number pair, ignoring assignment: %s", name
);
2999 if (STR_IN_SET(name
, "default", "main", "local")) {
3000 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
3001 "Route table name %s already predefined. Ignoring assignment: %s:%s", name
, name
, num
);
3005 r
= safe_atou32(num
, &table
);
3007 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3008 "Failed to parse route table number '%s', ignoring assignment: %s:%s", num
, name
, num
);
3012 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
3013 "Invalid route table number, ignoring assignment: %s:%s", name
, num
);
3017 r
= hashmap_ensure_put(&m
->route_table_numbers_by_name
, &string_hash_ops_free
, name
, UINT32_TO_PTR(table
));
3021 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3022 "Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name
, num
);
3026 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3027 "Failed to store route table name and number pair, ignoring assignment: %s:%s", name
, num
);
3031 /* The entry is duplicated. It should not be added to route_table_names_by_number hashmap. */
3034 r
= hashmap_ensure_put(&m
->route_table_names_by_number
, NULL
, UINT32_TO_PTR(table
), name
);
3036 hashmap_remove(m
->route_table_numbers_by_name
, name
);
3041 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3042 "Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name
, num
);
3044 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
3045 "Failed to store route table name and number pair, ignoring assignment: %s:%s", name
, num
);
3054 static int route_section_verify(Route
*route
, Network
*network
) {
3055 if (section_is_invalid(route
->section
))
3058 if (route
->gateway_from_dhcp_or_ra
) {
3059 if (route
->gw_family
== AF_UNSPEC
) {
3060 /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
3061 switch (route
->family
) {
3063 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3064 "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
3065 route
->section
->filename
, route
->section
->line
);
3066 route
->family
= AF_INET
;
3070 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3071 "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
3072 route
->section
->filename
, route
->section
->line
, route
->family
== AF_INET
? "_dhcp4" : "_ipv6ra");
3075 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3076 "%s: Invalid route family. Ignoring [Route] section from line %u.",
3077 route
->section
->filename
, route
->section
->line
);
3079 route
->gw_family
= route
->family
;
3082 if (route
->gw_family
== AF_INET
&& !FLAGS_SET(network
->dhcp
, ADDRESS_FAMILY_IPV4
))
3083 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3084 "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
3085 "Ignoring [Route] section from line %u.",
3086 route
->section
->filename
, route
->section
->line
);
3088 if (route
->gw_family
== AF_INET6
&& !network
->ipv6_accept_ra
)
3089 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3090 "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
3091 "Ignoring [Route] section from line %u.",
3092 route
->section
->filename
, route
->section
->line
);
3095 /* When only Gateway= is specified, assume the route family based on the Gateway address. */
3096 if (route
->family
== AF_UNSPEC
)
3097 route
->family
= route
->gw_family
;
3099 if (route
->family
== AF_UNSPEC
) {
3100 assert(route
->section
);
3102 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3103 "%s: Route section without Gateway=, Destination=, Source=, "
3104 "or PreferredSource= field configured. "
3105 "Ignoring [Route] section from line %u.",
3106 route
->section
->filename
, route
->section
->line
);
3109 if (route
->family
== AF_INET6
&& route
->gw_family
== AF_INET
)
3110 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3111 "%s: IPv4 gateway is configured for IPv6 route. "
3112 "Ignoring [Route] section from line %u.",
3113 route
->section
->filename
, route
->section
->line
);
3115 if (!route
->table_set
&& network
->vrf
) {
3116 route
->table
= VRF(network
->vrf
)->table
;
3117 route
->table_set
= true;
3120 if (!route
->table_set
&& IN_SET(route
->type
, RTN_LOCAL
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_NAT
))
3121 route
->table
= RT_TABLE_LOCAL
;
3123 if (!route
->scope_set
&& route
->family
!= AF_INET6
) {
3124 if (IN_SET(route
->type
, RTN_LOCAL
, RTN_NAT
))
3125 route
->scope
= RT_SCOPE_HOST
;
3126 else if (IN_SET(route
->type
, RTN_BROADCAST
, RTN_ANYCAST
, RTN_MULTICAST
))
3127 route
->scope
= RT_SCOPE_LINK
;
3130 if (route
->scope
!= RT_SCOPE_UNIVERSE
&& route
->family
== AF_INET6
) {
3131 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route
->section
->filename
);
3132 route
->scope
= RT_SCOPE_UNIVERSE
;
3135 if (route
->family
== AF_INET6
&& route
->priority
== 0)
3136 route
->priority
= IP6_RT_PRIO_USER
;
3138 if (route
->gateway_onlink
< 0 && in_addr_is_set(route
->gw_family
, &route
->gw
) &&
3139 ordered_hashmap_isempty(network
->addresses_by_section
)) {
3140 /* If no address is configured, in most cases the gateway cannot be reachable.
3141 * TODO: we may need to improve the condition above. */
3142 log_warning("%s: Gateway= without static address configured. "
3143 "Enabling GatewayOnLink= option.",
3145 route
->gateway_onlink
= true;
3148 if (route
->family
== AF_INET6
) {
3151 ORDERED_SET_FOREACH(m
, route
->multipath_routes
)
3152 if (m
->gateway
.family
== AF_INET
)
3153 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3154 "%s: IPv4 multipath route is specified for IPv6 route. "
3155 "Ignoring [Route] section from line %u.",
3156 route
->section
->filename
, route
->section
->line
);
3159 if ((route
->gateway_from_dhcp_or_ra
||
3160 in_addr_is_set(route
->gw_family
, &route
->gw
)) &&
3161 !ordered_set_isempty(route
->multipath_routes
))
3162 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3163 "%s: Gateway= cannot be specified with MultiPathRoute=. "
3164 "Ignoring [Route] section from line %u.",
3165 route
->section
->filename
, route
->section
->line
);
3167 if (route
->nexthop_id
> 0 &&
3168 (route
->gateway_from_dhcp_or_ra
||
3169 in_addr_is_set(route
->gw_family
, &route
->gw
) ||
3170 !ordered_set_isempty(route
->multipath_routes
)))
3171 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
3172 "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
3173 "Ignoring [Route] section from line %u.",
3174 route
->section
->filename
, route
->section
->line
);
3179 void network_drop_invalid_routes(Network
*network
) {
3184 HASHMAP_FOREACH(route
, network
->routes_by_section
)
3185 if (route_section_verify(route
, network
) < 0)