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