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