]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-route.c
basic: import linux/ipv6_route.h
[thirdparty/systemd.git] / src / network / networkd-route.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
f579559b 2
b5bf6f64
SS
3#include <linux/icmpv6.h>
4
b5efdb8a 5#include "alloc-util.h"
fc2f9534 6#include "netlink-util.h"
ca5ad760 7#include "networkd-ipv4ll.h"
23f53b99 8#include "networkd-manager.h"
e2263711 9#include "networkd-network.h"
141318f7 10#include "networkd-nexthop.h"
6bedfcbb 11#include "networkd-route.h"
141318f7 12#include "networkd-routing-policy-rule.h"
6bedfcbb 13#include "parse-util.h"
d308bb99 14#include "socket-netlink.h"
7a22312d 15#include "string-table.h"
07630cea 16#include "string-util.h"
d96edb2c 17#include "strv.h"
b297e0a7 18#include "strxcpyx.h"
47d2d30d 19#include "sysctl-util.h"
c0d48bc5 20#include "vrf.h"
f579559b 21
47d2d30d
ZJS
22#define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
23
ac49887e
YW
24static uint32_t link_get_vrf_table(Link *link) {
25 return link->network->vrf ? VRF(link->network->vrf)->table : RT_TABLE_MAIN;
26}
27
28uint32_t link_get_dhcp_route_table(Link *link) {
29 /* When the interface is part of an VRF use the VRFs routing table, unless
30 * another table is explicitly specified. */
31 if (link->network->dhcp_route_table_set)
32 return link->network->dhcp_route_table;
33 return link_get_vrf_table(link);
34}
35
36uint32_t link_get_ipv6_accept_ra_route_table(Link *link) {
37 if (link->network->ipv6_accept_ra_route_table_set)
38 return link->network->ipv6_accept_ra_route_table;
39 return link_get_vrf_table(link);
40}
41
74154c2e
YW
42static const char * const route_type_table[__RTN_MAX] = {
43 [RTN_UNICAST] = "unicast",
44 [RTN_LOCAL] = "local",
45 [RTN_BROADCAST] = "broadcast",
46 [RTN_ANYCAST] = "anycast",
47 [RTN_MULTICAST] = "multicast",
48 [RTN_BLACKHOLE] = "blackhole",
49 [RTN_UNREACHABLE] = "unreachable",
50 [RTN_PROHIBIT] = "prohibit",
51 [RTN_THROW] = "throw",
52 [RTN_NAT] = "nat",
53 [RTN_XRESOLVE] = "xresolve",
54};
55
56assert_cc(__RTN_MAX <= UCHAR_MAX);
57DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_type, int);
58
59static const char * const route_scope_table[] = {
60 [RT_SCOPE_UNIVERSE] = "global",
61 [RT_SCOPE_SITE] = "site",
62 [RT_SCOPE_LINK] = "link",
63 [RT_SCOPE_HOST] = "host",
64 [RT_SCOPE_NOWHERE] = "nowhere",
65};
66
67DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int);
68
69#define ROUTE_SCOPE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("nowhere") + 1)
70static const char *format_route_scope(int scope, char *buf, size_t size) {
71 const char *s;
72 char *p = buf;
73
74 s = route_scope_to_string(scope);
75 if (s)
76 strpcpy(&p, size, s);
77 else
78 strpcpyf(&p, size, "%d", scope);
79
80 return buf;
81}
82
83static const char * const route_table_table[] = {
84 [RT_TABLE_DEFAULT] = "default",
85 [RT_TABLE_MAIN] = "main",
86 [RT_TABLE_LOCAL] = "local",
87};
88
89DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
90
91#define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1)
92static const char *format_route_table(int table, char *buf, size_t size) {
93 const char *s;
94 char *p = buf;
95
96 s = route_table_to_string(table);
97 if (s)
98 strpcpy(&p, size, s);
99 else
100 strpcpyf(&p, size, "%d", table);
101
102 return buf;
103}
104
105static const char * const route_protocol_table[] = {
106 [RTPROT_KERNEL] = "kernel",
107 [RTPROT_BOOT] = "boot",
108 [RTPROT_STATIC] = "static",
109};
110
111DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int);
112
113static const char * const route_protocol_full_table[] = {
114 [RTPROT_REDIRECT] = "redirect",
115 [RTPROT_KERNEL] = "kernel",
116 [RTPROT_BOOT] = "boot",
117 [RTPROT_STATIC] = "static",
118 [RTPROT_GATED] = "gated",
119 [RTPROT_RA] = "ra",
120 [RTPROT_MRT] = "mrt",
121 [RTPROT_ZEBRA] = "zebra",
122 [RTPROT_BIRD] = "bird",
123 [RTPROT_DNROUTED] = "dnrouted",
124 [RTPROT_XORP] = "xorp",
125 [RTPROT_NTK] = "ntk",
126 [RTPROT_DHCP] = "dhcp",
127 [RTPROT_MROUTED] = "mrouted",
128 [RTPROT_BABEL] = "babel",
129 [RTPROT_BGP] = "bgp",
130 [RTPROT_ISIS] = "isis",
131 [RTPROT_OSPF] = "ospf",
132 [RTPROT_RIP] = "rip",
133 [RTPROT_EIGRP] = "eigrp",
134};
135
136DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int);
137
138#define ROUTE_PROTOCOL_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("redirect") + 1)
139static const char *format_route_protocol(int protocol, char *buf, size_t size) {
140 const char *s;
141 char *p = buf;
142
143 s = route_protocol_full_to_string(protocol);
144 if (s)
145 strpcpy(&p, size, s);
146 else
147 strpcpyf(&p, size, "%d", protocol);
148
149 return buf;
150}
151
47d2d30d
ZJS
152static unsigned routes_max(void) {
153 static thread_local unsigned cached = 0;
154
155 _cleanup_free_ char *s4 = NULL, *s6 = NULL;
156 unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
157
158 if (cached > 0)
159 return cached;
160
161 if (sysctl_read("net/ipv4/route/max_size", &s4) >= 0) {
162 truncate_nl(s4);
163 if (safe_atou(s4, &val4) >= 0 &&
164 val4 == 2147483647U)
165 /* This is the default "no limit" value in the kernel */
166 val4 = ROUTES_DEFAULT_MAX_PER_FAMILY;
167 }
168
169 if (sysctl_read("net/ipv6/route/max_size", &s6) >= 0) {
170 truncate_nl(s6);
171 (void) safe_atou(s6, &val6);
172 }
173
174 cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) +
175 MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6);
176 return cached;
177}
8c34b963 178
ed9e361a 179int route_new(Route **ret) {
8e766630 180 _cleanup_(route_freep) Route *route = NULL;
f0213e37 181
17f9c355 182 route = new(Route, 1);
f0213e37
TG
183 if (!route)
184 return -ENOMEM;
185
17f9c355
YW
186 *route = (Route) {
187 .family = AF_UNSPEC,
188 .scope = RT_SCOPE_UNIVERSE,
189 .protocol = RTPROT_UNSPEC,
190 .type = RTN_UNICAST,
191 .table = RT_TABLE_MAIN,
192 .lifetime = USEC_INFINITY,
193 .quickack = -1,
633c7258 194 .fast_open_no_cookie = -1,
54901fd2 195 .gateway_onlink = -1,
9b88f20a 196 .ttl_propagate = -1,
17f9c355 197 };
f0213e37 198
1cc6c93a 199 *ret = TAKE_PTR(route);
f0213e37
TG
200
201 return 0;
202}
203
9560e5b3 204static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
8e766630
LP
205 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
206 _cleanup_(route_freep) Route *route = NULL;
f0213e37 207 int r;
f579559b 208
8c34b963
LP
209 assert(network);
210 assert(ret);
2a54a044
YW
211 assert(filename);
212 assert(section_line > 0);
f4859fc7 213
2a54a044
YW
214 r = network_config_section_new(filename, section_line, &n);
215 if (r < 0)
216 return r;
6ae115c1 217
2a54a044
YW
218 route = hashmap_get(network->routes_by_section, n);
219 if (route) {
220 *ret = TAKE_PTR(route);
221 return 0;
6ae115c1
TG
222 }
223
2a54a044 224 if (hashmap_size(network->routes_by_section) >= routes_max())
8c34b963
LP
225 return -E2BIG;
226
ed9e361a 227 r = route_new(&route);
f0213e37
TG
228 if (r < 0)
229 return r;
801bd9e8 230
ed9e361a 231 route->protocol = RTPROT_STATIC;
0f7f2769 232 route->network = network;
2a54a044 233 route->section = TAKE_PTR(n);
cacc1dbf 234
2a54a044
YW
235 r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops);
236 if (r < 0)
237 return r;
3e570042 238
2a54a044
YW
239 r = hashmap_put(network->routes_by_section, route->section, route);
240 if (r < 0)
241 return r;
6ae115c1 242
1cc6c93a 243 *ret = TAKE_PTR(route);
f579559b
TG
244 return 0;
245}
246
169948e9 247Route *route_free(Route *route) {
f579559b 248 if (!route)
169948e9 249 return NULL;
f579559b 250
f048a16b 251 if (route->network) {
2a54a044
YW
252 assert(route->section);
253 hashmap_remove(route->network->routes_by_section, route->section);
f048a16b 254 }
6ae115c1 255
fd45e522
ZJS
256 network_config_section_free(route->section);
257
1c8e710c 258 if (route->link) {
50550722 259 NDiscRoute *n;
50550722 260
1c8e710c
TG
261 set_remove(route->link->routes, route);
262 set_remove(route->link->routes_foreign, route);
6e537f62
YW
263 set_remove(route->link->dhcp_routes, route);
264 set_remove(route->link->dhcp_routes_old, route);
1633c457
YW
265 set_remove(route->link->dhcp6_routes, route);
266 set_remove(route->link->dhcp6_routes_old, route);
267 set_remove(route->link->dhcp6_pd_routes, route);
268 set_remove(route->link->dhcp6_pd_routes_old, route);
90e74a66 269 SET_FOREACH(n, route->link->ndisc_routes)
50550722
YW
270 if (n->route == route)
271 free(set_remove(route->link->ndisc_routes, n));
1c8e710c
TG
272 }
273
6ff5cc6b
YW
274 ordered_set_free_free(route->multipath_routes);
275
f833694d
TG
276 sd_event_source_unref(route->expire);
277
169948e9 278 return mfree(route);
f579559b
TG
279}
280
501b09db 281void route_hash_func(const Route *route, struct siphash *state) {
bb7ae737
TG
282 assert(route);
283
284 siphash24_compress(&route->family, sizeof(route->family), state);
285
01aaa3df
YW
286 switch (route->family) {
287 case AF_INET:
288 case AF_INET6:
01aaa3df 289 siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
67e05dd8
ZJS
290 siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
291
01aaa3df 292 siphash24_compress(&route->src_prefixlen, sizeof(route->src_prefixlen), state);
67e05dd8
ZJS
293 siphash24_compress(&route->src, FAMILY_ADDRESS_SIZE(route->family), state);
294
295 siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->family), state);
296
01aaa3df
YW
297 siphash24_compress(&route->prefsrc, FAMILY_ADDRESS_SIZE(route->family), state);
298
299 siphash24_compress(&route->tos, sizeof(route->tos), state);
300 siphash24_compress(&route->priority, sizeof(route->priority), state);
301 siphash24_compress(&route->table, sizeof(route->table), state);
302 siphash24_compress(&route->protocol, sizeof(route->protocol), state);
303 siphash24_compress(&route->scope, sizeof(route->scope), state);
304 siphash24_compress(&route->type, sizeof(route->type), state);
67e05dd8 305
fa3e401a
YW
306 siphash24_compress(&route->initcwnd, sizeof(route->initcwnd), state);
307 siphash24_compress(&route->initrwnd, sizeof(route->initrwnd), state);
01aaa3df
YW
308
309 break;
310 default:
311 /* treat any other address family as AF_UNSPEC */
312 break;
313 }
314}
315
501b09db 316int route_compare_func(const Route *a, const Route *b) {
01aaa3df
YW
317 int r;
318
319 r = CMP(a->family, b->family);
320 if (r != 0)
321 return r;
322
323 switch (a->family) {
324 case AF_INET:
325 case AF_INET6:
326 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
327 if (r != 0)
328 return r;
329
67e05dd8
ZJS
330 r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
331 if (r != 0)
332 return r;
333
01aaa3df
YW
334 r = CMP(a->src_prefixlen, b->src_prefixlen);
335 if (r != 0)
336 return r;
337
67e05dd8 338 r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
01aaa3df
YW
339 if (r != 0)
340 return r;
341
67e05dd8 342 r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
01aaa3df
YW
343 if (r != 0)
344 return r;
345
67e05dd8 346 r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
01aaa3df
YW
347 if (r != 0)
348 return r;
349
67e05dd8 350 r = CMP(a->tos, b->tos);
01aaa3df
YW
351 if (r != 0)
352 return r;
353
67e05dd8 354 r = CMP(a->priority, b->priority);
01aaa3df
YW
355 if (r != 0)
356 return r;
357
67e05dd8 358 r = CMP(a->table, b->table);
01aaa3df
YW
359 if (r != 0)
360 return r;
361
67e05dd8 362 r = CMP(a->protocol, b->protocol);
fa3e401a
YW
363 if (r != 0)
364 return r;
365
67e05dd8 366 r = CMP(a->scope, b->scope);
fa3e401a
YW
367 if (r != 0)
368 return r;
369
67e05dd8 370 r = CMP(a->type, b->type);
01aaa3df
YW
371 if (r != 0)
372 return r;
373
67e05dd8 374 r = CMP(a->initcwnd, b->initcwnd);
01aaa3df
YW
375 if (r != 0)
376 return r;
377
67e05dd8 378 r = CMP(a->initrwnd, b->initrwnd);
01aaa3df
YW
379 if (r != 0)
380 return r;
381
67e05dd8 382 return 0;
01aaa3df
YW
383 default:
384 /* treat any other address family as AF_UNSPEC */
385 return 0;
386 }
387}
388
389DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
c077a205 390 route_hash_ops,
01aaa3df 391 Route,
c077a205
YW
392 route_hash_func,
393 route_compare_func,
01aaa3df
YW
394 route_free);
395
74154c2e 396static bool route_equal(Route *r1, Route *r2) {
7ecf0c3e
TJ
397 if (r1 == r2)
398 return true;
399
400 if (!r1 || !r2)
401 return false;
402
403 return route_compare_func(r1, r2) == 0;
404}
405
74154c2e 406static int route_get(Link *link, Route *in, Route **ret) {
f1368755
YW
407
408 Route *existing;
1b566071
LP
409
410 assert(link);
f1368755 411 assert(in);
1c8e710c 412
f1368755 413 existing = set_get(link->routes, in);
1c8e710c 414 if (existing) {
1b566071
LP
415 if (ret)
416 *ret = existing;
1c8e710c 417 return 1;
1c8e710c
TG
418 }
419
f1368755 420 existing = set_get(link->routes_foreign, in);
1b566071
LP
421 if (existing) {
422 if (ret)
423 *ret = existing;
424 return 0;
425 }
1c8e710c 426
1b566071 427 return -ENOENT;
1c8e710c
TG
428}
429
f1368755 430static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret) {
889b550f 431
8e766630 432 _cleanup_(route_freep) Route *route = NULL;
1c8e710c
TG
433 int r;
434
435 assert(link);
436 assert(routes);
f1368755 437 assert(in);
1c8e710c
TG
438
439 r = route_new(&route);
440 if (r < 0)
441 return r;
442
f1368755
YW
443 route->family = in->family;
444 route->src = in->src;
445 route->src_prefixlen = in->src_prefixlen;
446 route->dst = in->dst;
447 route->dst_prefixlen = in->dst_prefixlen;
448 route->gw = in->gw;
449 route->prefsrc = in->prefsrc;
450 route->scope = in->scope;
451 route->protocol = in->protocol;
452 route->type = in->type;
453 route->tos = in->tos;
454 route->priority = in->priority;
455 route->table = in->table;
456 route->initcwnd = in->initcwnd;
457 route->initrwnd = in->initrwnd;
458 route->lifetime = in->lifetime;
1c8e710c 459
de7fef4b 460 r = set_ensure_put(routes, &route_hash_ops, route);
1c8e710c
TG
461 if (r < 0)
462 return r;
75a302b5
YW
463 if (r == 0)
464 return -EEXIST;
1c8e710c
TG
465
466 route->link = link;
467
468 if (ret)
469 *ret = route;
470
471 route = NULL;
472
473 return 0;
474}
475
74154c2e 476static int route_add_foreign(Link *link, Route *in, Route **ret) {
f1368755 477 return route_add_internal(link, &link->routes_foreign, in, ret);
1c8e710c
TG
478}
479
74154c2e 480static int route_add(Link *link, Route *in, Route **ret) {
889b550f 481
1c8e710c
TG
482 Route *route;
483 int r;
484
f1368755 485 r = route_get(link, in, &route);
1c8e710c
TG
486 if (r == -ENOENT) {
487 /* Route does not exist, create a new one */
f1368755 488 r = route_add_internal(link, &link->routes, in, &route);
1c8e710c
TG
489 if (r < 0)
490 return r;
491 } else if (r == 0) {
492 /* Take over a foreign route */
de7fef4b 493 r = set_ensure_put(&link->routes, &route_hash_ops, route);
1c8e710c
TG
494 if (r < 0)
495 return r;
496
497 set_remove(link->routes_foreign, route);
498 } else if (r == 1) {
499 /* Route exists, do nothing */
500 ;
501 } else
502 return r;
503
856e309d
MC
504 if (ret)
505 *ret = route;
1c8e710c
TG
506
507 return 0;
508}
509
302a796f 510static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
4645ad47
YW
511 int r;
512
513 assert(m);
514 assert(link);
515 assert(link->ifname);
516
517 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
518 return 1;
519
520 r = sd_netlink_message_get_errno(m);
521 if (r < 0 && r != -ESRCH)
5ecb131d 522 log_link_message_warning_errno(link, m, r, "Could not drop route, ignoring");
4645ad47
YW
523
524 return 1;
525}
526
91b5f997 527int route_remove(Route *route, Link *link,
302a796f 528 link_netlink_message_handler_t callback) {
27efb52b 529
4afd3348 530 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
5c1d3fc9
UTL
531 int r;
532
533 assert(link);
534 assert(link->manager);
535 assert(link->manager->rtnl);
536 assert(link->ifindex > 0);
4c701096 537 assert(IN_SET(route->family, AF_INET, AF_INET6));
5c1d3fc9
UTL
538
539 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
28cc555d
DW
540 RTM_DELROUTE, route->family,
541 route->protocol);
f647962d 542 if (r < 0)
7750b796 543 return log_link_error_errno(link, r, "Could not create RTM_DELROUTE message: %m");
5c1d3fc9 544
b297e0a7
YW
545 if (DEBUG_LOGGING) {
546 _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
d3e291fd 547 char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
b297e0a7
YW
548
549 if (!in_addr_is_null(route->family, &route->dst)) {
550 (void) in_addr_to_string(route->family, &route->dst, &dst);
551 (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen);
552 }
553 if (!in_addr_is_null(route->family, &route->src))
554 (void) in_addr_to_string(route->family, &route->src, &src);
555 if (!in_addr_is_null(route->family, &route->gw))
556 (void) in_addr_to_string(route->family, &route->gw, &gw);
557 if (!in_addr_is_null(route->family, &route->prefsrc))
558 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
559
d3e291fd 560 log_link_debug(link, "Removing route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
b297e0a7
YW
561 strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc),
562 format_route_scope(route->scope, scope, sizeof(scope)),
563 format_route_table(route->table, table, sizeof(table)),
d3e291fd 564 format_route_protocol(route->protocol, protocol, sizeof(protocol)),
b297e0a7
YW
565 strna(route_type_to_string(route->type)));
566 }
567
d40b01e4 568 if (in_addr_is_null(route->family, &route->gw) == 0) {
43409486 569 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
f647962d 570 if (r < 0)
7750b796 571 return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
5c1d3fc9
UTL
572 }
573
574 if (route->dst_prefixlen) {
43409486 575 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
f647962d 576 if (r < 0)
7750b796 577 return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
5c1d3fc9
UTL
578
579 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
f647962d 580 if (r < 0)
7750b796 581 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
5c1d3fc9
UTL
582 }
583
9e7e4408 584 if (route->src_prefixlen) {
43409486 585 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
9e7e4408 586 if (r < 0)
7750b796 587 return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
9e7e4408
TG
588
589 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
590 if (r < 0)
7750b796 591 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
9e7e4408
TG
592 }
593
d40b01e4 594 if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
43409486 595 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
f647962d 596 if (r < 0)
7750b796 597 return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
46b0c76e
ERB
598 }
599
5c1d3fc9 600 r = sd_rtnl_message_route_set_scope(req, route->scope);
f647962d 601 if (r < 0)
7750b796 602 return log_link_error_errno(link, r, "Could not set scope: %m");
5c1d3fc9 603
86655331 604 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
f647962d 605 if (r < 0)
7750b796 606 return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
5c1d3fc9 607
2d53f310 608 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
983226f3
SS
609 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
610 if (r < 0)
7750b796 611 return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
983226f3 612 }
5c1d3fc9 613
302a796f
YW
614 r = netlink_call_async(link->manager->rtnl, NULL, req,
615 callback ?: route_remove_handler,
616 link_netlink_destroy_callback, link);
f647962d 617 if (r < 0)
7750b796 618 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
5c1d3fc9 619
563c69c6
TG
620 link_ref(link);
621
5c1d3fc9
UTL
622 return 0;
623}
624
779804dd
YW
625static bool link_is_static_route_configured(Link *link, Route *route) {
626 Route *net_route;
627
628 assert(link);
629 assert(route);
630
631 if (!link->network)
632 return false;
633
2a54a044 634 HASHMAP_FOREACH(net_route, link->network->routes_by_section)
779804dd
YW
635 if (route_equal(net_route, route))
636 return true;
637
638 return false;
639}
640
641int link_drop_foreign_routes(Link *link) {
642 Route *route;
643 int k, r = 0;
644
645 assert(link);
646
647 SET_FOREACH(route, link->routes_foreign) {
648 /* do not touch routes managed by the kernel */
649 if (route->protocol == RTPROT_KERNEL)
650 continue;
651
652 /* do not touch multicast route added by kernel */
653 /* FIXME: Why the kernel adds this route with protocol RTPROT_BOOT??? We need to investigate that.
654 * https://tools.ietf.org/html/rfc4862#section-5.4 may explain why. */
655 if (route->protocol == RTPROT_BOOT &&
656 route->family == AF_INET6 &&
657 route->dst_prefixlen == 8 &&
658 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 }}} }))
659 continue;
660
661 if (route->protocol == RTPROT_STATIC && link->network &&
662 FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
663 continue;
664
665 if (route->protocol == RTPROT_DHCP && link->network &&
666 FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
667 continue;
668
669 if (link_is_static_route_configured(link, route))
670 k = route_add(link, route, NULL);
671 else
672 k = route_remove(route, link, NULL);
673 if (k < 0 && r >= 0)
674 r = k;
675 }
676
677 return r;
678}
679
62f0ea5f
YW
680int link_drop_routes(Link *link) {
681 Route *route;
682 int k, r = 0;
683
684 assert(link);
685
686 SET_FOREACH(route, link->routes) {
687 /* do not touch routes managed by the kernel */
688 if (route->protocol == RTPROT_KERNEL)
689 continue;
690
691 k = route_remove(route, link, NULL);
692 if (k < 0 && r >= 0)
693 r = k;
694 }
695
696 return r;
697}
698
74154c2e 699static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
f833694d
TG
700 Route *route = userdata;
701 int r;
702
703 assert(route);
704
4645ad47 705 r = route_remove(route, route->link, NULL);
f833694d 706 if (r < 0)
98b02994 707 log_link_warning_errno(route->link, r, "Could not remove route: %m");
3bdccf69 708 else
fe7ca21a 709 route_free(route);
f833694d
TG
710
711 return 1;
712}
713
6ff5cc6b
YW
714static int append_nexthop_one(Route *route, MultipathRoute *m, struct rtattr **rta, size_t offset) {
715 struct rtnexthop *rtnh;
716 struct rtattr *new_rta;
717 int r;
718
719 assert(route);
720 assert(m);
721 assert(rta);
722 assert(*rta);
723
724 new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
725 if (!new_rta)
726 return -ENOMEM;
727 *rta = new_rta;
728
729 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
730 *rtnh = (struct rtnexthop) {
731 .rtnh_len = sizeof(*rtnh),
732 .rtnh_ifindex = m->ifindex,
733 .rtnh_hops = m->weight > 0 ? m->weight - 1 : 0,
734 };
735
736 (*rta)->rta_len += sizeof(struct rtnexthop);
737
738 if (route->family == m->gateway.family) {
739 r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
740 if (r < 0)
741 goto clear;
742 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
743 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
744 } else {
745 r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
746 if (r < 0)
747 goto clear;
748 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
749 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
750 }
751
752 return 0;
753
754clear:
755 (*rta)->rta_len -= sizeof(struct rtnexthop);
756 return r;
757}
758
759static int append_nexthops(Route *route, sd_netlink_message *req) {
760 _cleanup_free_ struct rtattr *rta = NULL;
761 struct rtnexthop *rtnh;
762 MultipathRoute *m;
763 size_t offset;
6ff5cc6b
YW
764 int r;
765
766 if (ordered_set_isempty(route->multipath_routes))
767 return 0;
768
769 rta = new(struct rtattr, 1);
770 if (!rta)
771 return -ENOMEM;
772
773 *rta = (struct rtattr) {
774 .rta_type = RTA_MULTIPATH,
775 .rta_len = RTA_LENGTH(0),
776 };
777 offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
778
90e74a66 779 ORDERED_SET_FOREACH(m, route->multipath_routes) {
6ff5cc6b
YW
780 r = append_nexthop_one(route, m, &rta, offset);
781 if (r < 0)
782 return r;
783
784 rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
785 offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
786 }
787
788 r = sd_netlink_message_append_data(req, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
789 if (r < 0)
790 return r;
791
792 return 0;
793}
794
1b566071
LP
795int route_configure(
796 Route *route,
797 Link *link,
80b0e860
YW
798 link_netlink_message_handler_t callback,
799 Route **ret) {
1b566071 800
4afd3348
LP
801 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
802 _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
f579559b
TG
803 int r;
804
f579559b 805 assert(link);
f882c247
TG
806 assert(link->manager);
807 assert(link->manager->rtnl);
f579559b 808 assert(link->ifindex > 0);
4c701096 809 assert(IN_SET(route->family, AF_INET, AF_INET6));
bd1175bc 810 assert(callback);
f579559b 811
f1368755 812 if (route_get(link, route, NULL) <= 0 &&
47d2d30d 813 set_size(link->routes) >= routes_max())
7750b796
YW
814 return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
815 "Too many routes are configured, refusing: %m");
1b566071 816
156ed65e
YW
817 if (DEBUG_LOGGING) {
818 _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
d3e291fd 819 char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
156ed65e
YW
820
821 if (!in_addr_is_null(route->family, &route->dst)) {
822 (void) in_addr_to_string(route->family, &route->dst, &dst);
823 (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen);
824 }
825 if (!in_addr_is_null(route->family, &route->src))
826 (void) in_addr_to_string(route->family, &route->src, &src);
827 if (!in_addr_is_null(route->family, &route->gw))
828 (void) in_addr_to_string(route->family, &route->gw, &gw);
829 if (!in_addr_is_null(route->family, &route->prefsrc))
830 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
831
d3e291fd 832 log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
b297e0a7
YW
833 strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc),
834 format_route_scope(route->scope, scope, sizeof(scope)),
835 format_route_table(route->table, table, sizeof(table)),
d3e291fd 836 format_route_protocol(route->protocol, protocol, sizeof(protocol)),
b297e0a7 837 strna(route_type_to_string(route->type)));
156ed65e
YW
838 }
839
151b9b96 840 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
28cc555d
DW
841 RTM_NEWROUTE, route->family,
842 route->protocol);
f647962d 843 if (r < 0)
7750b796 844 return log_link_error_errno(link, r, "Could not create RTM_NEWROUTE message: %m");
f579559b 845
d40b01e4 846 if (in_addr_is_null(route->family, &route->gw) == 0) {
43409486 847 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
f647962d 848 if (r < 0)
7750b796 849 return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
c953b24c
SS
850
851 r = sd_rtnl_message_route_set_family(req, route->family);
852 if (r < 0)
7750b796 853 return log_link_error_errno(link, r, "Could not set route family: %m");
f579559b
TG
854 }
855
70dc2362 856 if (route->dst_prefixlen > 0) {
43409486 857 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
f647962d 858 if (r < 0)
7750b796 859 return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
6ae115c1 860
ae4c67a7 861 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
f647962d 862 if (r < 0)
7750b796 863 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
1f01fb4f
TG
864 }
865
70dc2362 866 if (route->src_prefixlen > 0) {
43409486 867 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
9e7e4408 868 if (r < 0)
7750b796 869 return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
9e7e4408
TG
870
871 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
872 if (r < 0)
7750b796 873 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
9e7e4408
TG
874 }
875
d40b01e4 876 if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
43409486 877 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
f647962d 878 if (r < 0)
7750b796 879 return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
46b0c76e
ERB
880 }
881
5c1d3fc9 882 r = sd_rtnl_message_route_set_scope(req, route->scope);
f647962d 883 if (r < 0)
7750b796 884 return log_link_error_errno(link, r, "Could not set scope: %m");
5c1d3fc9 885
54901fd2
YW
886 if (route->gateway_onlink >= 0)
887 SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
888
3b015d40
TG
889 r = sd_rtnl_message_route_set_flags(req, route->flags);
890 if (r < 0)
7750b796 891 return log_link_error_errno(link, r, "Could not set flags: %m");
c953b24c 892
a0d95bbc 893 if (route->table != RT_TABLE_MAIN) {
c953b24c
SS
894 if (route->table < 256) {
895 r = sd_rtnl_message_route_set_table(req, route->table);
896 if (r < 0)
7750b796 897 return log_link_error_errno(link, r, "Could not set route table: %m");
c953b24c 898 } else {
c953b24c
SS
899 r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
900 if (r < 0)
7750b796 901 return log_link_error_errno(link, r, "Could not set route table: %m");
c953b24c 902
06976f5b 903 /* Table attribute to allow more than 256. */
c953b24c
SS
904 r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
905 if (r < 0)
7750b796 906 return log_link_error_errno(link, r, "Could not append RTA_TABLE attribute: %m");
c953b24c
SS
907 }
908 }
3b015d40 909
86655331 910 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
f647962d 911 if (r < 0)
7750b796 912 return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
5c1d3fc9 913
3b015d40
TG
914 r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
915 if (r < 0)
7750b796 916 return log_link_error_errno(link, r, "Could not append RTA_PREF attribute: %m");
3b015d40 917
f02ba163
DD
918 if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
919 r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
920 DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
921 if (r < 0)
7750b796 922 return log_link_error_errno(link, r, "Could not append RTA_EXPIRES attribute: %m");
f02ba163
DD
923 }
924
983226f3 925 r = sd_rtnl_message_route_set_type(req, route->type);
f647962d 926 if (r < 0)
7750b796 927 return log_link_error_errno(link, r, "Could not set route type: %m");
983226f3 928
2d53f310 929 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
983226f3
SS
930 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
931 if (r < 0)
7750b796 932 return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
983226f3 933 }
f579559b 934
9b88f20a
SS
935 if (route->ttl_propagate >= 0) {
936 r = sd_netlink_message_append_u8(req, RTA_TTL_PROPAGATE, route->ttl_propagate);
937 if (r < 0)
938 return log_link_error_errno(link, r, "Could not append RTA_TTL_PROPAGATE attribute: %m");
939 }
940
d6fceaf1
SS
941 r = sd_netlink_message_open_container(req, RTA_METRICS);
942 if (r < 0)
7750b796 943 return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
d6fceaf1
SS
944
945 if (route->mtu > 0) {
946 r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
947 if (r < 0)
7750b796 948 return log_link_error_errno(link, r, "Could not append RTAX_MTU attribute: %m");
d6fceaf1
SS
949 }
950
6b21ad33 951 if (route->initcwnd > 0) {
323d9329
SS
952 r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
953 if (r < 0)
7750b796 954 return log_link_error_errno(link, r, "Could not append RTAX_INITCWND attribute: %m");
323d9329
SS
955 }
956
6b21ad33 957 if (route->initrwnd > 0) {
323d9329
SS
958 r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
959 if (r < 0)
7750b796 960 return log_link_error_errno(link, r, "Could not append RTAX_INITRWND attribute: %m");
323d9329
SS
961 }
962
67c193bf 963 if (route->quickack >= 0) {
09f5dfad
SS
964 r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
965 if (r < 0)
7750b796 966 return log_link_error_errno(link, r, "Could not append RTAX_QUICKACK attribute: %m");
09f5dfad
SS
967 }
968
633c7258
SS
969 if (route->fast_open_no_cookie >= 0) {
970 r = sd_netlink_message_append_u32(req, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
971 if (r < 0)
972 return log_link_error_errno(link, r, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
973 }
974
d6fceaf1
SS
975 r = sd_netlink_message_close_container(req);
976 if (r < 0)
7750b796 977 return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
d6fceaf1 978
6ff5cc6b
YW
979 r = append_nexthops(route, req);
980 if (r < 0)
981 return log_link_error_errno(link, r, "Could not append RTA_MULTIPATH attribute: %m");
982
302a796f
YW
983 r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
984 link_netlink_destroy_callback, link);
f647962d 985 if (r < 0)
7750b796 986 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
f579559b 987
563c69c6
TG
988 link_ref(link);
989
f1368755 990 r = route_add(link, route, &route);
1c8e710c 991 if (r < 0)
7750b796 992 return log_link_error_errno(link, r, "Could not add route: %m");
1c8e710c 993
f833694d 994 /* TODO: drop expiration handling once it can be pushed into the kernel */
f02ba163 995 if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
f833694d
TG
996 r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
997 route->lifetime, 0, route_expire_handler, route);
998 if (r < 0)
7750b796 999 return log_link_error_errno(link, r, "Could not arm expiration timer: %m");
f833694d
TG
1000 }
1001
1002 sd_event_source_unref(route->expire);
1cc6c93a 1003 route->expire = TAKE_PTR(expire);
f833694d 1004
80b0e860
YW
1005 if (ret)
1006 *ret = route;
1007
c4423317 1008 return 1;
f579559b
TG
1009}
1010
141318f7
YW
1011static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
1012 int r;
1013
1014 assert(link);
1015 assert(link->route_messages > 0);
1016 assert(IN_SET(link->state, LINK_STATE_CONFIGURING,
1017 LINK_STATE_FAILED, LINK_STATE_LINGER));
1018
1019 link->route_messages--;
1020
1021 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
1022 return 1;
1023
1024 r = sd_netlink_message_get_errno(m);
1025 if (r < 0 && r != -EEXIST) {
1026 log_link_message_warning_errno(link, m, r, "Could not set route");
1027 link_enter_failed(link);
1028 return 1;
1029 }
1030
1031 if (link->route_messages == 0) {
1032 log_link_debug(link, "Routes set");
1033 link->static_routes_configured = true;
1034 link_set_nexthop(link);
1035 }
1036
1037 return 1;
1038}
1039
1040int link_set_routes(Link *link) {
1041 enum {
1042 PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */
1043 PHASE_GATEWAY, /* Second phase: Routes with a gateway */
1044 _PHASE_MAX
1045 } phase;
1046 Route *rt;
1047 int r;
1048
1049 assert(link);
1050 assert(link->network);
1051 assert(link->state != _LINK_STATE_INVALID);
1052
1053 link->static_routes_configured = false;
1054
1055 if (!link->addresses_ready)
1056 return 0;
1057
1058 if (!link_has_carrier(link) && !link->network->configure_without_carrier)
1059 /* During configuring addresses, the link lost its carrier. As networkd is dropping
1060 * the addresses now, let's not configure the routes either. */
1061 return 0;
1062
1063 r = link_set_routing_policy_rules(link);
1064 if (r < 0)
1065 return r;
1066
1067 /* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */
1068 for (phase = 0; phase < _PHASE_MAX; phase++)
2a54a044 1069 HASHMAP_FOREACH(rt, link->network->routes_by_section) {
141318f7
YW
1070 if (rt->gateway_from_dhcp)
1071 continue;
1072
1073 if ((in_addr_is_null(rt->family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY))
1074 continue;
1075
1076 r = route_configure(rt, link, route_handler, NULL);
1077 if (r < 0)
1078 return log_link_warning_errno(link, r, "Could not set routes: %m");
1079 if (r > 0)
1080 link->route_messages++;
1081 }
1082
1083 if (link->route_messages == 0) {
1084 link->static_routes_configured = true;
1085 link_set_nexthop(link);
1086 } else {
1087 log_link_debug(link, "Setting routes");
1088 link_set_state(link, LINK_STATE_CONFIGURING);
1089 }
1090
1091 return 0;
1092}
1093
4468f01b
YW
1094int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
1095 _cleanup_(route_freep) Route *tmp = NULL;
1096 Route *route = NULL;
1097 Link *link = NULL;
1098 uint32_t ifindex;
1099 uint16_t type;
1100 unsigned char table;
1101 int r;
1102
1103 assert(rtnl);
1104 assert(message);
1105 assert(m);
1106
1107 if (sd_netlink_message_is_error(message)) {
1108 r = sd_netlink_message_get_errno(message);
1109 if (r < 0)
1110 log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
1111
1112 return 0;
1113 }
1114
1115 r = sd_netlink_message_get_type(message, &type);
1116 if (r < 0) {
1117 log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
1118 return 0;
1119 } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
1120 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
1121 return 0;
1122 }
1123
1124 r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
1125 if (r == -ENODATA) {
1126 log_debug("rtnl: received route message without ifindex, ignoring");
1127 return 0;
1128 } else if (r < 0) {
1129 log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
1130 return 0;
1131 } else if (ifindex <= 0) {
1132 log_warning("rtnl: received route message with invalid ifindex %d, ignoring.", ifindex);
1133 return 0;
1134 }
1135
1136 r = link_get(m, ifindex, &link);
1137 if (r < 0 || !link) {
1138 /* when enumerating we might be out of sync, but we will
1139 * get the route again, so just ignore it */
1140 if (!m->enumerating)
1141 log_warning("rtnl: received route message for link (%d) we do not know about, ignoring", ifindex);
1142 return 0;
1143 }
1144
1145 r = route_new(&tmp);
1146 if (r < 0)
1147 return log_oom();
1148
1149 r = sd_rtnl_message_route_get_family(message, &tmp->family);
1150 if (r < 0) {
1151 log_link_warning(link, "rtnl: received route message without family, ignoring");
1152 return 0;
1153 } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
1154 log_link_debug(link, "rtnl: received route message with invalid family '%i', ignoring", tmp->family);
1155 return 0;
1156 }
1157
1158 r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
1159 if (r < 0) {
1160 log_warning_errno(r, "rtnl: received route message without route protocol: %m");
1161 return 0;
1162 }
1163
1164 switch (tmp->family) {
1165 case AF_INET:
1166 r = sd_netlink_message_read_in_addr(message, RTA_DST, &tmp->dst.in);
1167 if (r < 0 && r != -ENODATA) {
1168 log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
1169 return 0;
1170 }
1171
1172 r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &tmp->gw.in);
1173 if (r < 0 && r != -ENODATA) {
1174 log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
1175 return 0;
1176 }
1177
1178 r = sd_netlink_message_read_in_addr(message, RTA_SRC, &tmp->src.in);
1179 if (r < 0 && r != -ENODATA) {
1180 log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
1181 return 0;
1182 }
1183
1184 r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &tmp->prefsrc.in);
1185 if (r < 0 && r != -ENODATA) {
1186 log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
1187 return 0;
1188 }
1189
1190 break;
1191
1192 case AF_INET6:
1193 r = sd_netlink_message_read_in6_addr(message, RTA_DST, &tmp->dst.in6);
1194 if (r < 0 && r != -ENODATA) {
1195 log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
1196 return 0;
1197 }
1198
1199 r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &tmp->gw.in6);
1200 if (r < 0 && r != -ENODATA) {
1201 log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
1202 return 0;
1203 }
1204
1205 r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &tmp->src.in6);
1206 if (r < 0 && r != -ENODATA) {
1207 log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
1208 return 0;
1209 }
1210
1211 r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &tmp->prefsrc.in6);
1212 if (r < 0 && r != -ENODATA) {
1213 log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
1214 return 0;
1215 }
1216
1217 break;
1218
1219 default:
1220 assert_not_reached("Received route message with unsupported address family");
1221 return 0;
1222 }
1223
1224 r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
1225 if (r < 0) {
1226 log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1227 return 0;
1228 }
1229
1230 r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
1231 if (r < 0) {
1232 log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1233 return 0;
1234 }
1235
1236 r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
1237 if (r < 0) {
1238 log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m");
1239 return 0;
1240 }
1241
1242 r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
1243 if (r < 0) {
1244 log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m");
1245 return 0;
1246 }
1247
1248 r = sd_rtnl_message_route_get_type(message, &tmp->type);
1249 if (r < 0) {
1250 log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m");
1251 return 0;
1252 }
1253
1254 r = sd_rtnl_message_route_get_table(message, &table);
1255 if (r < 0) {
1256 log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m");
1257 return 0;
1258 }
1259 tmp->table = table;
1260
1261 r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
1262 if (r < 0 && r != -ENODATA) {
1263 log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
1264 return 0;
1265 }
1266
1267 r = sd_netlink_message_enter_container(message, RTA_METRICS);
1268 if (r < 0 && r != -ENODATA) {
1269 log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container: %m");
1270 return 0;
1271 }
1272 if (r >= 0) {
1273 r = sd_netlink_message_read_u32(message, RTAX_INITCWND, &tmp->initcwnd);
1274 if (r < 0 && r != -ENODATA) {
1275 log_link_warning_errno(link, r, "rtnl: received route message with invalid initcwnd, ignoring: %m");
1276 return 0;
1277 }
1278
1279 r = sd_netlink_message_read_u32(message, RTAX_INITRWND, &tmp->initrwnd);
1280 if (r < 0 && r != -ENODATA) {
1281 log_link_warning_errno(link, r, "rtnl: received route message with invalid initrwnd, ignoring: %m");
1282 return 0;
1283 }
1284
1285 r = sd_netlink_message_exit_container(message);
1286 if (r < 0) {
1287 log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container: %m");
1288 return 0;
1289 }
1290 }
1291
1292 (void) route_get(link, tmp, &route);
1293
1294 if (DEBUG_LOGGING) {
1295 _cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
1296 *buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL;
1297 char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX],
1298 buf_protocol[ROUTE_PROTOCOL_STR_MAX];
1299
1300 if (!in_addr_is_null(tmp->family, &tmp->dst)) {
1301 (void) in_addr_to_string(tmp->family, &tmp->dst, &buf_dst);
1302 (void) asprintf(&buf_dst_prefixlen, "/%u", tmp->dst_prefixlen);
1303 }
1304 if (!in_addr_is_null(tmp->family, &tmp->src))
1305 (void) in_addr_to_string(tmp->family, &tmp->src, &buf_src);
1306 if (!in_addr_is_null(tmp->family, &tmp->gw))
1307 (void) in_addr_to_string(tmp->family, &tmp->gw, &buf_gw);
1308 if (!in_addr_is_null(tmp->family, &tmp->prefsrc))
1309 (void) in_addr_to_string(tmp->family, &tmp->prefsrc, &buf_prefsrc);
1310
1311 log_link_debug(link,
1312 "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
1313 (!route && !link->manager->manage_foreign_routes) ? "Ignoring received foreign" :
1314 type == RTM_DELROUTE ? "Forgetting" :
1315 route ? "Received remembered" : "Remembering",
1316 strna(buf_dst), strempty(buf_dst_prefixlen),
1317 strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
1318 format_route_scope(tmp->scope, buf_scope, sizeof buf_scope),
1319 format_route_table(tmp->table, buf_table, sizeof buf_table),
1320 format_route_protocol(tmp->protocol, buf_protocol, sizeof buf_protocol),
1321 strna(route_type_to_string(tmp->type)));
1322 }
1323
1324 switch (type) {
1325 case RTM_NEWROUTE:
1326 if (!route && link->manager->manage_foreign_routes) {
1327 /* A route appeared that we did not request */
1328 r = route_add_foreign(link, tmp, &route);
1329 if (r < 0) {
1330 log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
1331 return 0;
1332 }
1333 }
1334
1335 break;
1336
1337 case RTM_DELROUTE:
1338 route_free(route);
1339 break;
1340
1341 default:
1342 assert_not_reached("Received route message with invalid RTNL message type");
1343 }
1344
1345 return 1;
1346}
1347
56519412
YW
1348int link_serialize_routes(Link *link, FILE *f) {
1349 bool space = false;
1350 Route *route;
1351
1352 assert(link);
1353 assert(link->network);
1354 assert(f);
1355
1356 fputs("ROUTES=", f);
1357 SET_FOREACH(route, link->routes) {
1358 _cleanup_free_ char *route_str = NULL;
1359
1360 if (in_addr_to_string(route->family, &route->dst, &route_str) < 0)
1361 continue;
1362
1363 fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%"PRIu32"/"USEC_FMT,
1364 space ? " " : "", route_str,
1365 route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime);
1366 space = true;
1367 }
1368 fputc('\n', f);
1369
1370 return 0;
1371}
1372
731ff05b
YW
1373int link_deserialize_routes(Link *link, const char *routes) {
1374 int r;
1375
1376 assert(link);
1377
1378 for (const char *p = routes;; ) {
1379 _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
1380 _cleanup_(route_freep) Route *tmp = NULL;
1381 _cleanup_free_ char *route_str = NULL;
1382 char *prefixlen_str;
1383 Route *route;
1384
1385 r = extract_first_word(&p, &route_str, NULL, 0);
1386 if (r < 0)
1387 return log_link_debug_errno(link, r, "Failed to parse ROUTES=: %m");
1388 if (r == 0)
1389 return 0;
1390
1391 prefixlen_str = strchr(route_str, '/');
1392 if (!prefixlen_str) {
1393 log_link_debug(link, "Failed to parse route, ignoring: %s", route_str);
1394 continue;
1395 }
1396 *prefixlen_str++ = '\0';
1397
1398 r = route_new(&tmp);
1399 if (r < 0)
1400 return log_oom();
1401
1402 r = sscanf(prefixlen_str,
1403 "%hhu/%hhu/%"SCNu32"/%"PRIu32"/"USEC_FMT,
1404 &tmp->dst_prefixlen,
1405 &tmp->tos,
1406 &tmp->priority,
1407 &tmp->table,
1408 &tmp->lifetime);
1409 if (r != 5) {
1410 log_link_debug(link,
1411 "Failed to parse destination prefix length, tos, priority, table or expiration: %s",
1412 prefixlen_str);
1413 continue;
1414 }
1415
1416 r = in_addr_from_string_auto(route_str, &tmp->family, &tmp->dst);
1417 if (r < 0) {
1418 log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str);
1419 continue;
1420 }
1421
1422 r = route_add(link, tmp, &route);
1423 if (r < 0)
1424 return log_link_debug_errno(link, r, "Failed to add route: %m");
1425
1426 if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
1427 r = sd_event_add_time(link->manager->event, &expire,
1428 clock_boottime_or_monotonic(),
1429 route->lifetime, 0, route_expire_handler, route);
1430 if (r < 0)
1431 log_link_debug_errno(link, r, "Could not arm route expiration handler: %m");
1432 }
1433
1434 sd_event_source_unref(route->expire);
1435 route->expire = TAKE_PTR(expire);
1436 }
1437}
1438
fa7cd711 1439int network_add_ipv4ll_route(Network *network) {
fcbf4cb7 1440 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2a54a044 1441 unsigned section_line;
fa7cd711
YW
1442 int r;
1443
1444 assert(network);
1445
1446 if (!network->ipv4ll_route)
1447 return 0;
1448
2a54a044
YW
1449 section_line = hashmap_find_free_section_line(network->routes_by_section);
1450
fa7cd711 1451 /* IPv4LLRoute= is in [Network] section. */
2a54a044 1452 r = route_new_static(network, network->filename, section_line, &n);
fa7cd711
YW
1453 if (r < 0)
1454 return r;
1455
1456 r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
1457 if (r < 0)
1458 return r;
1459
1460 n->family = AF_INET;
1461 n->dst_prefixlen = 16;
1462 n->scope = RT_SCOPE_LINK;
94d6e299
YW
1463 n->scope_set = true;
1464 n->table_set = true;
fa7cd711
YW
1465 n->priority = IPV4LL_ROUTE_METRIC;
1466 n->protocol = RTPROT_STATIC;
1467
1468 TAKE_PTR(n);
1469 return 0;
1470}
1471
5d5003ab
YW
1472int network_add_default_route_on_device(Network *network) {
1473 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2a54a044 1474 unsigned section_line;
5d5003ab
YW
1475 int r;
1476
1477 assert(network);
1478
1479 if (!network->default_route_on_device)
1480 return 0;
1481
2a54a044
YW
1482 section_line = hashmap_find_free_section_line(network->routes_by_section);
1483
5d5003ab 1484 /* DefaultRouteOnDevice= is in [Network] section. */
2a54a044 1485 r = route_new_static(network, network->filename, section_line, &n);
5d5003ab
YW
1486 if (r < 0)
1487 return r;
1488
5d5003ab 1489 n->family = AF_INET;
c697db75
YW
1490 n->scope = RT_SCOPE_LINK;
1491 n->scope_set = true;
1492 n->protocol = RTPROT_STATIC;
5d5003ab
YW
1493
1494 TAKE_PTR(n);
1495 return 0;
1496}
1497
27efb52b
YW
1498int config_parse_gateway(
1499 const char *unit,
f579559b
TG
1500 const char *filename,
1501 unsigned line,
1502 const char *section,
71a61510 1503 unsigned section_line,
f579559b
TG
1504 const char *lvalue,
1505 int ltype,
1506 const char *rvalue,
1507 void *data,
1508 void *userdata) {
44e7b949 1509
6ae115c1 1510 Network *network = userdata;
fcbf4cb7 1511 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
7934dede 1512 int r;
f579559b
TG
1513
1514 assert(filename);
6ae115c1 1515 assert(section);
f579559b
TG
1516 assert(lvalue);
1517 assert(rvalue);
1518 assert(data);
1519
92fe133a 1520 if (streq(section, "Network")) {
2a54a044
YW
1521 /* we are not in an Route section, so use line number instead */
1522 r = route_new_static(network, filename, line, &n);
d96edb2c
YW
1523 if (r == -ENOMEM)
1524 return log_oom();
1525 if (r < 0) {
1526 log_syntax(unit, LOG_WARNING, filename, line, r,
1527 "Failed to allocate route, ignoring assignment: %m");
1528 return 0;
1529 }
1985c54f 1530 } else {
f4859fc7 1531 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1532 if (r == -ENOMEM)
1533 return log_oom();
1534 if (r < 0) {
1535 log_syntax(unit, LOG_WARNING, filename, line, r,
1536 "Failed to allocate route, ignoring assignment: %m");
1537 return 0;
1538 }
1985c54f 1539
427928ca 1540 if (streq(rvalue, "_dhcp")) {
1985c54f
YW
1541 n->gateway_from_dhcp = true;
1542 TAKE_PTR(n);
1543 return 0;
1544 }
1545 }
f579559b 1546
01d4e732
YW
1547 if (n->family == AF_UNSPEC)
1548 r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
1549 else
1550 r = in_addr_from_string(n->family, rvalue, &n->gw);
f579559b 1551 if (r < 0) {
d96edb2c 1552 log_syntax(unit, LOG_WARNING, filename, line, r,
01d4e732 1553 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
f579559b
TG
1554 return 0;
1555 }
1556
aff44301 1557 TAKE_PTR(n);
f579559b
TG
1558 return 0;
1559}
6ae115c1 1560
27efb52b
YW
1561int config_parse_preferred_src(
1562 const char *unit,
0d07e595
JK
1563 const char *filename,
1564 unsigned line,
1565 const char *section,
1566 unsigned section_line,
1567 const char *lvalue,
1568 int ltype,
1569 const char *rvalue,
1570 void *data,
1571 void *userdata) {
1572
1573 Network *network = userdata;
fcbf4cb7 1574 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
7934dede 1575 int r;
0d07e595
JK
1576
1577 assert(filename);
1578 assert(section);
1579 assert(lvalue);
1580 assert(rvalue);
1581 assert(data);
1582
f4859fc7 1583 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1584 if (r == -ENOMEM)
1585 return log_oom();
1586 if (r < 0) {
1587 log_syntax(unit, LOG_WARNING, filename, line, r,
1588 "Failed to allocate route, ignoring assignment: %m");
1589 return 0;
1590 }
0d07e595 1591
01d4e732
YW
1592 if (n->family == AF_UNSPEC)
1593 r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
1594 else
1595 r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
0d07e595 1596 if (r < 0) {
d96edb2c 1597 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
01d4e732 1598 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
0d07e595
JK
1599 return 0;
1600 }
1601
aff44301 1602 TAKE_PTR(n);
0d07e595
JK
1603 return 0;
1604}
1605
27efb52b
YW
1606int config_parse_destination(
1607 const char *unit,
6ae115c1
TG
1608 const char *filename,
1609 unsigned line,
1610 const char *section,
1611 unsigned section_line,
1612 const char *lvalue,
1613 int ltype,
1614 const char *rvalue,
1615 void *data,
1616 void *userdata) {
44e7b949 1617
6ae115c1 1618 Network *network = userdata;
fcbf4cb7 1619 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
7934dede
YW
1620 union in_addr_union *buffer;
1621 unsigned char *prefixlen;
ca3bad65 1622 int r;
6ae115c1
TG
1623
1624 assert(filename);
1625 assert(section);
1626 assert(lvalue);
1627 assert(rvalue);
1628 assert(data);
1629
f4859fc7 1630 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1631 if (r == -ENOMEM)
1632 return log_oom();
1633 if (r < 0) {
1634 log_syntax(unit, LOG_WARNING, filename, line, r,
1635 "Failed to allocate route, ignoring assignment: %m");
1636 return 0;
1637 }
6ae115c1 1638
9e7e4408 1639 if (streq(lvalue, "Destination")) {
7934dede
YW
1640 buffer = &n->dst;
1641 prefixlen = &n->dst_prefixlen;
9e7e4408 1642 } else if (streq(lvalue, "Source")) {
7934dede
YW
1643 buffer = &n->src;
1644 prefixlen = &n->src_prefixlen;
9e7e4408
TG
1645 } else
1646 assert_not_reached(lvalue);
1647
01d4e732
YW
1648 if (n->family == AF_UNSPEC)
1649 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
1650 else
1651 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
7934dede 1652 if (r < 0) {
d96edb2c 1653 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
01d4e732 1654 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
7934dede
YW
1655 return 0;
1656 }
1657
aff44301 1658 TAKE_PTR(n);
6ae115c1
TG
1659 return 0;
1660}
5d8e593d 1661
27efb52b
YW
1662int config_parse_route_priority(
1663 const char *unit,
1664 const char *filename,
1665 unsigned line,
1666 const char *section,
1667 unsigned section_line,
1668 const char *lvalue,
1669 int ltype,
1670 const char *rvalue,
1671 void *data,
1672 void *userdata) {
1673
5d8e593d 1674 Network *network = userdata;
fcbf4cb7 1675 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
5d8e593d
SS
1676 int r;
1677
1678 assert(filename);
1679 assert(section);
1680 assert(lvalue);
1681 assert(rvalue);
1682 assert(data);
1683
f4859fc7 1684 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1685 if (r == -ENOMEM)
1686 return log_oom();
1687 if (r < 0) {
1688 log_syntax(unit, LOG_WARNING, filename, line, r,
1689 "Failed to allocate route, ignoring assignment: %m");
1690 return 0;
1691 }
5d8e593d 1692
aff44301 1693 r = safe_atou32(rvalue, &n->priority);
1c4b1179 1694 if (r < 0) {
d96edb2c 1695 log_syntax(unit, LOG_WARNING, filename, line, r,
1c4b1179
SS
1696 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
1697 return 0;
1698 }
5d8e593d 1699
aff44301 1700 TAKE_PTR(n);
5d8e593d
SS
1701 return 0;
1702}
769b56a3 1703
27efb52b
YW
1704int config_parse_route_scope(
1705 const char *unit,
1706 const char *filename,
1707 unsigned line,
1708 const char *section,
1709 unsigned section_line,
1710 const char *lvalue,
1711 int ltype,
1712 const char *rvalue,
1713 void *data,
1714 void *userdata) {
1715
769b56a3 1716 Network *network = userdata;
fcbf4cb7 1717 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
769b56a3
TG
1718 int r;
1719
1720 assert(filename);
1721 assert(section);
1722 assert(lvalue);
1723 assert(rvalue);
1724 assert(data);
1725
f4859fc7 1726 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1727 if (r == -ENOMEM)
1728 return log_oom();
1729 if (r < 0) {
1730 log_syntax(unit, LOG_WARNING, filename, line, r,
1731 "Failed to allocate route, ignoring assignment: %m");
1732 return 0;
1733 }
769b56a3 1734
41b90a1e
YW
1735 r = route_scope_from_string(rvalue);
1736 if (r < 0) {
d96edb2c 1737 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route scope: %s", rvalue);
769b56a3
TG
1738 return 0;
1739 }
1740
41b90a1e 1741 n->scope = r;
94d6e299 1742 n->scope_set = true;
aff44301 1743 TAKE_PTR(n);
769b56a3
TG
1744 return 0;
1745}
c953b24c 1746
27efb52b
YW
1747int config_parse_route_table(
1748 const char *unit,
1749 const char *filename,
1750 unsigned line,
1751 const char *section,
1752 unsigned section_line,
1753 const char *lvalue,
1754 int ltype,
1755 const char *rvalue,
1756 void *data,
1757 void *userdata) {
1758
fcbf4cb7 1759 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
c953b24c 1760 Network *network = userdata;
c953b24c
SS
1761 int r;
1762
1763 assert(filename);
1764 assert(section);
1765 assert(lvalue);
1766 assert(rvalue);
1767 assert(data);
1768
f4859fc7 1769 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1770 if (r == -ENOMEM)
1771 return log_oom();
1772 if (r < 0) {
1773 log_syntax(unit, LOG_WARNING, filename, line, r,
1774 "Failed to allocate route, ignoring assignment: %m");
1775 return 0;
1776 }
c953b24c 1777
41b90a1e
YW
1778 r = route_table_from_string(rvalue);
1779 if (r >= 0)
1780 n->table = r;
1781 else {
1782 r = safe_atou32(rvalue, &n->table);
1783 if (r < 0) {
d96edb2c 1784 log_syntax(unit, LOG_WARNING, filename, line, r,
41b90a1e
YW
1785 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
1786 return 0;
1787 }
c953b24c
SS
1788 }
1789
94d6e299 1790 n->table_set = true;
aff44301 1791 TAKE_PTR(n);
c953b24c
SS
1792 return 0;
1793}
28959f7d 1794
d96edb2c 1795int config_parse_route_boolean(
27efb52b
YW
1796 const char *unit,
1797 const char *filename,
1798 unsigned line,
1799 const char *section,
1800 unsigned section_line,
1801 const char *lvalue,
1802 int ltype,
1803 const char *rvalue,
1804 void *data,
1805 void *userdata) {
1806
28959f7d 1807 Network *network = userdata;
fcbf4cb7 1808 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
28959f7d
SS
1809 int r;
1810
1811 assert(filename);
1812 assert(section);
1813 assert(lvalue);
1814 assert(rvalue);
1815 assert(data);
1816
1817 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1818 if (r == -ENOMEM)
1819 return log_oom();
1820 if (r < 0) {
1821 log_syntax(unit, LOG_WARNING, filename, line, r,
1822 "Failed to allocate route, ignoring assignment: %m");
1823 return 0;
1824 }
28959f7d
SS
1825
1826 r = parse_boolean(rvalue);
1827 if (r < 0) {
d96edb2c 1828 log_syntax(unit, LOG_WARNING, filename, line, r,
9cb8c559 1829 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
28959f7d
SS
1830 return 0;
1831 }
1832
d96edb2c
YW
1833 if (STR_IN_SET(lvalue, "GatewayOnLink", "GatewayOnlink"))
1834 n->gateway_onlink = r;
1835 else if (streq(lvalue, "QuickAck"))
1836 n->quickack = r;
1837 else if (streq(lvalue, "FastOpenNoCookie"))
1838 n->fast_open_no_cookie = r;
1839 else if (streq(lvalue, "TTLPropagate"))
1840 n->ttl_propagate = r;
1841 else
1842 assert_not_reached("Invalid lvalue");
54901fd2 1843
aff44301 1844 TAKE_PTR(n);
b5bf6f64
SS
1845 return 0;
1846}
1847
27efb52b
YW
1848int config_parse_ipv6_route_preference(
1849 const char *unit,
1850 const char *filename,
1851 unsigned line,
1852 const char *section,
1853 unsigned section_line,
1854 const char *lvalue,
1855 int ltype,
1856 const char *rvalue,
1857 void *data,
1858 void *userdata) {
1859
b5bf6f64 1860 Network *network = userdata;
fcbf4cb7 1861 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
b5bf6f64
SS
1862 int r;
1863
4c7bd9cf 1864 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1865 if (r == -ENOMEM)
1866 return log_oom();
1867 if (r < 0) {
1868 log_syntax(unit, LOG_WARNING, filename, line, r,
1869 "Failed to allocate route, ignoring assignment: %m");
1870 return 0;
1871 }
4c7bd9cf 1872
b5bf6f64
SS
1873 if (streq(rvalue, "low"))
1874 n->pref = ICMPV6_ROUTER_PREF_LOW;
1875 else if (streq(rvalue, "medium"))
1876 n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
1877 else if (streq(rvalue, "high"))
1878 n->pref = ICMPV6_ROUTER_PREF_HIGH;
1879 else {
d96edb2c 1880 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route preference: %s", rvalue);
b5bf6f64
SS
1881 return 0;
1882 }
28959f7d 1883
aff44301 1884 TAKE_PTR(n);
28959f7d
SS
1885 return 0;
1886}
c83ecc04 1887
27efb52b
YW
1888int config_parse_route_protocol(
1889 const char *unit,
1890 const char *filename,
1891 unsigned line,
1892 const char *section,
1893 unsigned section_line,
1894 const char *lvalue,
1895 int ltype,
1896 const char *rvalue,
1897 void *data,
1898 void *userdata) {
1899
c83ecc04 1900 Network *network = userdata;
fcbf4cb7 1901 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
c83ecc04
SS
1902 int r;
1903
1904 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1905 if (r == -ENOMEM)
1906 return log_oom();
1907 if (r < 0) {
1908 log_syntax(unit, LOG_WARNING, filename, line, r,
1909 "Failed to allocate route, ignoring assignment: %m");
1910 return 0;
1911 }
c83ecc04 1912
1b64651b
YW
1913 r = route_protocol_from_string(rvalue);
1914 if (r >= 0)
1915 n->protocol = r;
c83ecc04
SS
1916 else {
1917 r = safe_atou8(rvalue , &n->protocol);
1918 if (r < 0) {
d96edb2c 1919 log_syntax(unit, LOG_WARNING, filename, line, r,
f205a92a 1920 "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
c83ecc04
SS
1921 return 0;
1922 }
1923 }
1924
aff44301 1925 TAKE_PTR(n);
c83ecc04
SS
1926 return 0;
1927}
983226f3 1928
27efb52b
YW
1929int config_parse_route_type(
1930 const char *unit,
1931 const char *filename,
1932 unsigned line,
1933 const char *section,
1934 unsigned section_line,
1935 const char *lvalue,
1936 int ltype,
1937 const char *rvalue,
1938 void *data,
1939 void *userdata) {
1940
983226f3 1941 Network *network = userdata;
fcbf4cb7 1942 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
7a22312d 1943 int t, r;
983226f3
SS
1944
1945 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1946 if (r == -ENOMEM)
1947 return log_oom();
1948 if (r < 0) {
1949 log_syntax(unit, LOG_WARNING, filename, line, r,
1950 "Failed to allocate route, ignoring assignment: %m");
1951 return 0;
1952 }
983226f3 1953
7a22312d
YW
1954 t = route_type_from_string(rvalue);
1955 if (t < 0) {
d96edb2c 1956 log_syntax(unit, LOG_WARNING, filename, line, 0,
f205a92a 1957 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
983226f3
SS
1958 return 0;
1959 }
1960
7a22312d
YW
1961 n->type = (unsigned char) t;
1962
aff44301 1963 TAKE_PTR(n);
983226f3
SS
1964 return 0;
1965}
323d9329 1966
27efb52b
YW
1967int config_parse_tcp_window(
1968 const char *unit,
1969 const char *filename,
1970 unsigned line,
1971 const char *section,
1972 unsigned section_line,
1973 const char *lvalue,
1974 int ltype,
1975 const char *rvalue,
1976 void *data,
1977 void *userdata) {
1978
fcbf4cb7 1979 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
6b21ad33 1980 Network *network = userdata;
fef160b5 1981 uint32_t k;
323d9329
SS
1982 int r;
1983
1984 assert(filename);
1985 assert(section);
1986 assert(lvalue);
1987 assert(rvalue);
1988 assert(data);
1989
1990 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
1991 if (r == -ENOMEM)
1992 return log_oom();
1993 if (r < 0) {
1994 log_syntax(unit, LOG_WARNING, filename, line, r,
1995 "Failed to allocate route, ignoring assignment: %m");
1996 return 0;
1997 }
323d9329 1998
fef160b5 1999 r = safe_atou32(rvalue, &k);
f205a92a 2000 if (r < 0) {
d96edb2c 2001 log_syntax(unit, LOG_WARNING, filename, line, r,
f205a92a
YW
2002 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
2003 return 0;
2004 }
fef160b5 2005 if (k >= 1024) {
d96edb2c 2006 log_syntax(unit, LOG_WARNING, filename, line, 0,
f205a92a 2007 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
323d9329
SS
2008 return 0;
2009 }
2010
2011 if (streq(lvalue, "InitialCongestionWindow"))
2012 n->initcwnd = k;
2013 else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
2014 n->initrwnd = k;
f205a92a
YW
2015 else
2016 assert_not_reached("Invalid TCP window type.");
323d9329 2017
aff44301 2018 TAKE_PTR(n);
323d9329
SS
2019 return 0;
2020}
09f5dfad 2021
cea79e66
SS
2022int config_parse_route_mtu(
2023 const char *unit,
2024 const char *filename,
2025 unsigned line,
2026 const char *section,
2027 unsigned section_line,
2028 const char *lvalue,
2029 int ltype,
2030 const char *rvalue,
2031 void *data,
2032 void *userdata) {
2033
2034 Network *network = userdata;
fcbf4cb7 2035 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
cea79e66
SS
2036 int r;
2037
2038 assert(filename);
2039 assert(section);
2040 assert(lvalue);
2041 assert(rvalue);
2042 assert(data);
2043
2044 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
2045 if (r == -ENOMEM)
2046 return log_oom();
2047 if (r < 0) {
2048 log_syntax(unit, LOG_WARNING, filename, line, r,
2049 "Failed to allocate route, ignoring assignment: %m");
2050 return 0;
2051 }
cea79e66
SS
2052
2053 r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &n->mtu, userdata);
2054 if (r < 0)
2055 return r;
2056
aff44301 2057 TAKE_PTR(n);
cea79e66
SS
2058 return 0;
2059}
fcbf4cb7 2060
6ff5cc6b
YW
2061int config_parse_multipath_route(
2062 const char *unit,
2063 const char *filename,
2064 unsigned line,
2065 const char *section,
2066 unsigned section_line,
2067 const char *lvalue,
2068 int ltype,
2069 const char *rvalue,
2070 void *data,
2071 void *userdata) {
2072
2073 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2074 _cleanup_free_ char *word = NULL, *buf = NULL;
2075 _cleanup_free_ MultipathRoute *m = NULL;
2076 Network *network = userdata;
2077 const char *p, *ip, *dev;
2078 union in_addr_union a;
2079 int family, r;
2080
2081 assert(filename);
2082 assert(section);
2083 assert(lvalue);
2084 assert(rvalue);
2085 assert(data);
2086
2087 r = route_new_static(network, filename, section_line, &n);
d96edb2c
YW
2088 if (r == -ENOMEM)
2089 return log_oom();
2090 if (r < 0) {
2091 log_syntax(unit, LOG_WARNING, filename, line, r,
2092 "Failed to allocate route, ignoring assignment: %m");
2093 return 0;
2094 }
6ff5cc6b
YW
2095
2096 if (isempty(rvalue)) {
2097 n->multipath_routes = ordered_set_free_free(n->multipath_routes);
2098 return 0;
2099 }
2100
2101 m = new0(MultipathRoute, 1);
2102 if (!m)
2103 return log_oom();
2104
2105 p = rvalue;
2106 r = extract_first_word(&p, &word, NULL, 0);
2107 if (r == -ENOMEM)
2108 return log_oom();
2109 if (r <= 0) {
d96edb2c 2110 log_syntax(unit, LOG_WARNING, filename, line, r,
6ff5cc6b
YW
2111 "Invalid multipath route option, ignoring assignment: %s", rvalue);
2112 return 0;
2113 }
2114
2115 dev = strchr(word, '@');
2116 if (dev) {
2117 buf = strndup(word, dev - word);
2118 if (!buf)
2119 return log_oom();
2120 ip = buf;
2121 dev++;
2122 } else
2123 ip = word;
2124
2125 r = in_addr_from_string_auto(ip, &family, &a);
2126 if (r < 0) {
d96edb2c 2127 log_syntax(unit, LOG_WARNING, filename, line, r,
6ff5cc6b
YW
2128 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue);
2129 return 0;
2130 }
2131 m->gateway.address = a;
2132 m->gateway.family = family;
2133
2134 if (dev) {
d308bb99 2135 r = resolve_interface(NULL, dev);
6ff5cc6b 2136 if (r < 0) {
d96edb2c 2137 log_syntax(unit, LOG_WARNING, filename, line, r,
6ff5cc6b
YW
2138 "Invalid interface name or index, ignoring assignment: %s", dev);
2139 return 0;
2140 }
597da51b 2141 m->ifindex = r;
6ff5cc6b
YW
2142 }
2143
2144 if (!isempty(p)) {
2145 r = safe_atou32(p, &m->weight);
2146 if (r < 0) {
d96edb2c 2147 log_syntax(unit, LOG_WARNING, filename, line, r,
6ff5cc6b
YW
2148 "Invalid multipath route weight, ignoring assignment: %s", p);
2149 return 0;
2150 }
2151 if (m->weight == 0 || m->weight > 256) {
d96edb2c 2152 log_syntax(unit, LOG_WARNING, filename, line, 0,
6ff5cc6b
YW
2153 "Invalid multipath route weight, ignoring assignment: %s", p);
2154 return 0;
2155 }
2156 }
2157
2158 r = ordered_set_ensure_allocated(&n->multipath_routes, NULL);
2159 if (r < 0)
2160 return log_oom();
2161
2162 r = ordered_set_put(n->multipath_routes, m);
2163 if (r < 0) {
d96edb2c 2164 log_syntax(unit, LOG_WARNING, filename, line, r,
6ff5cc6b
YW
2165 "Failed to store multipath route, ignoring assignment: %m");
2166 return 0;
2167 }
2168
2169 TAKE_PTR(m);
2170 TAKE_PTR(n);
2171 return 0;
2172}
2173
d9940a3f 2174static int route_section_verify(Route *route, Network *network) {
fcbf4cb7
YW
2175 if (section_is_invalid(route->section))
2176 return -EINVAL;
2177
2178 if (route->family == AF_UNSPEC) {
2179 assert(route->section);
2180
2181 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
2182 "%s: Route section without Gateway=, Destination=, Source=, "
2183 "or PreferredSource= field configured. "
2184 "Ignoring [Route] section from line %u.",
2185 route->section->filename, route->section->line);
2186 }
2187
c0d48bc5
YW
2188 if (!route->table_set && network->vrf) {
2189 route->table = VRF(network->vrf)->table;
2190 route->table_set = true;
2191 }
2192
f5c38922
YW
2193 if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
2194 route->table = RT_TABLE_LOCAL;
2195
2196 if (!route->scope_set && route->family != AF_INET6) {
2197 if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
2198 route->scope = RT_SCOPE_HOST;
2199 else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
2200 route->scope = RT_SCOPE_LINK;
94d6e299
YW
2201 }
2202
9cd9fc8f 2203 if (ordered_hashmap_isempty(network->addresses_by_section) &&
fcbf4cb7
YW
2204 in_addr_is_null(route->family, &route->gw) == 0 &&
2205 route->gateway_onlink < 0) {
2206 log_warning("%s: Gateway= without static address configured. "
2207 "Enabling GatewayOnLink= option.",
2208 network->filename);
2209 route->gateway_onlink = true;
2210 }
2211
2212 return 0;
2213}
d9940a3f 2214
13ffa39f 2215void network_drop_invalid_routes(Network *network) {
2a54a044 2216 Route *route;
d9940a3f
YW
2217
2218 assert(network);
2219
2a54a044 2220 HASHMAP_FOREACH(route, network->routes_by_section)
d9940a3f
YW
2221 if (route_section_verify(route, network) < 0)
2222 route_free(route);
2223}