]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-route.c
Merge pull request #30513 from rpigott/resolved-ede
[thirdparty/systemd.git] / src / network / networkd-route.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <linux/icmpv6.h>
4 #include <linux/ipv6_route.h>
5 #include <linux/nexthop.h>
6
7 #include "alloc-util.h"
8 #include "event-util.h"
9 #include "netlink-util.h"
10 #include "networkd-address.h"
11 #include "networkd-ipv4ll.h"
12 #include "networkd-manager.h"
13 #include "networkd-network.h"
14 #include "networkd-nexthop.h"
15 #include "networkd-queue.h"
16 #include "networkd-route-util.h"
17 #include "networkd-route.h"
18 #include "parse-util.h"
19 #include "string-util.h"
20 #include "strv.h"
21 #include "vrf.h"
22 #include "wireguard.h"
23
24 int route_new(Route **ret) {
25 _cleanup_(route_freep) Route *route = NULL;
26
27 route = new(Route, 1);
28 if (!route)
29 return -ENOMEM;
30
31 *route = (Route) {
32 .family = AF_UNSPEC,
33 .scope = RT_SCOPE_UNIVERSE,
34 .protocol = RTPROT_UNSPEC,
35 .type = RTN_UNICAST,
36 .table = RT_TABLE_MAIN,
37 .lifetime_usec = USEC_INFINITY,
38 .quickack = -1,
39 .fast_open_no_cookie = -1,
40 .gateway_onlink = -1,
41 };
42
43 *ret = TAKE_PTR(route);
44
45 return 0;
46 }
47
48 static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
49 _cleanup_(config_section_freep) ConfigSection *n = NULL;
50 _cleanup_(route_freep) Route *route = NULL;
51 int r;
52
53 assert(network);
54 assert(ret);
55 assert(filename);
56 assert(section_line > 0);
57
58 r = config_section_new(filename, section_line, &n);
59 if (r < 0)
60 return r;
61
62 route = hashmap_get(network->routes_by_section, n);
63 if (route) {
64 *ret = TAKE_PTR(route);
65 return 0;
66 }
67
68 if (hashmap_size(network->routes_by_section) >= routes_max())
69 return -E2BIG;
70
71 r = route_new(&route);
72 if (r < 0)
73 return r;
74
75 route->protocol = RTPROT_STATIC;
76 route->network = network;
77 route->section = TAKE_PTR(n);
78 route->source = NETWORK_CONFIG_SOURCE_STATIC;
79
80 r = hashmap_ensure_put(&network->routes_by_section, &config_section_hash_ops, route->section, route);
81 if (r < 0)
82 return r;
83
84 *ret = TAKE_PTR(route);
85 return 0;
86 }
87
88 Route *route_free(Route *route) {
89 if (!route)
90 return NULL;
91
92 if (route->network) {
93 assert(route->section);
94 hashmap_remove(route->network->routes_by_section, route->section);
95 }
96
97 config_section_free(route->section);
98
99 if (route->link)
100 set_remove(route->link->routes, route);
101
102 if (route->manager)
103 set_remove(route->manager->routes, route);
104
105 ordered_set_free_with_destructor(route->multipath_routes, multipath_route_free);
106
107 sd_event_source_disable_unref(route->expire);
108
109 free(route->tcp_congestion_control_algo);
110
111 return mfree(route);
112 }
113
114 static void route_hash_func(const Route *route, struct siphash *state) {
115 assert(route);
116
117 siphash24_compress_typesafe(route->family, state);
118
119 switch (route->family) {
120 case AF_INET:
121 case AF_INET6:
122 siphash24_compress_typesafe(route->dst_prefixlen, state);
123 in_addr_hash_func(&route->dst, route->family, state);
124
125 siphash24_compress_typesafe(route->src_prefixlen, state);
126 in_addr_hash_func(&route->src, route->family, state);
127
128 siphash24_compress_typesafe(route->gw_family, state);
129 if (IN_SET(route->gw_family, AF_INET, AF_INET6)) {
130 in_addr_hash_func(&route->gw, route->gw_family, state);
131 siphash24_compress_typesafe(route->gw_weight, state);
132 }
133
134 in_addr_hash_func(&route->prefsrc, route->family, state);
135
136 siphash24_compress_typesafe(route->tos, state);
137 siphash24_compress_typesafe(route->priority, state);
138 siphash24_compress_typesafe(route->table, state);
139 siphash24_compress_typesafe(route->protocol, state);
140 siphash24_compress_typesafe(route->scope, state);
141 siphash24_compress_typesafe(route->type, state);
142
143 siphash24_compress_typesafe(route->initcwnd, state);
144 siphash24_compress_typesafe(route->initrwnd, state);
145
146 siphash24_compress_typesafe(route->advmss, state);
147 siphash24_compress_typesafe(route->nexthop_id, state);
148
149 break;
150 default:
151 /* treat any other address family as AF_UNSPEC */
152 break;
153 }
154 }
155
156 static int route_compare_func(const Route *a, const Route *b) {
157 int r;
158
159 r = CMP(a->family, b->family);
160 if (r != 0)
161 return r;
162
163 switch (a->family) {
164 case AF_INET:
165 case AF_INET6:
166 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
167 if (r != 0)
168 return r;
169
170 r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
171 if (r != 0)
172 return r;
173
174 r = CMP(a->src_prefixlen, b->src_prefixlen);
175 if (r != 0)
176 return r;
177
178 r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
179 if (r != 0)
180 return r;
181
182 r = CMP(a->gw_family, b->gw_family);
183 if (r != 0)
184 return r;
185
186 if (IN_SET(a->gw_family, AF_INET, AF_INET6)) {
187 r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
188 if (r != 0)
189 return r;
190
191 r = CMP(a->gw_weight, b->gw_weight);
192 if (r != 0)
193 return r;
194 }
195
196 r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
197 if (r != 0)
198 return r;
199
200 r = CMP(a->tos, b->tos);
201 if (r != 0)
202 return r;
203
204 r = CMP(a->priority, b->priority);
205 if (r != 0)
206 return r;
207
208 r = CMP(a->table, b->table);
209 if (r != 0)
210 return r;
211
212 r = CMP(a->protocol, b->protocol);
213 if (r != 0)
214 return r;
215
216 r = CMP(a->scope, b->scope);
217 if (r != 0)
218 return r;
219
220 r = CMP(a->type, b->type);
221 if (r != 0)
222 return r;
223
224 r = CMP(a->initcwnd, b->initcwnd);
225 if (r != 0)
226 return r;
227
228 r = CMP(a->initrwnd, b->initrwnd);
229 if (r != 0)
230 return r;
231
232 r = CMP(a->advmss, b->advmss);
233 if (r != 0)
234 return r;
235
236 r = CMP(a->nexthop_id, b->nexthop_id);
237 if (r != 0)
238 return r;
239
240 return 0;
241 default:
242 /* treat any other address family as AF_UNSPEC */
243 return 0;
244 }
245 }
246
247 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
248 route_hash_ops,
249 Route,
250 route_hash_func,
251 route_compare_func,
252 route_free);
253
254 static bool route_type_is_reject(const Route *route) {
255 assert(route);
256
257 return IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW);
258 }
259
260 static bool route_needs_convert(const Route *route) {
261 assert(route);
262
263 return route->nexthop_id > 0 || !ordered_set_isempty(route->multipath_routes);
264 }
265
266 static int route_add(Manager *manager, Link *link, Route *route) {
267 int r;
268
269 assert(route);
270
271 if (route_type_is_reject(route)) {
272 assert(manager);
273
274 r = set_ensure_put(&manager->routes, &route_hash_ops, route);
275 if (r < 0)
276 return r;
277 if (r == 0)
278 return -EEXIST;
279
280 route->manager = manager;
281 } else {
282 assert(link);
283
284 r = set_ensure_put(&link->routes, &route_hash_ops, route);
285 if (r < 0)
286 return r;
287 if (r == 0)
288 return -EEXIST;
289
290 route->link = link;
291 }
292
293 return 0;
294 }
295
296 int route_get(Manager *manager, Link *link, const Route *in, Route **ret) {
297 Route *route;
298
299 assert(in);
300
301 if (route_type_is_reject(in)) {
302 if (!manager)
303 return -ENOENT;
304
305 route = set_get(manager->routes, in);
306 } else {
307 if (!link)
308 return -ENOENT;
309
310 route = set_get(link->routes, in);
311 }
312 if (!route)
313 return -ENOENT;
314
315 if (ret)
316 *ret = route;
317
318 return 0;
319 }
320
321 int route_dup(const Route *src, Route **ret) {
322 _cleanup_(route_freep) Route *dest = NULL;
323 int r;
324
325 /* This does not copy mulipath routes. */
326
327 assert(src);
328 assert(ret);
329
330 dest = newdup(Route, src, 1);
331 if (!dest)
332 return -ENOMEM;
333
334 /* Unset all pointers */
335 dest->network = NULL;
336 dest->section = NULL;
337 dest->link = NULL;
338 dest->manager = NULL;
339 dest->multipath_routes = NULL;
340 dest->expire = NULL;
341 dest->tcp_congestion_control_algo = NULL;
342
343 r = free_and_strdup(&dest->tcp_congestion_control_algo, src->tcp_congestion_control_algo);
344 if (r < 0)
345 return r;
346
347 *ret = TAKE_PTR(dest);
348 return 0;
349 }
350
351 static void route_apply_nexthop(Route *route, const NextHop *nh, uint8_t nh_weight) {
352 assert(route);
353 assert(nh);
354 assert(hashmap_isempty(nh->group));
355
356 route->gw_family = nh->family;
357 route->gw = nh->gw;
358
359 if (nh_weight != UINT8_MAX)
360 route->gw_weight = nh_weight;
361
362 if (nh->blackhole)
363 route->type = RTN_BLACKHOLE;
364 }
365
366 static void route_apply_multipath_route(Route *route, const MultipathRoute *m) {
367 assert(route);
368 assert(m);
369
370 route->gw_family = m->gateway.family;
371 route->gw = m->gateway.address;
372 route->gw_weight = m->weight;
373 }
374
375 static int multipath_route_get_link(Manager *manager, const MultipathRoute *m, Link **ret) {
376 int r;
377
378 assert(manager);
379 assert(m);
380
381 if (m->ifname) {
382 r = link_get_by_name(manager, m->ifname, ret);
383 return r < 0 ? r : 1;
384
385 } else if (m->ifindex > 0) { /* Always ignore ifindex if ifname is set. */
386 r = link_get_by_index(manager, m->ifindex, ret);
387 return r < 0 ? r : 1;
388 }
389
390 if (ret)
391 *ret = NULL;
392 return 0;
393 }
394
395 typedef struct ConvertedRoutes {
396 size_t n;
397 Route **routes;
398 Link **links;
399 } ConvertedRoutes;
400
401 static ConvertedRoutes *converted_routes_free(ConvertedRoutes *c) {
402 if (!c)
403 return NULL;
404
405 for (size_t i = 0; i < c->n; i++)
406 route_free(c->routes[i]);
407
408 free(c->routes);
409 free(c->links);
410
411 return mfree(c);
412 }
413
414 DEFINE_TRIVIAL_CLEANUP_FUNC(ConvertedRoutes*, converted_routes_free);
415
416 static int converted_routes_new(size_t n, ConvertedRoutes **ret) {
417 _cleanup_(converted_routes_freep) ConvertedRoutes *c = NULL;
418 _cleanup_free_ Route **routes = NULL;
419 _cleanup_free_ Link **links = NULL;
420
421 assert(n > 0);
422 assert(ret);
423
424 routes = new0(Route*, n);
425 if (!routes)
426 return -ENOMEM;
427
428 links = new0(Link*, n);
429 if (!links)
430 return -ENOMEM;
431
432 c = new(ConvertedRoutes, 1);
433 if (!c)
434 return -ENOMEM;
435
436 *c = (ConvertedRoutes) {
437 .n = n,
438 .routes = TAKE_PTR(routes),
439 .links = TAKE_PTR(links),
440 };
441
442 *ret = TAKE_PTR(c);
443 return 0;
444 }
445
446 static int route_convert(Manager *manager, const Route *route, ConvertedRoutes **ret) {
447 _cleanup_(converted_routes_freep) ConvertedRoutes *c = NULL;
448 int r;
449
450 assert(manager);
451 assert(route);
452 assert(ret);
453
454 if (!route_needs_convert(route)) {
455 *ret = NULL;
456 return 0;
457 }
458
459 if (route->nexthop_id > 0) {
460 struct nexthop_grp *nhg;
461 NextHop *nh;
462
463 r = nexthop_get_by_id(manager, route->nexthop_id, &nh);
464 if (r < 0)
465 return r;
466
467 if (hashmap_isempty(nh->group)) {
468 r = converted_routes_new(1, &c);
469 if (r < 0)
470 return r;
471
472 r = route_dup(route, &c->routes[0]);
473 if (r < 0)
474 return r;
475
476 route_apply_nexthop(c->routes[0], nh, UINT8_MAX);
477 (void) link_get_by_index(manager, nh->ifindex, c->links);
478
479 *ret = TAKE_PTR(c);
480 return 1;
481 }
482
483 r = converted_routes_new(hashmap_size(nh->group), &c);
484 if (r < 0)
485 return r;
486
487 size_t i = 0;
488 HASHMAP_FOREACH(nhg, nh->group) {
489 NextHop *h;
490
491 r = nexthop_get_by_id(manager, nhg->id, &h);
492 if (r < 0)
493 return r;
494
495 r = route_dup(route, &c->routes[i]);
496 if (r < 0)
497 return r;
498
499 route_apply_nexthop(c->routes[i], h, nhg->weight);
500 (void) link_get_by_index(manager, h->ifindex, c->links + i);
501
502 i++;
503 }
504
505 *ret = TAKE_PTR(c);
506 return 1;
507
508 }
509
510 assert(!ordered_set_isempty(route->multipath_routes));
511
512 r = converted_routes_new(ordered_set_size(route->multipath_routes), &c);
513 if (r < 0)
514 return r;
515
516 size_t i = 0;
517 MultipathRoute *m;
518 ORDERED_SET_FOREACH(m, route->multipath_routes) {
519 r = route_dup(route, &c->routes[i]);
520 if (r < 0)
521 return r;
522
523 route_apply_multipath_route(c->routes[i], m);
524
525 r = multipath_route_get_link(manager, m, &c->links[i]);
526 if (r < 0)
527 return r;
528
529 i++;
530 }
531
532 *ret = TAKE_PTR(c);
533 return 1;
534 }
535
536 void link_mark_routes(Link *link, NetworkConfigSource source) {
537 Route *route;
538
539 assert(link);
540
541 SET_FOREACH(route, link->routes) {
542 if (route->source != source)
543 continue;
544
545 route_mark(route);
546 }
547 }
548
549 static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *manager) {
550 _cleanup_free_ char *state = NULL, *gw_alloc = NULL, *prefsrc = NULL,
551 *table = NULL, *scope = NULL, *proto = NULL, *flags = NULL;
552 const char *gw = NULL, *dst, *src;
553
554 assert(route);
555 assert(str);
556 assert(manager);
557
558 /* link may be NULL. */
559
560 if (!DEBUG_LOGGING)
561 return;
562
563 (void) network_config_state_to_string_alloc(route->state, &state);
564
565 dst = in_addr_is_set(route->family, &route->dst) || route->dst_prefixlen > 0 ?
566 IN_ADDR_PREFIX_TO_STRING(route->family, &route->dst, route->dst_prefixlen) : NULL;
567 src = in_addr_is_set(route->family, &route->src) || route->src_prefixlen > 0 ?
568 IN_ADDR_PREFIX_TO_STRING(route->family, &route->src, route->src_prefixlen) : NULL;
569
570 if (in_addr_is_set(route->gw_family, &route->gw)) {
571 (void) in_addr_to_string(route->gw_family, &route->gw, &gw_alloc);
572 gw = gw_alloc;
573 } else if (route->gateway_from_dhcp_or_ra) {
574 if (route->gw_family == AF_INET)
575 gw = "_dhcp4";
576 else if (route->gw_family == AF_INET6)
577 gw = "_ipv6ra";
578 } else {
579 MultipathRoute *m;
580
581 ORDERED_SET_FOREACH(m, route->multipath_routes) {
582 _cleanup_free_ char *buf = NULL;
583 union in_addr_union a = m->gateway.address;
584
585 (void) in_addr_to_string(m->gateway.family, &a, &buf);
586 (void) strextend_with_separator(&gw_alloc, ",", strna(buf));
587 if (m->ifname)
588 (void) strextend(&gw_alloc, "@", m->ifname);
589 else if (m->ifindex > 0)
590 (void) strextendf(&gw_alloc, "@%i", m->ifindex);
591 /* See comments in config_parse_multipath_route(). */
592 (void) strextendf(&gw_alloc, ":%"PRIu32, m->weight + 1);
593 }
594 gw = gw_alloc;
595 }
596 if (in_addr_is_set(route->family, &route->prefsrc))
597 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
598 (void) route_scope_to_string_alloc(route->scope, &scope);
599 (void) manager_get_route_table_to_string(manager, route->table, /* append_num = */ true, &table);
600 (void) route_protocol_full_to_string_alloc(route->protocol, &proto);
601 (void) route_flags_to_string_alloc(route->flags, &flags);
602
603 log_link_debug(link,
604 "%s %s route (%s): dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, "
605 "proto: %s, type: %s, nexthop: %"PRIu32", priority: %"PRIu32", flags: %s",
606 str, strna(network_config_source_to_string(route->source)), strna(state),
607 strna(dst), strna(src), strna(gw), strna(prefsrc),
608 strna(scope), strna(table), strna(proto),
609 strna(route_type_to_string(route->type)),
610 route->nexthop_id, route->priority, strna(flags));
611 }
612
613 static int route_set_netlink_message(const Route *route, sd_netlink_message *req, Link *link) {
614 int r;
615
616 assert(route);
617 assert(req);
618
619 /* link may be NULL */
620
621 if (in_addr_is_set(route->gw_family, &route->gw) && route->nexthop_id == 0) {
622 if (route->gw_family == route->family) {
623 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->gw_family, &route->gw);
624 if (r < 0)
625 return r;
626 } else {
627 RouteVia rtvia = {
628 .family = route->gw_family,
629 .address = route->gw,
630 };
631
632 r = sd_netlink_message_append_data(req, RTA_VIA, &rtvia, sizeof(rtvia));
633 if (r < 0)
634 return r;
635 }
636 }
637
638 if (route->dst_prefixlen > 0) {
639 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
640 if (r < 0)
641 return r;
642
643 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
644 if (r < 0)
645 return r;
646 }
647
648 if (route->src_prefixlen > 0) {
649 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
650 if (r < 0)
651 return r;
652
653 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
654 if (r < 0)
655 return r;
656 }
657
658 if (in_addr_is_set(route->family, &route->prefsrc)) {
659 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
660 if (r < 0)
661 return r;
662 }
663
664 r = sd_rtnl_message_route_set_scope(req, route->scope);
665 if (r < 0)
666 return r;
667
668 r = sd_rtnl_message_route_set_flags(req, route->flags & RTNH_F_ONLINK);
669 if (r < 0)
670 return r;
671
672 if (route->table < 256) {
673 r = sd_rtnl_message_route_set_table(req, route->table);
674 if (r < 0)
675 return r;
676 } else {
677 r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
678 if (r < 0)
679 return r;
680
681 /* Table attribute to allow more than 256. */
682 r = sd_netlink_message_append_u32(req, RTA_TABLE, route->table);
683 if (r < 0)
684 return r;
685 }
686
687 if (!route_type_is_reject(route) &&
688 route->nexthop_id == 0 &&
689 ordered_set_isempty(route->multipath_routes)) {
690 assert(link); /* Those routes must be attached to a specific link */
691
692 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
693 if (r < 0)
694 return r;
695 }
696
697 if (route->nexthop_id > 0) {
698 r = sd_netlink_message_append_u32(req, RTA_NH_ID, route->nexthop_id);
699 if (r < 0)
700 return r;
701 }
702
703 r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
704 if (r < 0)
705 return r;
706
707 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
708 if (r < 0)
709 return r;
710
711 return 0;
712 }
713
714 static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
715 int r;
716
717 assert(m);
718
719 /* link may be NULL. */
720
721 if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
722 return 0;
723
724 r = sd_netlink_message_get_errno(m);
725 if (r < 0 && r != -ESRCH)
726 log_link_message_warning_errno(link, m, r, "Could not drop route, ignoring");
727
728 return 1;
729 }
730
731 int route_remove(Route *route) {
732 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
733 unsigned char type;
734 Manager *manager;
735 Link *link;
736 int r;
737
738 assert(route);
739 assert(route->manager || (route->link && route->link->manager));
740 assert(IN_SET(route->family, AF_INET, AF_INET6));
741
742 link = route->link;
743 manager = route->manager ?: link->manager;
744
745 log_route_debug(route, "Removing", link, manager);
746
747 r = sd_rtnl_message_new_route(manager->rtnl, &req,
748 RTM_DELROUTE, route->family,
749 route->protocol);
750 if (r < 0)
751 return log_link_error_errno(link, r, "Could not create netlink message: %m");
752
753 if (route->family == AF_INET && route->nexthop_id > 0 && route->type == RTN_BLACKHOLE)
754 /* When IPv4 route has nexthop id and the nexthop type is blackhole, even though kernel
755 * sends RTM_NEWROUTE netlink message with blackhole type, kernel's internal route type
756 * fib_rt_info::type may not be blackhole. Thus, we cannot know the internal value.
757 * Moreover, on route removal, the matching is done with the hidden value if we set
758 * non-zero type in RTM_DELROUTE message. Note, sd_rtnl_message_new_route() sets
759 * RTN_UNICAST by default. So, we need to clear the type here. */
760 type = RTN_UNSPEC;
761 else
762 type = route->type;
763
764 r = sd_rtnl_message_route_set_type(req, type);
765 if (r < 0)
766 return log_link_error_errno(link, r, "Could not set route type: %m");
767
768 r = route_set_netlink_message(route, req, link);
769 if (r < 0)
770 return log_error_errno(r, "Could not fill netlink message: %m");
771
772 r = netlink_call_async(manager->rtnl, NULL, req, route_remove_handler,
773 link ? link_netlink_destroy_callback : NULL, link);
774 if (r < 0)
775 return log_link_error_errno(link, r, "Could not send netlink message: %m");
776
777 link_ref(link);
778
779 route_enter_removing(route);
780 return 0;
781 }
782
783 int route_remove_and_drop(Route *route) {
784 if (!route)
785 return 0;
786
787 route_cancel_request(route, NULL);
788
789 if (route_exists(route))
790 return route_remove(route);
791
792 if (route->state == 0)
793 route_free(route);
794
795 return 0;
796 }
797
798 static void manager_mark_routes(Manager *manager, bool foreign, const Link *except) {
799 Route *route;
800 Link *link;
801 int r;
802
803 assert(manager);
804
805 /* First, mark all routes. */
806 SET_FOREACH(route, manager->routes) {
807 /* Do not touch routes managed by the kernel. */
808 if (route->protocol == RTPROT_KERNEL)
809 continue;
810
811 /* When 'foreign' is true, mark only foreign routes, and vice versa. */
812 if (foreign != (route->source == NETWORK_CONFIG_SOURCE_FOREIGN))
813 continue;
814
815 /* Do not touch dynamic routes. They will removed by dhcp_pd_prefix_lost() */
816 if (IN_SET(route->source, NETWORK_CONFIG_SOURCE_DHCP4, NETWORK_CONFIG_SOURCE_DHCP6))
817 continue;
818
819 /* Ignore routes not assigned yet or already removed. */
820 if (!route_exists(route))
821 continue;
822
823 route_mark(route);
824 }
825
826 /* Then, unmark all routes requested by active links. */
827 HASHMAP_FOREACH(link, manager->links_by_index) {
828 if (link == except)
829 continue;
830
831 if (!link->network)
832 continue;
833
834 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
835 continue;
836
837 HASHMAP_FOREACH(route, link->network->routes_by_section) {
838 _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
839 Route *existing;
840
841 r = route_convert(manager, route, &converted);
842 if (r < 0)
843 continue;
844 if (r == 0) {
845 if (route_get(manager, NULL, route, &existing) >= 0)
846 route_unmark(existing);
847 continue;
848 }
849
850 for (size_t i = 0; i < converted->n; i++)
851 if (route_get(manager, NULL, converted->routes[i], &existing) >= 0)
852 route_unmark(existing);
853 }
854 }
855 }
856
857 static int manager_drop_marked_routes(Manager *manager) {
858 Route *route;
859 int r = 0;
860
861 assert(manager);
862
863 SET_FOREACH(route, manager->routes) {
864 if (!route_is_marked(route))
865 continue;
866
867 RET_GATHER(r, route_remove(route));
868 }
869
870 return r;
871 }
872
873 static bool route_by_kernel(const Route *route) {
874 assert(route);
875
876 if (route->protocol == RTPROT_KERNEL)
877 return true;
878
879 /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
880 * multicast with RTPROT_BOOT. Do not touch it. */
881 if (route->protocol == RTPROT_BOOT &&
882 route->family == AF_INET6 &&
883 route->dst_prefixlen == 8 &&
884 in6_addr_equal(&route->dst.in6, & (struct in6_addr) {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}}))
885 return true;
886
887 return false;
888 }
889
890 static void link_unmark_wireguard_routes(Link *link) {
891 assert(link);
892
893 if (!link->netdev || link->netdev->kind != NETDEV_KIND_WIREGUARD)
894 return;
895
896 Route *route, *existing;
897 Wireguard *w = WIREGUARD(link->netdev);
898
899 SET_FOREACH(route, w->routes)
900 if (route_get(NULL, link, route, &existing) >= 0)
901 route_unmark(existing);
902 }
903
904 int link_drop_foreign_routes(Link *link) {
905 Route *route;
906 int r;
907
908 assert(link);
909 assert(link->manager);
910 assert(link->network);
911
912 SET_FOREACH(route, link->routes) {
913 /* do not touch routes managed by the kernel */
914 if (route_by_kernel(route))
915 continue;
916
917 /* Do not remove routes we configured. */
918 if (route->source != NETWORK_CONFIG_SOURCE_FOREIGN)
919 continue;
920
921 /* Ignore routes not assigned yet or already removed. */
922 if (!route_exists(route))
923 continue;
924
925 if (route->protocol == RTPROT_STATIC &&
926 FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
927 continue;
928
929 if (route->protocol == RTPROT_DHCP &&
930 FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
931 continue;
932
933 route_mark(route);
934 }
935
936 HASHMAP_FOREACH(route, link->network->routes_by_section) {
937 _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
938 Route *existing;
939
940 r = route_convert(link->manager, route, &converted);
941 if (r < 0)
942 continue;
943 if (r == 0) {
944 if (route_get(NULL, link, route, &existing) >= 0)
945 route_unmark(existing);
946 continue;
947 }
948
949 for (size_t i = 0; i < converted->n; i++)
950 if (route_get(NULL, link, converted->routes[i], &existing) >= 0)
951 route_unmark(existing);
952 }
953
954 link_unmark_wireguard_routes(link);
955
956 r = 0;
957 SET_FOREACH(route, link->routes) {
958 if (!route_is_marked(route))
959 continue;
960
961 RET_GATHER(r, route_remove(route));
962 }
963
964 manager_mark_routes(link->manager, /* foreign = */ true, NULL);
965
966 return RET_GATHER(r, manager_drop_marked_routes(link->manager));
967 }
968
969 int link_drop_managed_routes(Link *link) {
970 Route *route;
971 int r = 0;
972
973 assert(link);
974
975 SET_FOREACH(route, link->routes) {
976 /* do not touch routes managed by the kernel */
977 if (route_by_kernel(route))
978 continue;
979
980 /* Do not touch routes managed by kernel or other tools. */
981 if (route->source == NETWORK_CONFIG_SOURCE_FOREIGN)
982 continue;
983
984 if (!route_exists(route))
985 continue;
986
987 RET_GATHER(r, route_remove(route));
988 }
989
990 manager_mark_routes(link->manager, /* foreign = */ false, link);
991
992 return RET_GATHER(r, manager_drop_marked_routes(link->manager));
993 }
994
995 void link_foreignize_routes(Link *link) {
996 Route *route;
997
998 assert(link);
999
1000 SET_FOREACH(route, link->routes)
1001 route->source = NETWORK_CONFIG_SOURCE_FOREIGN;
1002
1003 manager_mark_routes(link->manager, /* foreign = */ false, link);
1004
1005 SET_FOREACH(route, link->manager->routes) {
1006 if (!route_is_marked(route))
1007 continue;
1008
1009 route->source = NETWORK_CONFIG_SOURCE_FOREIGN;
1010 }
1011 }
1012
1013 static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
1014 Route *route = ASSERT_PTR(userdata);
1015 Link *link;
1016 int r;
1017
1018 assert(route->manager || (route->link && route->link->manager));
1019
1020 link = route->link; /* This may be NULL. */
1021
1022 r = route_remove(route);
1023 if (r < 0) {
1024 log_link_warning_errno(link, r, "Could not remove route: %m");
1025 if (link)
1026 link_enter_failed(link);
1027 }
1028
1029 return 1;
1030 }
1031
1032 static int route_setup_timer(Route *route, const struct rta_cacheinfo *cacheinfo) {
1033 Manager *manager;
1034 int r;
1035
1036 assert(route);
1037 assert(route->manager || (route->link && route->link->manager));
1038
1039 manager = route->manager ?: route->link->manager;
1040
1041 if (route->lifetime_usec == USEC_INFINITY)
1042 return 0;
1043
1044 if (cacheinfo && cacheinfo->rta_expires != 0)
1045 /* Assume that non-zero rta_expires means kernel will handle the route expiration. */
1046 return 0;
1047
1048 r = event_reset_time(manager->event, &route->expire, CLOCK_BOOTTIME,
1049 route->lifetime_usec, 0, route_expire_handler, route, 0, "route-expiration", true);
1050 if (r < 0)
1051 return r;
1052
1053 return 1;
1054 }
1055
1056 static int append_nexthop_one(const Link *link, const Route *route, const MultipathRoute *m, struct rtattr **rta, size_t offset) {
1057 struct rtnexthop *rtnh;
1058 struct rtattr *new_rta;
1059 int r;
1060
1061 assert(route);
1062 assert(m);
1063 assert(rta);
1064 assert(*rta);
1065
1066 new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
1067 if (!new_rta)
1068 return -ENOMEM;
1069 *rta = new_rta;
1070
1071 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
1072 *rtnh = (struct rtnexthop) {
1073 .rtnh_len = sizeof(*rtnh),
1074 .rtnh_ifindex = m->ifindex > 0 ? m->ifindex : link->ifindex,
1075 .rtnh_hops = m->weight,
1076 };
1077
1078 (*rta)->rta_len += sizeof(struct rtnexthop);
1079
1080 if (route->family == m->gateway.family) {
1081 r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
1082 if (r < 0)
1083 goto clear;
1084 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
1085 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
1086 } else {
1087 r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
1088 if (r < 0)
1089 goto clear;
1090 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
1091 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
1092 }
1093
1094 return 0;
1095
1096 clear:
1097 (*rta)->rta_len -= sizeof(struct rtnexthop);
1098 return r;
1099 }
1100
1101 static int append_nexthops(const Link *link, const Route *route, sd_netlink_message *req) {
1102 _cleanup_free_ struct rtattr *rta = NULL;
1103 struct rtnexthop *rtnh;
1104 MultipathRoute *m;
1105 size_t offset;
1106 int r;
1107
1108 assert(link);
1109 assert(route);
1110 assert(req);
1111
1112 if (ordered_set_isempty(route->multipath_routes))
1113 return 0;
1114
1115 rta = new(struct rtattr, 1);
1116 if (!rta)
1117 return -ENOMEM;
1118
1119 *rta = (struct rtattr) {
1120 .rta_type = RTA_MULTIPATH,
1121 .rta_len = RTA_LENGTH(0),
1122 };
1123 offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
1124
1125 ORDERED_SET_FOREACH(m, route->multipath_routes) {
1126 r = append_nexthop_one(link, route, m, &rta, offset);
1127 if (r < 0)
1128 return r;
1129
1130 rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
1131 offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
1132 }
1133
1134 r = sd_netlink_message_append_data(req, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
1135 if (r < 0)
1136 return r;
1137
1138 return 0;
1139 }
1140
1141 int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg) {
1142 int r;
1143
1144 assert(m);
1145 assert(link);
1146 assert(error_msg);
1147
1148 r = sd_netlink_message_get_errno(m);
1149 if (r < 0 && r != -EEXIST) {
1150 log_link_message_warning_errno(link, m, r, "Could not set route");
1151 link_enter_failed(link);
1152 return 0;
1153 }
1154
1155 return 1;
1156 }
1157
1158 static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link, Request *req) {
1159 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
1160 int r;
1161
1162 assert(route);
1163 assert(IN_SET(route->family, AF_INET, AF_INET6));
1164 assert(link);
1165 assert(link->manager);
1166 assert(link->manager->rtnl);
1167 assert(link->ifindex > 0);
1168 assert(req);
1169
1170 log_route_debug(route, "Configuring", link, link->manager);
1171
1172 r = sd_rtnl_message_new_route(link->manager->rtnl, &m, RTM_NEWROUTE, route->family, route->protocol);
1173 if (r < 0)
1174 return r;
1175
1176 r = sd_rtnl_message_route_set_type(m, route->type);
1177 if (r < 0)
1178 return r;
1179
1180 r = route_set_netlink_message(route, m, link);
1181 if (r < 0)
1182 return r;
1183
1184 if (lifetime_sec != UINT32_MAX) {
1185 r = sd_netlink_message_append_u32(m, RTA_EXPIRES, lifetime_sec);
1186 if (r < 0)
1187 return r;
1188 }
1189
1190 r = sd_netlink_message_open_container(m, RTA_METRICS);
1191 if (r < 0)
1192 return r;
1193
1194 if (route->mtu > 0) {
1195 r = sd_netlink_message_append_u32(m, RTAX_MTU, route->mtu);
1196 if (r < 0)
1197 return r;
1198 }
1199
1200 if (route->initcwnd > 0) {
1201 r = sd_netlink_message_append_u32(m, RTAX_INITCWND, route->initcwnd);
1202 if (r < 0)
1203 return r;
1204 }
1205
1206 if (route->initrwnd > 0) {
1207 r = sd_netlink_message_append_u32(m, RTAX_INITRWND, route->initrwnd);
1208 if (r < 0)
1209 return r;
1210 }
1211
1212 if (route->quickack >= 0) {
1213 r = sd_netlink_message_append_u32(m, RTAX_QUICKACK, route->quickack);
1214 if (r < 0)
1215 return r;
1216 }
1217
1218 if (route->fast_open_no_cookie >= 0) {
1219 r = sd_netlink_message_append_u32(m, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
1220 if (r < 0)
1221 return r;
1222 }
1223
1224 if (route->advmss > 0) {
1225 r = sd_netlink_message_append_u32(m, RTAX_ADVMSS, route->advmss);
1226 if (r < 0)
1227 return r;
1228 }
1229
1230 if (!isempty(route->tcp_congestion_control_algo)) {
1231 r = sd_netlink_message_append_string(m, RTAX_CC_ALGO, route->tcp_congestion_control_algo);
1232 if (r < 0)
1233 return r;
1234 }
1235
1236 if (route->hop_limit > 0) {
1237 r = sd_netlink_message_append_u32(m, RTAX_HOPLIMIT, route->hop_limit);
1238 if (r < 0)
1239 return r;
1240 }
1241
1242 if (route->tcp_rto_usec > 0) {
1243 r = sd_netlink_message_append_u32(m, RTAX_RTO_MIN, DIV_ROUND_UP(route->tcp_rto_usec, USEC_PER_MSEC));
1244 if (r < 0)
1245 return r;
1246 }
1247
1248 r = sd_netlink_message_close_container(m);
1249 if (r < 0)
1250 return r;
1251
1252 if (!ordered_set_isempty(route->multipath_routes)) {
1253 assert(route->nexthop_id == 0);
1254 assert(!in_addr_is_set(route->gw_family, &route->gw));
1255
1256 r = append_nexthops(link, route, m);
1257 if (r < 0)
1258 return r;
1259 }
1260
1261 return request_call_netlink_async(link->manager->rtnl, m, req);
1262 }
1263
1264 static int route_is_ready_to_configure(const Route *route, Link *link) {
1265 int r;
1266
1267 assert(route);
1268 assert(link);
1269
1270 if (!link_is_ready_to_configure(link, false))
1271 return false;
1272
1273 if (set_size(link->routes) >= routes_max())
1274 return false;
1275
1276 if (route->nexthop_id > 0) {
1277 struct nexthop_grp *nhg;
1278 NextHop *nh;
1279
1280 if (nexthop_get_by_id(link->manager, route->nexthop_id, &nh) < 0)
1281 return false;
1282
1283 if (!nexthop_exists(nh))
1284 return false;
1285
1286 HASHMAP_FOREACH(nhg, nh->group) {
1287 NextHop *g;
1288
1289 if (nexthop_get_by_id(link->manager, nhg->id, &g) < 0)
1290 return false;
1291
1292 if (!nexthop_exists(g))
1293 return false;
1294 }
1295 }
1296
1297 if (in_addr_is_set(route->family, &route->prefsrc) > 0) {
1298 r = manager_has_address(link->manager, route->family, &route->prefsrc);
1299 if (r <= 0)
1300 return r;
1301 }
1302
1303 if (!gateway_is_ready(link, FLAGS_SET(route->flags, RTNH_F_ONLINK), route->gw_family, &route->gw))
1304 return false;
1305
1306 MultipathRoute *m;
1307 ORDERED_SET_FOREACH(m, route->multipath_routes) {
1308 union in_addr_union a = m->gateway.address;
1309 Link *l = NULL;
1310
1311 r = multipath_route_get_link(link->manager, m, &l);
1312 if (r < 0)
1313 return false;
1314 if (r > 0) {
1315 if (!link_is_ready_to_configure(l, /* allow_unmanaged = */ true) ||
1316 !link_has_carrier(l))
1317 return false;
1318
1319 m->ifindex = l->ifindex;
1320 }
1321
1322 if (!gateway_is_ready(l ?: link, FLAGS_SET(route->flags, RTNH_F_ONLINK), m->gateway.family, &a))
1323 return false;
1324 }
1325
1326 return true;
1327 }
1328
1329 static int route_process_request(Request *req, Link *link, Route *route) {
1330 _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
1331 int r;
1332
1333 assert(req);
1334 assert(link);
1335 assert(link->manager);
1336 assert(route);
1337
1338 r = route_is_ready_to_configure(route, link);
1339 if (r < 0)
1340 return log_link_warning_errno(link, r, "Failed to check if route is ready to configure: %m");
1341 if (r == 0)
1342 return 0;
1343
1344 if (route_needs_convert(route)) {
1345 r = route_convert(link->manager, route, &converted);
1346 if (r < 0)
1347 return log_link_warning_errno(link, r, "Failed to convert route: %m");
1348
1349 assert(r > 0);
1350 assert(converted);
1351
1352 for (size_t i = 0; i < converted->n; i++) {
1353 Route *existing;
1354
1355 if (route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) < 0) {
1356 _cleanup_(route_freep) Route *tmp = NULL;
1357
1358 r = route_dup(converted->routes[i], &tmp);
1359 if (r < 0)
1360 return log_oom();
1361
1362 r = route_add(link->manager, converted->links[i] ?: link, tmp);
1363 if (r < 0)
1364 return log_link_warning_errno(link, r, "Failed to add route: %m");
1365
1366 TAKE_PTR(tmp);
1367 } else {
1368 existing->source = converted->routes[i]->source;
1369 existing->provider = converted->routes[i]->provider;
1370 }
1371 }
1372 }
1373
1374 usec_t now_usec;
1375 assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
1376 uint32_t sec = usec_to_sec(route->lifetime_usec, now_usec);
1377 if (sec == 0) {
1378 log_link_debug(link, "Refuse to configure %s route with zero lifetime.",
1379 network_config_source_to_string(route->source));
1380
1381 if (converted)
1382 for (size_t i = 0; i < converted->n; i++) {
1383 Route *existing;
1384
1385 assert_se(route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) >= 0);
1386 route_cancel_requesting(existing);
1387 }
1388 else
1389 route_cancel_requesting(route);
1390
1391 return 1;
1392 }
1393
1394 r = route_configure(route, sec, link, req);
1395 if (r < 0)
1396 return log_link_warning_errno(link, r, "Failed to configure route: %m");
1397
1398 if (converted)
1399 for (size_t i = 0; i < converted->n; i++) {
1400 Route *existing;
1401
1402 assert_se(route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) >= 0);
1403 route_enter_configuring(existing);
1404 }
1405 else
1406 route_enter_configuring(route);
1407
1408 return 1;
1409 }
1410
1411 int link_request_route(
1412 Link *link,
1413 Route *route,
1414 bool consume_object,
1415 unsigned *message_counter,
1416 route_netlink_handler_t netlink_handler,
1417 Request **ret) {
1418
1419 Route *existing = NULL;
1420 int r;
1421
1422 assert(link);
1423 assert(link->manager);
1424 assert(route);
1425 assert(route->source != NETWORK_CONFIG_SOURCE_FOREIGN);
1426 assert(!route_needs_convert(route));
1427
1428 (void) route_get(link->manager, link, route, &existing);
1429
1430 if (route->lifetime_usec == 0) {
1431 if (consume_object)
1432 route_free(route);
1433
1434 /* The requested route is outdated. Let's remove it. */
1435 return route_remove_and_drop(existing);
1436 }
1437
1438 if (!existing) {
1439 _cleanup_(route_freep) Route *tmp = NULL;
1440
1441 if (consume_object)
1442 tmp = route;
1443 else {
1444 r = route_dup(route, &tmp);
1445 if (r < 0)
1446 return r;
1447 }
1448
1449 r = route_add(link->manager, link, tmp);
1450 if (r < 0)
1451 return r;
1452
1453 existing = TAKE_PTR(tmp);
1454 } else {
1455 existing->source = route->source;
1456 existing->provider = route->provider;
1457 existing->lifetime_usec = route->lifetime_usec;
1458 if (consume_object)
1459 route_free(route);
1460
1461 if (existing->expire) {
1462 /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE
1463 * message, so we need to update the timer here. */
1464 r = route_setup_timer(existing, NULL);
1465 if (r < 0)
1466 log_link_warning_errno(link, r, "Failed to update expiration timer for route, ignoring: %m");
1467 if (r > 0)
1468 log_route_debug(existing, "Updated expiration timer for", link, link->manager);
1469 }
1470 }
1471
1472 log_route_debug(existing, "Requesting", link, link->manager);
1473 r = link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
1474 existing, NULL,
1475 route_hash_func,
1476 route_compare_func,
1477 route_process_request,
1478 message_counter, netlink_handler, ret);
1479 if (r <= 0)
1480 return r;
1481
1482 route_enter_requesting(existing);
1483 return 1;
1484 }
1485
1486 static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
1487 int r;
1488
1489 assert(link);
1490
1491 r = route_configure_handler_internal(rtnl, m, link, "Could not set route");
1492 if (r <= 0)
1493 return r;
1494
1495 if (link->static_route_messages == 0) {
1496 log_link_debug(link, "Routes set");
1497 link->static_routes_configured = true;
1498 link_check_ready(link);
1499 }
1500
1501 return 1;
1502 }
1503
1504 static int link_request_static_route(Link *link, Route *route) {
1505 assert(link);
1506 assert(link->manager);
1507 assert(route);
1508
1509 if (!route_needs_convert(route))
1510 return link_request_route(link, route, false, &link->static_route_messages,
1511 static_route_handler, NULL);
1512
1513 log_route_debug(route, "Requesting", link, link->manager);
1514 return link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
1515 route, NULL, route_hash_func, route_compare_func,
1516 route_process_request,
1517 &link->static_route_messages, static_route_handler, NULL);
1518 }
1519
1520 static int link_request_wireguard_routes(Link *link, bool only_ipv4) {
1521 NetDev *netdev;
1522 Route *route;
1523 int r;
1524
1525 assert(link);
1526
1527 if (!streq_ptr(link->kind, "wireguard"))
1528 return 0;
1529
1530 if (netdev_get(link->manager, link->ifname, &netdev) < 0)
1531 return 0;
1532
1533 Wireguard *w = WIREGUARD(netdev);
1534
1535 SET_FOREACH(route, w->routes) {
1536 if (only_ipv4 && route->family != AF_INET)
1537 continue;
1538
1539 r = link_request_static_route(link, route);
1540 if (r < 0)
1541 return r;
1542 }
1543
1544 return 0;
1545 }
1546
1547 int link_request_static_routes(Link *link, bool only_ipv4) {
1548 Route *route;
1549 int r;
1550
1551 assert(link);
1552 assert(link->network);
1553
1554 link->static_routes_configured = false;
1555
1556 HASHMAP_FOREACH(route, link->network->routes_by_section) {
1557 if (route->gateway_from_dhcp_or_ra)
1558 continue;
1559
1560 if (only_ipv4 && route->family != AF_INET)
1561 continue;
1562
1563 r = link_request_static_route(link, route);
1564 if (r < 0)
1565 return r;
1566 }
1567
1568 r = link_request_wireguard_routes(link, only_ipv4);
1569 if (r < 0)
1570 return r;
1571
1572 if (link->static_route_messages == 0) {
1573 link->static_routes_configured = true;
1574 link_check_ready(link);
1575 } else {
1576 log_link_debug(link, "Requesting routes");
1577 link_set_state(link, LINK_STATE_CONFIGURING);
1578 }
1579
1580 return 0;
1581 }
1582
1583 void route_cancel_request(Route *route, Link *link) {
1584 Request req;
1585
1586 assert(route);
1587
1588 link = route->link ?: link;
1589
1590 assert(link);
1591
1592 if (!route_is_requesting(route))
1593 return;
1594
1595 req = (Request) {
1596 .link = link,
1597 .type = REQUEST_TYPE_ROUTE,
1598 .userdata = route,
1599 .hash_func = (hash_func_t) route_hash_func,
1600 .compare_func = (compare_func_t) route_compare_func,
1601 };
1602
1603 request_detach(link->manager, &req);
1604 route_cancel_requesting(route);
1605 }
1606
1607 static int process_route_one(
1608 Manager *manager,
1609 Link *link,
1610 uint16_t type,
1611 Route *in,
1612 const struct rta_cacheinfo *cacheinfo) {
1613
1614 _cleanup_(route_freep) Route *tmp = in;
1615 Route *route = NULL;
1616 bool update_dhcp4;
1617 int r;
1618
1619 assert(manager);
1620 assert(tmp);
1621 assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE));
1622
1623 /* link may be NULL. This consumes 'in'. */
1624
1625 update_dhcp4 = link && tmp->family == AF_INET6 && tmp->dst_prefixlen == 0;
1626
1627 (void) route_get(manager, link, tmp, &route);
1628
1629 switch (type) {
1630 case RTM_NEWROUTE:
1631 if (route) {
1632 route->flags = tmp->flags;
1633 route_enter_configured(route);
1634 log_route_debug(route, "Received remembered", link, manager);
1635
1636 r = route_setup_timer(route, cacheinfo);
1637 if (r < 0)
1638 log_link_warning_errno(link, r, "Failed to configure expiration timer for route, ignoring: %m");
1639 if (r > 0)
1640 log_route_debug(route, "Configured expiration timer for", link, manager);
1641
1642 } else if (!manager->manage_foreign_routes) {
1643 route_enter_configured(tmp);
1644 log_route_debug(tmp, "Ignoring received", link, manager);
1645
1646 } else {
1647 /* A route appeared that we did not request */
1648 route_enter_configured(tmp);
1649 log_route_debug(tmp, "Received new", link, manager);
1650 r = route_add(manager, link, tmp);
1651 if (r < 0) {
1652 log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
1653 return 0;
1654 }
1655 TAKE_PTR(tmp);
1656 }
1657
1658 break;
1659
1660 case RTM_DELROUTE:
1661 if (route) {
1662 route_enter_removed(route);
1663 if (route->state == 0) {
1664 log_route_debug(route, "Forgetting", link, manager);
1665 route_free(route);
1666 } else
1667 log_route_debug(route, "Removed", link, manager);
1668 } else
1669 log_route_debug(tmp,
1670 manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received",
1671 link, manager);
1672
1673 break;
1674
1675 default:
1676 assert_not_reached();
1677 }
1678
1679 if (update_dhcp4) {
1680 r = dhcp4_update_ipv6_connectivity(link);
1681 if (r < 0) {
1682 log_link_warning_errno(link, r, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");
1683 link_enter_failed(link);
1684 }
1685 }
1686
1687 return 1;
1688 }
1689
1690 int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
1691 _cleanup_(converted_routes_freep) ConvertedRoutes *converted = NULL;
1692 _cleanup_(route_freep) Route *tmp = NULL;
1693 _cleanup_free_ void *rta_multipath = NULL;
1694 struct rta_cacheinfo cacheinfo;
1695 bool has_cacheinfo;
1696 Link *link = NULL;
1697 uint32_t ifindex;
1698 uint16_t type;
1699 size_t rta_len;
1700 int r;
1701
1702 assert(rtnl);
1703 assert(message);
1704 assert(m);
1705
1706 if (sd_netlink_message_is_error(message)) {
1707 r = sd_netlink_message_get_errno(message);
1708 if (r < 0)
1709 log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
1710
1711 return 0;
1712 }
1713
1714 r = sd_netlink_message_get_type(message, &type);
1715 if (r < 0) {
1716 log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
1717 return 0;
1718 } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
1719 log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
1720 return 0;
1721 }
1722
1723 r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex);
1724 if (r < 0 && r != -ENODATA) {
1725 log_warning_errno(r, "rtnl: could not get ifindex from route message, ignoring: %m");
1726 return 0;
1727 } else if (r >= 0) {
1728 if (ifindex <= 0) {
1729 log_warning("rtnl: received route message with invalid ifindex %u, ignoring.", ifindex);
1730 return 0;
1731 }
1732
1733 r = link_get_by_index(m, ifindex, &link);
1734 if (r < 0) {
1735 /* when enumerating we might be out of sync, but we will
1736 * get the route again, so just ignore it */
1737 if (!m->enumerating)
1738 log_warning("rtnl: received route message for link (%u) we do not know about, ignoring", ifindex);
1739 return 0;
1740 }
1741 }
1742
1743 r = route_new(&tmp);
1744 if (r < 0)
1745 return log_oom();
1746
1747 r = sd_rtnl_message_route_get_family(message, &tmp->family);
1748 if (r < 0) {
1749 log_link_warning(link, "rtnl: received route message without family, ignoring");
1750 return 0;
1751 } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
1752 log_link_debug(link, "rtnl: received route message with invalid family '%i', ignoring", tmp->family);
1753 return 0;
1754 }
1755
1756 r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
1757 if (r < 0) {
1758 log_warning_errno(r, "rtnl: received route message without route protocol, ignoring: %m");
1759 return 0;
1760 }
1761
1762 r = sd_rtnl_message_route_get_flags(message, &tmp->flags);
1763 if (r < 0) {
1764 log_warning_errno(r, "rtnl: received route message without route flags, ignoring: %m");
1765 return 0;
1766 }
1767
1768 r = netlink_message_read_in_addr_union(message, RTA_DST, tmp->family, &tmp->dst);
1769 if (r < 0 && r != -ENODATA) {
1770 log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m");
1771 return 0;
1772 }
1773
1774 r = netlink_message_read_in_addr_union(message, RTA_GATEWAY, tmp->family, &tmp->gw);
1775 if (r < 0 && r != -ENODATA) {
1776 log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
1777 return 0;
1778 } else if (r >= 0)
1779 tmp->gw_family = tmp->family;
1780 else if (tmp->family == AF_INET) {
1781 RouteVia via;
1782
1783 r = sd_netlink_message_read(message, RTA_VIA, sizeof(via), &via);
1784 if (r < 0 && r != -ENODATA) {
1785 log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m");
1786 return 0;
1787 } else if (r >= 0) {
1788 tmp->gw_family = via.family;
1789 tmp->gw = via.address;
1790 }
1791 }
1792
1793 r = netlink_message_read_in_addr_union(message, RTA_SRC, tmp->family, &tmp->src);
1794 if (r < 0 && r != -ENODATA) {
1795 log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m");
1796 return 0;
1797 }
1798
1799 r = netlink_message_read_in_addr_union(message, RTA_PREFSRC, tmp->family, &tmp->prefsrc);
1800 if (r < 0 && r != -ENODATA) {
1801 log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m");
1802 return 0;
1803 }
1804
1805 r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
1806 if (r < 0) {
1807 log_link_warning_errno(link, r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1808 return 0;
1809 }
1810
1811 r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
1812 if (r < 0) {
1813 log_link_warning_errno(link, r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1814 return 0;
1815 }
1816
1817 r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
1818 if (r < 0) {
1819 log_link_warning_errno(link, r, "rtnl: received route message with invalid scope, ignoring: %m");
1820 return 0;
1821 }
1822
1823 r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
1824 if (r < 0) {
1825 log_link_warning_errno(link, r, "rtnl: received route message with invalid tos, ignoring: %m");
1826 return 0;
1827 }
1828
1829 r = sd_rtnl_message_route_get_type(message, &tmp->type);
1830 if (r < 0) {
1831 log_link_warning_errno(link, r, "rtnl: received route message with invalid type, ignoring: %m");
1832 return 0;
1833 }
1834
1835 r = sd_netlink_message_read_u32(message, RTA_TABLE, &tmp->table);
1836 if (r == -ENODATA) {
1837 unsigned char table;
1838
1839 r = sd_rtnl_message_route_get_table(message, &table);
1840 if (r >= 0)
1841 tmp->table = table;
1842 }
1843 if (r < 0) {
1844 log_link_warning_errno(link, r, "rtnl: received route message with invalid table, ignoring: %m");
1845 return 0;
1846 }
1847
1848 r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
1849 if (r < 0 && r != -ENODATA) {
1850 log_link_warning_errno(link, r, "rtnl: received route message with invalid priority, ignoring: %m");
1851 return 0;
1852 }
1853
1854 r = sd_netlink_message_read_u32(message, RTA_NH_ID, &tmp->nexthop_id);
1855 if (r < 0 && r != -ENODATA) {
1856 log_link_warning_errno(link, r, "rtnl: received route message with invalid nexthop id, ignoring: %m");
1857 return 0;
1858 }
1859
1860 r = sd_netlink_message_enter_container(message, RTA_METRICS);
1861 if (r < 0 && r != -ENODATA) {
1862 log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container, ignoring: %m");
1863 return 0;
1864 }
1865 if (r >= 0) {
1866 r = sd_netlink_message_read_u32(message, RTAX_INITCWND, &tmp->initcwnd);
1867 if (r < 0 && r != -ENODATA) {
1868 log_link_warning_errno(link, r, "rtnl: received route message with invalid initcwnd, ignoring: %m");
1869 return 0;
1870 }
1871
1872 r = sd_netlink_message_read_u32(message, RTAX_INITRWND, &tmp->initrwnd);
1873 if (r < 0 && r != -ENODATA) {
1874 log_link_warning_errno(link, r, "rtnl: received route message with invalid initrwnd, ignoring: %m");
1875 return 0;
1876 }
1877
1878 r = sd_netlink_message_read_u32(message, RTAX_ADVMSS, &tmp->advmss);
1879 if (r < 0 && r != -ENODATA) {
1880 log_link_warning_errno(link, r, "rtnl: received route message with invalid advmss, ignoring: %m");
1881 return 0;
1882 }
1883
1884 r = sd_netlink_message_exit_container(message);
1885 if (r < 0) {
1886 log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container, ignoring: %m");
1887 return 0;
1888 }
1889 }
1890
1891 r = sd_netlink_message_read_data(message, RTA_MULTIPATH, &rta_len, &rta_multipath);
1892 if (r < 0 && r != -ENODATA) {
1893 log_link_warning_errno(link, r, "rtnl: failed to read RTA_MULTIPATH attribute, ignoring: %m");
1894 return 0;
1895 } else if (r >= 0) {
1896 r = rtattr_read_nexthop(rta_multipath, rta_len, tmp->family, &tmp->multipath_routes);
1897 if (r < 0) {
1898 log_link_warning_errno(link, r, "rtnl: failed to parse RTA_MULTIPATH attribute, ignoring: %m");
1899 return 0;
1900 }
1901 }
1902
1903 r = sd_netlink_message_read(message, RTA_CACHEINFO, sizeof(cacheinfo), &cacheinfo);
1904 if (r < 0 && r != -ENODATA) {
1905 log_link_warning_errno(link, r, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1906 return 0;
1907 }
1908 has_cacheinfo = r >= 0;
1909
1910 /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's
1911 * fib6_nh_init() in net/ipv6/route.c. However, we'd like to manage them by Manager. Hence, set
1912 * link to NULL here. */
1913 if (route_type_is_reject(tmp))
1914 link = NULL;
1915
1916 if (!route_needs_convert(tmp))
1917 return process_route_one(m, link, type, TAKE_PTR(tmp), has_cacheinfo ? &cacheinfo : NULL);
1918
1919 r = route_convert(m, tmp, &converted);
1920 if (r < 0) {
1921 log_link_warning_errno(link, r, "rtnl: failed to convert received route, ignoring: %m");
1922 return 0;
1923 }
1924
1925 assert(r > 0);
1926 assert(converted);
1927
1928 for (size_t i = 0; i < converted->n; i++)
1929 (void) process_route_one(m,
1930 converted->links[i] ?: link,
1931 type,
1932 TAKE_PTR(converted->routes[i]),
1933 has_cacheinfo ? &cacheinfo : NULL);
1934
1935 return 1;
1936 }
1937
1938 int network_add_ipv4ll_route(Network *network) {
1939 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1940 unsigned section_line;
1941 int r;
1942
1943 assert(network);
1944
1945 if (!network->ipv4ll_route)
1946 return 0;
1947
1948 r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
1949 if (r < 0)
1950 return r;
1951
1952 /* IPv4LLRoute= is in [Network] section. */
1953 r = route_new_static(network, network->filename, section_line, &n);
1954 if (r < 0)
1955 return r;
1956
1957 r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
1958 if (r < 0)
1959 return r;
1960
1961 n->family = AF_INET;
1962 n->dst_prefixlen = 16;
1963 n->scope = RT_SCOPE_LINK;
1964 n->scope_set = true;
1965 n->table_set = true;
1966 n->priority = IPV4LL_ROUTE_METRIC;
1967 n->protocol = RTPROT_STATIC;
1968
1969 TAKE_PTR(n);
1970 return 0;
1971 }
1972
1973 int network_add_default_route_on_device(Network *network) {
1974 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1975 unsigned section_line;
1976 int r;
1977
1978 assert(network);
1979
1980 if (!network->default_route_on_device)
1981 return 0;
1982
1983 r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
1984 if (r < 0)
1985 return r;
1986
1987 /* DefaultRouteOnDevice= is in [Network] section. */
1988 r = route_new_static(network, network->filename, section_line, &n);
1989 if (r < 0)
1990 return r;
1991
1992 n->family = AF_INET;
1993 n->scope = RT_SCOPE_LINK;
1994 n->scope_set = true;
1995 n->protocol = RTPROT_STATIC;
1996
1997 TAKE_PTR(n);
1998 return 0;
1999 }
2000
2001 int config_parse_gateway(
2002 const char *unit,
2003 const char *filename,
2004 unsigned line,
2005 const char *section,
2006 unsigned section_line,
2007 const char *lvalue,
2008 int ltype,
2009 const char *rvalue,
2010 void *data,
2011 void *userdata) {
2012
2013 Network *network = userdata;
2014 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2015 int r;
2016
2017 assert(filename);
2018 assert(section);
2019 assert(lvalue);
2020 assert(rvalue);
2021 assert(data);
2022
2023 if (streq(section, "Network")) {
2024 /* we are not in an Route section, so use line number instead */
2025 r = route_new_static(network, filename, line, &n);
2026 if (r == -ENOMEM)
2027 return log_oom();
2028 if (r < 0) {
2029 log_syntax(unit, LOG_WARNING, filename, line, r,
2030 "Failed to allocate route, ignoring assignment: %m");
2031 return 0;
2032 }
2033 } else {
2034 r = route_new_static(network, filename, section_line, &n);
2035 if (r == -ENOMEM)
2036 return log_oom();
2037 if (r < 0) {
2038 log_syntax(unit, LOG_WARNING, filename, line, r,
2039 "Failed to allocate route, ignoring assignment: %m");
2040 return 0;
2041 }
2042
2043 if (isempty(rvalue)) {
2044 n->gateway_from_dhcp_or_ra = false;
2045 n->gw_family = AF_UNSPEC;
2046 n->gw = IN_ADDR_NULL;
2047 TAKE_PTR(n);
2048 return 0;
2049 }
2050
2051 if (streq(rvalue, "_dhcp")) {
2052 n->gateway_from_dhcp_or_ra = true;
2053 TAKE_PTR(n);
2054 return 0;
2055 }
2056
2057 if (streq(rvalue, "_dhcp4")) {
2058 n->gw_family = AF_INET;
2059 n->gateway_from_dhcp_or_ra = true;
2060 TAKE_PTR(n);
2061 return 0;
2062 }
2063
2064 if (streq(rvalue, "_ipv6ra")) {
2065 n->gw_family = AF_INET6;
2066 n->gateway_from_dhcp_or_ra = true;
2067 TAKE_PTR(n);
2068 return 0;
2069 }
2070 }
2071
2072 r = in_addr_from_string_auto(rvalue, &n->gw_family, &n->gw);
2073 if (r < 0) {
2074 log_syntax(unit, LOG_WARNING, filename, line, r,
2075 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
2076 return 0;
2077 }
2078
2079 n->gateway_from_dhcp_or_ra = false;
2080 TAKE_PTR(n);
2081 return 0;
2082 }
2083
2084 int config_parse_preferred_src(
2085 const char *unit,
2086 const char *filename,
2087 unsigned line,
2088 const char *section,
2089 unsigned section_line,
2090 const char *lvalue,
2091 int ltype,
2092 const char *rvalue,
2093 void *data,
2094 void *userdata) {
2095
2096 Network *network = userdata;
2097 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2098 int r;
2099
2100 assert(filename);
2101 assert(section);
2102 assert(lvalue);
2103 assert(rvalue);
2104 assert(data);
2105
2106 r = route_new_static(network, filename, section_line, &n);
2107 if (r == -ENOMEM)
2108 return log_oom();
2109 if (r < 0) {
2110 log_syntax(unit, LOG_WARNING, filename, line, r,
2111 "Failed to allocate route, ignoring assignment: %m");
2112 return 0;
2113 }
2114
2115 if (n->family == AF_UNSPEC)
2116 r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
2117 else
2118 r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
2119 if (r < 0) {
2120 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
2121 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
2122 return 0;
2123 }
2124
2125 TAKE_PTR(n);
2126 return 0;
2127 }
2128
2129 int config_parse_destination(
2130 const char *unit,
2131 const char *filename,
2132 unsigned line,
2133 const char *section,
2134 unsigned section_line,
2135 const char *lvalue,
2136 int ltype,
2137 const char *rvalue,
2138 void *data,
2139 void *userdata) {
2140
2141 Network *network = userdata;
2142 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2143 union in_addr_union *buffer;
2144 unsigned char *prefixlen;
2145 int r;
2146
2147 assert(filename);
2148 assert(section);
2149 assert(lvalue);
2150 assert(rvalue);
2151 assert(data);
2152
2153 r = route_new_static(network, filename, section_line, &n);
2154 if (r == -ENOMEM)
2155 return log_oom();
2156 if (r < 0) {
2157 log_syntax(unit, LOG_WARNING, filename, line, r,
2158 "Failed to allocate route, ignoring assignment: %m");
2159 return 0;
2160 }
2161
2162 if (streq(lvalue, "Destination")) {
2163 buffer = &n->dst;
2164 prefixlen = &n->dst_prefixlen;
2165 } else if (streq(lvalue, "Source")) {
2166 buffer = &n->src;
2167 prefixlen = &n->src_prefixlen;
2168 } else
2169 assert_not_reached();
2170
2171 if (n->family == AF_UNSPEC)
2172 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
2173 else
2174 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
2175 if (r < 0) {
2176 log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
2177 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
2178 return 0;
2179 }
2180
2181 (void) in_addr_mask(n->family, buffer, *prefixlen);
2182
2183 TAKE_PTR(n);
2184 return 0;
2185 }
2186
2187 int config_parse_route_priority(
2188 const char *unit,
2189 const char *filename,
2190 unsigned line,
2191 const char *section,
2192 unsigned section_line,
2193 const char *lvalue,
2194 int ltype,
2195 const char *rvalue,
2196 void *data,
2197 void *userdata) {
2198
2199 Network *network = userdata;
2200 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2201 int r;
2202
2203 assert(filename);
2204 assert(section);
2205 assert(lvalue);
2206 assert(rvalue);
2207 assert(data);
2208
2209 r = route_new_static(network, filename, section_line, &n);
2210 if (r == -ENOMEM)
2211 return log_oom();
2212 if (r < 0) {
2213 log_syntax(unit, LOG_WARNING, filename, line, r,
2214 "Failed to allocate route, ignoring assignment: %m");
2215 return 0;
2216 }
2217
2218 r = safe_atou32(rvalue, &n->priority);
2219 if (r < 0) {
2220 log_syntax(unit, LOG_WARNING, filename, line, r,
2221 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
2222 return 0;
2223 }
2224
2225 n->priority_set = true;
2226 TAKE_PTR(n);
2227 return 0;
2228 }
2229
2230 int config_parse_route_scope(
2231 const char *unit,
2232 const char *filename,
2233 unsigned line,
2234 const char *section,
2235 unsigned section_line,
2236 const char *lvalue,
2237 int ltype,
2238 const char *rvalue,
2239 void *data,
2240 void *userdata) {
2241
2242 Network *network = userdata;
2243 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2244 int r;
2245
2246 assert(filename);
2247 assert(section);
2248 assert(lvalue);
2249 assert(rvalue);
2250 assert(data);
2251
2252 r = route_new_static(network, filename, section_line, &n);
2253 if (r == -ENOMEM)
2254 return log_oom();
2255 if (r < 0) {
2256 log_syntax(unit, LOG_WARNING, filename, line, r,
2257 "Failed to allocate route, ignoring assignment: %m");
2258 return 0;
2259 }
2260
2261 r = route_scope_from_string(rvalue);
2262 if (r < 0) {
2263 log_syntax(unit, LOG_WARNING, filename, line, r, "Unknown route scope: %s", rvalue);
2264 return 0;
2265 }
2266
2267 n->scope = r;
2268 n->scope_set = true;
2269 TAKE_PTR(n);
2270 return 0;
2271 }
2272
2273 int config_parse_route_nexthop(
2274 const char *unit,
2275 const char *filename,
2276 unsigned line,
2277 const char *section,
2278 unsigned section_line,
2279 const char *lvalue,
2280 int ltype,
2281 const char *rvalue,
2282 void *data,
2283 void *userdata) {
2284
2285 Network *network = userdata;
2286 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2287 uint32_t id;
2288 int r;
2289
2290 assert(filename);
2291 assert(section);
2292 assert(lvalue);
2293 assert(rvalue);
2294 assert(data);
2295
2296 r = route_new_static(network, filename, section_line, &n);
2297 if (r == -ENOMEM)
2298 return log_oom();
2299 if (r < 0) {
2300 log_syntax(unit, LOG_WARNING, filename, line, r,
2301 "Failed to allocate route, ignoring assignment: %m");
2302 return 0;
2303 }
2304
2305 if (isempty(rvalue)) {
2306 n->nexthop_id = 0;
2307 TAKE_PTR(n);
2308 return 0;
2309 }
2310
2311 r = safe_atou32(rvalue, &id);
2312 if (r < 0) {
2313 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue);
2314 return 0;
2315 }
2316 if (id == 0) {
2317 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue);
2318 return 0;
2319 }
2320
2321 n->nexthop_id = id;
2322 TAKE_PTR(n);
2323 return 0;
2324 }
2325
2326 int config_parse_route_table(
2327 const char *unit,
2328 const char *filename,
2329 unsigned line,
2330 const char *section,
2331 unsigned section_line,
2332 const char *lvalue,
2333 int ltype,
2334 const char *rvalue,
2335 void *data,
2336 void *userdata) {
2337
2338 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2339 Network *network = userdata;
2340 int r;
2341
2342 assert(filename);
2343 assert(section);
2344 assert(lvalue);
2345 assert(rvalue);
2346 assert(data);
2347
2348 r = route_new_static(network, filename, section_line, &n);
2349 if (r == -ENOMEM)
2350 return log_oom();
2351 if (r < 0) {
2352 log_syntax(unit, LOG_WARNING, filename, line, r,
2353 "Failed to allocate route, ignoring assignment: %m");
2354 return 0;
2355 }
2356
2357 r = manager_get_route_table_from_string(network->manager, rvalue, &n->table);
2358 if (r < 0) {
2359 log_syntax(unit, LOG_WARNING, filename, line, r,
2360 "Could not parse route table \"%s\", ignoring assignment: %m", rvalue);
2361 return 0;
2362 }
2363
2364 n->table_set = true;
2365 TAKE_PTR(n);
2366 return 0;
2367 }
2368
2369 int config_parse_route_boolean(
2370 const char *unit,
2371 const char *filename,
2372 unsigned line,
2373 const char *section,
2374 unsigned section_line,
2375 const char *lvalue,
2376 int ltype,
2377 const char *rvalue,
2378 void *data,
2379 void *userdata) {
2380
2381 Network *network = userdata;
2382 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2383 int r;
2384
2385 assert(filename);
2386 assert(section);
2387 assert(lvalue);
2388 assert(rvalue);
2389 assert(data);
2390
2391 r = route_new_static(network, filename, section_line, &n);
2392 if (r == -ENOMEM)
2393 return log_oom();
2394 if (r < 0) {
2395 log_syntax(unit, LOG_WARNING, filename, line, r,
2396 "Failed to allocate route, ignoring assignment: %m");
2397 return 0;
2398 }
2399
2400 r = parse_boolean(rvalue);
2401 if (r < 0) {
2402 log_syntax(unit, LOG_WARNING, filename, line, r,
2403 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
2404 return 0;
2405 }
2406
2407 if (STR_IN_SET(lvalue, "GatewayOnLink", "GatewayOnlink"))
2408 n->gateway_onlink = r;
2409 else if (streq(lvalue, "QuickAck"))
2410 n->quickack = r;
2411 else if (streq(lvalue, "FastOpenNoCookie"))
2412 n->fast_open_no_cookie = r;
2413 else
2414 assert_not_reached();
2415
2416 TAKE_PTR(n);
2417 return 0;
2418 }
2419
2420 int config_parse_ipv6_route_preference(
2421 const char *unit,
2422 const char *filename,
2423 unsigned line,
2424 const char *section,
2425 unsigned section_line,
2426 const char *lvalue,
2427 int ltype,
2428 const char *rvalue,
2429 void *data,
2430 void *userdata) {
2431
2432 Network *network = userdata;
2433 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2434 int r;
2435
2436 r = route_new_static(network, filename, section_line, &n);
2437 if (r == -ENOMEM)
2438 return log_oom();
2439 if (r < 0) {
2440 log_syntax(unit, LOG_WARNING, filename, line, r,
2441 "Failed to allocate route, ignoring assignment: %m");
2442 return 0;
2443 }
2444
2445 if (streq(rvalue, "low"))
2446 n->pref = ICMPV6_ROUTER_PREF_LOW;
2447 else if (streq(rvalue, "medium"))
2448 n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
2449 else if (streq(rvalue, "high"))
2450 n->pref = ICMPV6_ROUTER_PREF_HIGH;
2451 else {
2452 log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route preference: %s", rvalue);
2453 return 0;
2454 }
2455
2456 n->pref_set = true;
2457 TAKE_PTR(n);
2458 return 0;
2459 }
2460
2461 int config_parse_route_protocol(
2462 const char *unit,
2463 const char *filename,
2464 unsigned line,
2465 const char *section,
2466 unsigned section_line,
2467 const char *lvalue,
2468 int ltype,
2469 const char *rvalue,
2470 void *data,
2471 void *userdata) {
2472
2473 Network *network = userdata;
2474 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2475 int r;
2476
2477 r = route_new_static(network, filename, section_line, &n);
2478 if (r == -ENOMEM)
2479 return log_oom();
2480 if (r < 0) {
2481 log_syntax(unit, LOG_WARNING, filename, line, r,
2482 "Failed to allocate route, ignoring assignment: %m");
2483 return 0;
2484 }
2485
2486 r = route_protocol_from_string(rvalue);
2487 if (r < 0) {
2488 log_syntax(unit, LOG_WARNING, filename, line, r,
2489 "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue);
2490 return 0;
2491 }
2492
2493 n->protocol = r;
2494
2495 TAKE_PTR(n);
2496 return 0;
2497 }
2498
2499 int config_parse_route_type(
2500 const char *unit,
2501 const char *filename,
2502 unsigned line,
2503 const char *section,
2504 unsigned section_line,
2505 const char *lvalue,
2506 int ltype,
2507 const char *rvalue,
2508 void *data,
2509 void *userdata) {
2510
2511 Network *network = userdata;
2512 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2513 int t, r;
2514
2515 r = route_new_static(network, filename, section_line, &n);
2516 if (r == -ENOMEM)
2517 return log_oom();
2518 if (r < 0) {
2519 log_syntax(unit, LOG_WARNING, filename, line, r,
2520 "Failed to allocate route, ignoring assignment: %m");
2521 return 0;
2522 }
2523
2524 t = route_type_from_string(rvalue);
2525 if (t < 0) {
2526 log_syntax(unit, LOG_WARNING, filename, line, r,
2527 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
2528 return 0;
2529 }
2530
2531 n->type = (unsigned char) t;
2532
2533 TAKE_PTR(n);
2534 return 0;
2535 }
2536
2537 int config_parse_route_hop_limit(
2538 const char *unit,
2539 const char *filename,
2540 unsigned line,
2541 const char *section,
2542 unsigned section_line,
2543 const char *lvalue,
2544 int ltype,
2545 const char *rvalue,
2546 void *data,
2547 void *userdata) {
2548
2549 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2550 Network *network = userdata;
2551 uint32_t k;
2552 int r;
2553
2554 assert(filename);
2555 assert(section);
2556 assert(lvalue);
2557 assert(rvalue);
2558 assert(data);
2559
2560 r = route_new_static(network, filename, section_line, &n);
2561 if (r == -ENOMEM)
2562 return log_oom();
2563 if (r < 0) {
2564 log_syntax(unit, LOG_WARNING, filename, line, r,
2565 "Failed to allocate route, ignoring assignment: %m");
2566 return 0;
2567 }
2568
2569 if (isempty(rvalue)) {
2570 n->hop_limit = 0;
2571 TAKE_PTR(n);
2572 return 0;
2573 }
2574
2575 r = safe_atou32(rvalue, &k);
2576 if (r < 0) {
2577 log_syntax(unit, LOG_WARNING, filename, line, r,
2578 "Could not parse per route hop limit, ignoring assignment: %s", rvalue);
2579 return 0;
2580 }
2581 if (k > 255) {
2582 log_syntax(unit, LOG_WARNING, filename, line, 0,
2583 "Specified per route hop limit \"%s\" is too large, ignoring assignment: %m", rvalue);
2584 return 0;
2585 }
2586 if (k == 0) {
2587 log_syntax(unit, LOG_WARNING, filename, line, 0,
2588 "Invalid per route hop limit \"%s\", ignoring assignment: %m", rvalue);
2589 return 0;
2590 }
2591
2592 n->hop_limit = k;
2593
2594 TAKE_PTR(n);
2595 return 0;
2596 }
2597
2598 int config_parse_tcp_congestion(
2599 const char *unit,
2600 const char *filename,
2601 unsigned line,
2602 const char *section,
2603 unsigned section_line,
2604 const char *lvalue,
2605 int ltype,
2606 const char *rvalue,
2607 void *data,
2608 void *userdata) {
2609
2610 Network *network = userdata;
2611 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2612 int r;
2613
2614 assert(filename);
2615 assert(section);
2616 assert(lvalue);
2617 assert(rvalue);
2618 assert(data);
2619
2620 r = route_new_static(network, filename, section_line, &n);
2621 if (r == -ENOMEM)
2622 return log_oom();
2623 if (r < 0) {
2624 log_syntax(unit, LOG_WARNING, filename, line, r,
2625 "Failed to allocate route, ignoring assignment: %m");
2626 return 0;
2627 }
2628
2629 r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype,
2630 rvalue, &n->tcp_congestion_control_algo, userdata);
2631 if (r < 0)
2632 return r;
2633
2634 TAKE_PTR(n);
2635 return 0;
2636 }
2637
2638 int config_parse_tcp_advmss(
2639 const char *unit,
2640 const char *filename,
2641 unsigned line,
2642 const char *section,
2643 unsigned section_line,
2644 const char *lvalue,
2645 int ltype,
2646 const char *rvalue,
2647 void *data,
2648 void *userdata) {
2649
2650 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2651 Network *network = userdata;
2652 uint64_t u;
2653 int r;
2654
2655 assert(filename);
2656 assert(section);
2657 assert(lvalue);
2658 assert(rvalue);
2659 assert(data);
2660
2661 r = route_new_static(network, filename, section_line, &n);
2662 if (r == -ENOMEM)
2663 return log_oom();
2664 if (r < 0) {
2665 log_syntax(unit, LOG_WARNING, filename, line, r,
2666 "Failed to allocate route, ignoring assignment: %m");
2667 return 0;
2668 }
2669
2670 if (isempty(rvalue)) {
2671 n->advmss = 0;
2672 TAKE_PTR(n);
2673 return 0;
2674 }
2675
2676 r = parse_size(rvalue, 1024, &u);
2677 if (r < 0) {
2678 log_syntax(unit, LOG_WARNING, filename, line, r,
2679 "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue);
2680 return 0;
2681 }
2682
2683 if (u == 0 || u > UINT32_MAX) {
2684 log_syntax(unit, LOG_WARNING, filename, line, 0,
2685 "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue);
2686 return 0;
2687 }
2688
2689 n->advmss = u;
2690
2691 TAKE_PTR(n);
2692 return 0;
2693 }
2694
2695 int config_parse_tcp_window(
2696 const char *unit,
2697 const char *filename,
2698 unsigned line,
2699 const char *section,
2700 unsigned section_line,
2701 const char *lvalue,
2702 int ltype,
2703 const char *rvalue,
2704 void *data,
2705 void *userdata) {
2706
2707 uint32_t *window = ASSERT_PTR(data);
2708 uint32_t k;
2709 int r;
2710
2711 assert(filename);
2712 assert(section);
2713 assert(lvalue);
2714 assert(rvalue);
2715 assert(data);
2716
2717 r = safe_atou32(rvalue, &k);
2718 if (r < 0) {
2719 log_syntax(unit, LOG_WARNING, filename, line, r,
2720 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
2721 return 0;
2722 }
2723 if (k >= 1024) {
2724 log_syntax(unit, LOG_WARNING, filename, line, 0,
2725 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
2726 return 0;
2727 }
2728 if (k == 0) {
2729 log_syntax(unit, LOG_WARNING, filename, line, 0,
2730 "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
2731 return 0;
2732 }
2733
2734 *window = k;
2735 return 0;
2736 }
2737
2738 int config_parse_route_tcp_window(
2739 const char *unit,
2740 const char *filename,
2741 unsigned line,
2742 const char *section,
2743 unsigned section_line,
2744 const char *lvalue,
2745 int ltype,
2746 const char *rvalue,
2747 void *data,
2748 void *userdata) {
2749
2750 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2751 Network *network = userdata;
2752 uint32_t *d;
2753 int r;
2754
2755 assert(filename);
2756 assert(section);
2757 assert(lvalue);
2758 assert(rvalue);
2759 assert(data);
2760
2761 r = route_new_static(network, filename, section_line, &n);
2762 if (r == -ENOMEM)
2763 return log_oom();
2764 if (r < 0) {
2765 log_syntax(unit, LOG_WARNING, filename, line, r,
2766 "Failed to allocate route, ignoring assignment: %m");
2767 return 0;
2768 }
2769
2770 if (streq(lvalue, "InitialCongestionWindow"))
2771 d = &n->initcwnd;
2772 else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
2773 d = &n->initrwnd;
2774 else
2775 assert_not_reached();
2776
2777 r = config_parse_tcp_window(unit, filename, line, section, section_line, lvalue, ltype, rvalue, d, userdata);
2778 if (r < 0)
2779 return r;
2780
2781 TAKE_PTR(n);
2782 return 0;
2783 }
2784
2785 int config_parse_route_mtu(
2786 const char *unit,
2787 const char *filename,
2788 unsigned line,
2789 const char *section,
2790 unsigned section_line,
2791 const char *lvalue,
2792 int ltype,
2793 const char *rvalue,
2794 void *data,
2795 void *userdata) {
2796
2797 Network *network = userdata;
2798 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2799 int r;
2800
2801 assert(filename);
2802 assert(section);
2803 assert(lvalue);
2804 assert(rvalue);
2805 assert(data);
2806
2807 r = route_new_static(network, filename, section_line, &n);
2808 if (r == -ENOMEM)
2809 return log_oom();
2810 if (r < 0) {
2811 log_syntax(unit, LOG_WARNING, filename, line, r,
2812 "Failed to allocate route, ignoring assignment: %m");
2813 return 0;
2814 }
2815
2816 r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &n->mtu, userdata);
2817 if (r < 0)
2818 return r;
2819
2820 TAKE_PTR(n);
2821 return 0;
2822 }
2823
2824 int config_parse_route_tcp_rto(
2825 const char *unit,
2826 const char *filename,
2827 unsigned line,
2828 const char *section,
2829 unsigned section_line,
2830 const char *lvalue,
2831 int ltype,
2832 const char *rvalue,
2833 void *data,
2834 void *userdata) {
2835
2836 Network *network = userdata;
2837 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2838 usec_t usec;
2839 int r;
2840
2841 assert(filename);
2842 assert(section);
2843 assert(lvalue);
2844 assert(rvalue);
2845 assert(data);
2846
2847 r = route_new_static(network, filename, section_line, &n);
2848 if (r == -ENOMEM)
2849 return log_oom();
2850 if (r < 0) {
2851 log_syntax(unit, LOG_WARNING, filename, line, r,
2852 "Failed to allocate route, ignoring assignment: %m");
2853 return 0;
2854 }
2855
2856 r = parse_sec(rvalue, &usec);
2857 if (r < 0) {
2858 log_syntax(unit, LOG_WARNING, filename, line, r,
2859 "Failed to parse route TCP retransmission timeout (RTO), ignoring assignment: %s", rvalue);
2860 return 0;
2861 }
2862
2863 if (!timestamp_is_set(usec) ||
2864 DIV_ROUND_UP(usec, USEC_PER_MSEC) > UINT32_MAX) {
2865 log_syntax(unit, LOG_WARNING, filename, line, 0,
2866 "Route TCP retransmission timeout (RTO) must be in the range 0…%"PRIu32"ms, ignoring assignment: %s", UINT32_MAX, rvalue);
2867 return 0;
2868 }
2869
2870 n->tcp_rto_usec = usec;
2871
2872 TAKE_PTR(n);
2873 return 0;
2874 }
2875
2876 int config_parse_multipath_route(
2877 const char *unit,
2878 const char *filename,
2879 unsigned line,
2880 const char *section,
2881 unsigned section_line,
2882 const char *lvalue,
2883 int ltype,
2884 const char *rvalue,
2885 void *data,
2886 void *userdata) {
2887
2888 _cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
2889 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
2890 _cleanup_free_ char *word = NULL;
2891 Network *network = userdata;
2892 union in_addr_union a;
2893 int family, r;
2894 const char *p;
2895 char *dev;
2896
2897 assert(filename);
2898 assert(section);
2899 assert(lvalue);
2900 assert(rvalue);
2901 assert(data);
2902
2903 r = route_new_static(network, filename, section_line, &n);
2904 if (r == -ENOMEM)
2905 return log_oom();
2906 if (r < 0) {
2907 log_syntax(unit, LOG_WARNING, filename, line, r,
2908 "Failed to allocate route, ignoring assignment: %m");
2909 return 0;
2910 }
2911
2912 if (isempty(rvalue)) {
2913 n->multipath_routes = ordered_set_free_with_destructor(n->multipath_routes, multipath_route_free);
2914 return 0;
2915 }
2916
2917 m = new0(MultipathRoute, 1);
2918 if (!m)
2919 return log_oom();
2920
2921 p = rvalue;
2922 r = extract_first_word(&p, &word, NULL, 0);
2923 if (r == -ENOMEM)
2924 return log_oom();
2925 if (r <= 0) {
2926 log_syntax(unit, LOG_WARNING, filename, line, r,
2927 "Invalid multipath route option, ignoring assignment: %s", rvalue);
2928 return 0;
2929 }
2930
2931 dev = strchr(word, '@');
2932 if (dev) {
2933 *dev++ = '\0';
2934
2935 r = parse_ifindex(dev);
2936 if (r > 0)
2937 m->ifindex = r;
2938 else {
2939 if (!ifname_valid_full(dev, IFNAME_VALID_ALTERNATIVE)) {
2940 log_syntax(unit, LOG_WARNING, filename, line, 0,
2941 "Invalid interface name '%s' in %s=, ignoring: %s", dev, lvalue, rvalue);
2942 return 0;
2943 }
2944
2945 m->ifname = strdup(dev);
2946 if (!m->ifname)
2947 return log_oom();
2948 }
2949 }
2950
2951 r = in_addr_from_string_auto(word, &family, &a);
2952 if (r < 0) {
2953 log_syntax(unit, LOG_WARNING, filename, line, r,
2954 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue);
2955 return 0;
2956 }
2957 m->gateway.address = a;
2958 m->gateway.family = family;
2959
2960 if (!isempty(p)) {
2961 r = safe_atou32(p, &m->weight);
2962 if (r < 0) {
2963 log_syntax(unit, LOG_WARNING, filename, line, r,
2964 "Invalid multipath route weight, ignoring assignment: %s", p);
2965 return 0;
2966 }
2967 /* ip command takes weight in the range 1…255, while kernel takes the value in the
2968 * range 0…254. MultiPathRoute= setting also takes weight in the same range which ip
2969 * command uses, then networkd decreases by one and stores it to match the range which
2970 * kernel uses. */
2971 if (m->weight == 0 || m->weight > 256) {
2972 log_syntax(unit, LOG_WARNING, filename, line, 0,
2973 "Invalid multipath route weight, ignoring assignment: %s", p);
2974 return 0;
2975 }
2976 m->weight--;
2977 }
2978
2979 r = ordered_set_ensure_put(&n->multipath_routes, NULL, m);
2980 if (r == -ENOMEM)
2981 return log_oom();
2982 if (r < 0) {
2983 log_syntax(unit, LOG_WARNING, filename, line, r,
2984 "Failed to store multipath route, ignoring assignment: %m");
2985 return 0;
2986 }
2987
2988 TAKE_PTR(m);
2989 TAKE_PTR(n);
2990 return 0;
2991 }
2992
2993 static int route_section_verify(Route *route, Network *network) {
2994 if (section_is_invalid(route->section))
2995 return -EINVAL;
2996
2997 /* Currently, we do not support static route with finite lifetime. */
2998 assert(route->lifetime_usec == USEC_INFINITY);
2999
3000 if (route->gateway_from_dhcp_or_ra) {
3001 if (route->gw_family == AF_UNSPEC) {
3002 /* When deprecated Gateway=_dhcp is set, then assume gateway family based on other settings. */
3003 switch (route->family) {
3004 case AF_UNSPEC:
3005 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3006 "Please use \"_dhcp4\" or \"_ipv6ra\" instead. Assuming \"_dhcp4\".",
3007 route->section->filename, route->section->line);
3008 route->family = AF_INET;
3009 break;
3010 case AF_INET:
3011 case AF_INET6:
3012 log_warning("%s: Deprecated value \"_dhcp\" is specified for Gateway= in [Route] section from line %u. "
3013 "Assuming \"%s\" based on Destination=, Source=, or PreferredSource= setting.",
3014 route->section->filename, route->section->line, route->family == AF_INET ? "_dhcp4" : "_ipv6ra");
3015 break;
3016 default:
3017 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3018 "%s: Invalid route family. Ignoring [Route] section from line %u.",
3019 route->section->filename, route->section->line);
3020 }
3021 route->gw_family = route->family;
3022 }
3023
3024 if (route->gw_family == AF_INET && !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4))
3025 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3026 "%s: Gateway=\"_dhcp4\" is specified but DHCPv4 client is disabled. "
3027 "Ignoring [Route] section from line %u.",
3028 route->section->filename, route->section->line);
3029
3030 if (route->gw_family == AF_INET6 && !network->ipv6_accept_ra)
3031 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3032 "%s: Gateway=\"_ipv6ra\" is specified but IPv6AcceptRA= is disabled. "
3033 "Ignoring [Route] section from line %u.",
3034 route->section->filename, route->section->line);
3035 }
3036
3037 /* When only Gateway= is specified, assume the route family based on the Gateway address. */
3038 if (route->family == AF_UNSPEC)
3039 route->family = route->gw_family;
3040
3041 if (route->family == AF_UNSPEC) {
3042 assert(route->section);
3043
3044 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3045 "%s: Route section without Gateway=, Destination=, Source=, "
3046 "or PreferredSource= field configured. "
3047 "Ignoring [Route] section from line %u.",
3048 route->section->filename, route->section->line);
3049 }
3050
3051 if (route->family == AF_INET6 && route->gw_family == AF_INET)
3052 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3053 "%s: IPv4 gateway is configured for IPv6 route. "
3054 "Ignoring [Route] section from line %u.",
3055 route->section->filename, route->section->line);
3056
3057 if (!route->table_set && network->vrf) {
3058 route->table = VRF(network->vrf)->table;
3059 route->table_set = true;
3060 }
3061
3062 if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
3063 route->table = RT_TABLE_LOCAL;
3064
3065 if (!route->scope_set && route->family != AF_INET6) {
3066 if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
3067 route->scope = RT_SCOPE_HOST;
3068 else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
3069 route->scope = RT_SCOPE_LINK;
3070 else if (IN_SET(route->type, RTN_UNICAST, RTN_UNSPEC) &&
3071 !route->gateway_from_dhcp_or_ra &&
3072 !in_addr_is_set(route->gw_family, &route->gw) &&
3073 ordered_set_isempty(route->multipath_routes) &&
3074 route->nexthop_id == 0)
3075 route->scope = RT_SCOPE_LINK;
3076 }
3077
3078 if (route->scope != RT_SCOPE_UNIVERSE && route->family == AF_INET6) {
3079 log_warning("%s: Scope= is specified for IPv6 route. It will be ignored.", route->section->filename);
3080 route->scope = RT_SCOPE_UNIVERSE;
3081 }
3082
3083 if (route->family == AF_INET6 && route->priority == 0)
3084 route->priority = IP6_RT_PRIO_USER;
3085
3086 if (route->gateway_onlink < 0 && in_addr_is_set(route->gw_family, &route->gw) &&
3087 ordered_hashmap_isempty(network->addresses_by_section)) {
3088 /* If no address is configured, in most cases the gateway cannot be reachable.
3089 * TODO: we may need to improve the condition above. */
3090 log_warning("%s: Gateway= without static address configured. "
3091 "Enabling GatewayOnLink= option.",
3092 network->filename);
3093 route->gateway_onlink = true;
3094 }
3095
3096 if (route->gateway_onlink >= 0)
3097 SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
3098
3099 if (route->family == AF_INET6) {
3100 MultipathRoute *m;
3101
3102 ORDERED_SET_FOREACH(m, route->multipath_routes)
3103 if (m->gateway.family == AF_INET)
3104 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3105 "%s: IPv4 multipath route is specified for IPv6 route. "
3106 "Ignoring [Route] section from line %u.",
3107 route->section->filename, route->section->line);
3108 }
3109
3110 if ((route->gateway_from_dhcp_or_ra ||
3111 in_addr_is_set(route->gw_family, &route->gw)) &&
3112 !ordered_set_isempty(route->multipath_routes))
3113 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3114 "%s: Gateway= cannot be specified with MultiPathRoute=. "
3115 "Ignoring [Route] section from line %u.",
3116 route->section->filename, route->section->line);
3117
3118 if (route->nexthop_id > 0 &&
3119 (route->gateway_from_dhcp_or_ra ||
3120 in_addr_is_set(route->gw_family, &route->gw) ||
3121 !ordered_set_isempty(route->multipath_routes)))
3122 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
3123 "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. "
3124 "Ignoring [Route] section from line %u.",
3125 route->section->filename, route->section->line);
3126
3127 return 0;
3128 }
3129
3130 void network_drop_invalid_routes(Network *network) {
3131 Route *route;
3132
3133 assert(network);
3134
3135 HASHMAP_FOREACH(route, network->routes_by_section)
3136 if (route_section_verify(route, network) < 0)
3137 route_free(route);
3138 }