]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-route.c
Merge pull request #14423 from danielshahaf/zsh-add-missing-completions
[thirdparty/systemd.git] / src / network / networkd-route.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <linux/icmpv6.h>
4
5 #include "alloc-util.h"
6 #include "conf-parser.h"
7 #include "in-addr-util.h"
8 #include "missing_network.h"
9 #include "netlink-util.h"
10 #include "networkd-ipv4ll.h"
11 #include "networkd-manager.h"
12 #include "networkd-route.h"
13 #include "parse-util.h"
14 #include "set.h"
15 #include "string-table.h"
16 #include "string-util.h"
17 #include "strxcpyx.h"
18 #include "sysctl-util.h"
19 #include "util.h"
20
21 #define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
22
23 static unsigned routes_max(void) {
24 static thread_local unsigned cached = 0;
25
26 _cleanup_free_ char *s4 = NULL, *s6 = NULL;
27 unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
28
29 if (cached > 0)
30 return cached;
31
32 if (sysctl_read("net/ipv4/route/max_size", &s4) >= 0) {
33 truncate_nl(s4);
34 if (safe_atou(s4, &val4) >= 0 &&
35 val4 == 2147483647U)
36 /* This is the default "no limit" value in the kernel */
37 val4 = ROUTES_DEFAULT_MAX_PER_FAMILY;
38 }
39
40 if (sysctl_read("net/ipv6/route/max_size", &s6) >= 0) {
41 truncate_nl(s6);
42 (void) safe_atou(s6, &val6);
43 }
44
45 cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) +
46 MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6);
47 return cached;
48 }
49
50 int route_new(Route **ret) {
51 _cleanup_(route_freep) Route *route = NULL;
52
53 route = new(Route, 1);
54 if (!route)
55 return -ENOMEM;
56
57 *route = (Route) {
58 .family = AF_UNSPEC,
59 .scope = RT_SCOPE_UNIVERSE,
60 .protocol = RTPROT_UNSPEC,
61 .type = RTN_UNICAST,
62 .table = RT_TABLE_MAIN,
63 .lifetime = USEC_INFINITY,
64 .quickack = -1,
65 .fast_open_no_cookie = -1,
66 .gateway_onlink = -1,
67 .ttl_propagate = -1,
68 };
69
70 *ret = TAKE_PTR(route);
71
72 return 0;
73 }
74
75 static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
76 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
77 _cleanup_(route_freep) Route *route = NULL;
78 int r;
79
80 assert(network);
81 assert(ret);
82 assert(!!filename == (section_line > 0));
83
84 if (filename) {
85 r = network_config_section_new(filename, section_line, &n);
86 if (r < 0)
87 return r;
88
89 route = hashmap_get(network->routes_by_section, n);
90 if (route) {
91 *ret = TAKE_PTR(route);
92
93 return 0;
94 }
95 }
96
97 if (network->n_static_routes >= routes_max())
98 return -E2BIG;
99
100 r = route_new(&route);
101 if (r < 0)
102 return r;
103
104 route->protocol = RTPROT_STATIC;
105 route->network = network;
106 LIST_PREPEND(routes, network->static_routes, route);
107 network->n_static_routes++;
108
109 if (filename) {
110 route->section = TAKE_PTR(n);
111
112 r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops);
113 if (r < 0)
114 return r;
115
116 r = hashmap_put(network->routes_by_section, route->section, route);
117 if (r < 0)
118 return r;
119 }
120
121 *ret = TAKE_PTR(route);
122
123 return 0;
124 }
125
126 void route_free(Route *route) {
127 if (!route)
128 return;
129
130 if (route->network) {
131 LIST_REMOVE(routes, route->network->static_routes, route);
132
133 assert(route->network->n_static_routes > 0);
134 route->network->n_static_routes--;
135
136 if (route->section)
137 hashmap_remove(route->network->routes_by_section, route->section);
138 }
139
140 network_config_section_free(route->section);
141
142 if (route->link) {
143 set_remove(route->link->routes, route);
144 set_remove(route->link->routes_foreign, route);
145 }
146
147 ordered_set_free_free(route->multipath_routes);
148
149 sd_event_source_unref(route->expire);
150
151 free(route);
152 }
153
154 static void route_hash_func(const Route *route, struct siphash *state) {
155 assert(route);
156
157 siphash24_compress(&route->family, sizeof(route->family), state);
158
159 switch (route->family) {
160 case AF_INET:
161 case AF_INET6:
162 siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
163 siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
164
165 siphash24_compress(&route->src_prefixlen, sizeof(route->src_prefixlen), state);
166 siphash24_compress(&route->src, FAMILY_ADDRESS_SIZE(route->family), state);
167
168 siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->family), state);
169
170 siphash24_compress(&route->prefsrc, FAMILY_ADDRESS_SIZE(route->family), state);
171
172 siphash24_compress(&route->tos, sizeof(route->tos), state);
173 siphash24_compress(&route->priority, sizeof(route->priority), state);
174 siphash24_compress(&route->table, sizeof(route->table), state);
175 siphash24_compress(&route->protocol, sizeof(route->protocol), state);
176 siphash24_compress(&route->scope, sizeof(route->scope), state);
177 siphash24_compress(&route->type, sizeof(route->type), state);
178
179 siphash24_compress(&route->initcwnd, sizeof(route->initcwnd), state);
180 siphash24_compress(&route->initrwnd, sizeof(route->initrwnd), state);
181
182 break;
183 default:
184 /* treat any other address family as AF_UNSPEC */
185 break;
186 }
187 }
188
189 static int route_compare_func(const Route *a, const Route *b) {
190 int r;
191
192 r = CMP(a->family, b->family);
193 if (r != 0)
194 return r;
195
196 switch (a->family) {
197 case AF_INET:
198 case AF_INET6:
199 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
200 if (r != 0)
201 return r;
202
203 r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
204 if (r != 0)
205 return r;
206
207 r = CMP(a->src_prefixlen, b->src_prefixlen);
208 if (r != 0)
209 return r;
210
211 r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
212 if (r != 0)
213 return r;
214
215 r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
216 if (r != 0)
217 return r;
218
219 r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
220 if (r != 0)
221 return r;
222
223 r = CMP(a->tos, b->tos);
224 if (r != 0)
225 return r;
226
227 r = CMP(a->priority, b->priority);
228 if (r != 0)
229 return r;
230
231 r = CMP(a->table, b->table);
232 if (r != 0)
233 return r;
234
235 r = CMP(a->protocol, b->protocol);
236 if (r != 0)
237 return r;
238
239 r = CMP(a->scope, b->scope);
240 if (r != 0)
241 return r;
242
243 r = CMP(a->type, b->type);
244 if (r != 0)
245 return r;
246
247 r = CMP(a->initcwnd, b->initcwnd);
248 if (r != 0)
249 return r;
250
251 r = CMP(a->initrwnd, b->initrwnd);
252 if (r != 0)
253 return r;
254
255 return 0;
256 default:
257 /* treat any other address family as AF_UNSPEC */
258 return 0;
259 }
260 }
261
262 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
263 route_hash_ops,
264 Route,
265 route_hash_func,
266 route_compare_func,
267 route_free);
268
269 bool route_equal(Route *r1, Route *r2) {
270 if (r1 == r2)
271 return true;
272
273 if (!r1 || !r2)
274 return false;
275
276 return route_compare_func(r1, r2) == 0;
277 }
278
279 int route_get(Link *link, Route *in, Route **ret) {
280
281 Route *existing;
282
283 assert(link);
284 assert(in);
285
286 existing = set_get(link->routes, in);
287 if (existing) {
288 if (ret)
289 *ret = existing;
290 return 1;
291 }
292
293 existing = set_get(link->routes_foreign, in);
294 if (existing) {
295 if (ret)
296 *ret = existing;
297 return 0;
298 }
299
300 return -ENOENT;
301 }
302
303 static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret) {
304
305 _cleanup_(route_freep) Route *route = NULL;
306 int r;
307
308 assert(link);
309 assert(routes);
310 assert(in);
311
312 r = route_new(&route);
313 if (r < 0)
314 return r;
315
316 route->family = in->family;
317 route->src = in->src;
318 route->src_prefixlen = in->src_prefixlen;
319 route->dst = in->dst;
320 route->dst_prefixlen = in->dst_prefixlen;
321 route->gw = in->gw;
322 route->prefsrc = in->prefsrc;
323 route->scope = in->scope;
324 route->protocol = in->protocol;
325 route->type = in->type;
326 route->tos = in->tos;
327 route->priority = in->priority;
328 route->table = in->table;
329 route->initcwnd = in->initcwnd;
330 route->initrwnd = in->initrwnd;
331 route->lifetime = in->lifetime;
332
333 r = set_ensure_allocated(routes, &route_hash_ops);
334 if (r < 0)
335 return r;
336
337 r = set_put(*routes, route);
338 if (r < 0)
339 return r;
340 if (r == 0)
341 return -EEXIST;
342
343 route->link = link;
344
345 if (ret)
346 *ret = route;
347
348 route = NULL;
349
350 return 0;
351 }
352
353 int route_add_foreign(Link *link, Route *in, Route **ret) {
354 return route_add_internal(link, &link->routes_foreign, in, ret);
355 }
356
357 int route_add(Link *link, Route *in, Route **ret) {
358
359 Route *route;
360 int r;
361
362 r = route_get(link, in, &route);
363 if (r == -ENOENT) {
364 /* Route does not exist, create a new one */
365 r = route_add_internal(link, &link->routes, in, &route);
366 if (r < 0)
367 return r;
368 } else if (r == 0) {
369 /* Take over a foreign route */
370 r = set_ensure_allocated(&link->routes, &route_hash_ops);
371 if (r < 0)
372 return r;
373
374 r = set_put(link->routes, route);
375 if (r < 0)
376 return r;
377
378 set_remove(link->routes_foreign, route);
379 } else if (r == 1) {
380 /* Route exists, do nothing */
381 ;
382 } else
383 return r;
384
385 if (ret)
386 *ret = route;
387
388 return 0;
389 }
390
391 static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
392 int r;
393
394 assert(m);
395 assert(link);
396 assert(link->ifname);
397
398 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
399 return 1;
400
401 r = sd_netlink_message_get_errno(m);
402 if (r < 0 && r != -ESRCH)
403 log_link_message_warning_errno(link, m, r, "Could not drop route, ignoring");
404
405 return 1;
406 }
407
408 int route_remove(Route *route, Link *link,
409 link_netlink_message_handler_t callback) {
410
411 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
412 int r;
413
414 assert(link);
415 assert(link->manager);
416 assert(link->manager->rtnl);
417 assert(link->ifindex > 0);
418 assert(IN_SET(route->family, AF_INET, AF_INET6));
419
420 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
421 RTM_DELROUTE, route->family,
422 route->protocol);
423 if (r < 0)
424 return log_link_error_errno(link, r, "Could not create RTM_DELROUTE message: %m");
425
426 if (DEBUG_LOGGING) {
427 _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
428 char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
429
430 if (!in_addr_is_null(route->family, &route->dst)) {
431 (void) in_addr_to_string(route->family, &route->dst, &dst);
432 (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen);
433 }
434 if (!in_addr_is_null(route->family, &route->src))
435 (void) in_addr_to_string(route->family, &route->src, &src);
436 if (!in_addr_is_null(route->family, &route->gw))
437 (void) in_addr_to_string(route->family, &route->gw, &gw);
438 if (!in_addr_is_null(route->family, &route->prefsrc))
439 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
440
441 log_link_debug(link, "Removing route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
442 strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc),
443 format_route_scope(route->scope, scope, sizeof(scope)),
444 format_route_table(route->table, table, sizeof(table)),
445 format_route_protocol(route->protocol, protocol, sizeof(protocol)),
446 strna(route_type_to_string(route->type)));
447 }
448
449 if (in_addr_is_null(route->family, &route->gw) == 0) {
450 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
451 if (r < 0)
452 return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
453 }
454
455 if (route->dst_prefixlen) {
456 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
457 if (r < 0)
458 return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
459
460 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
461 if (r < 0)
462 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
463 }
464
465 if (route->src_prefixlen) {
466 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
467 if (r < 0)
468 return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
469
470 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
471 if (r < 0)
472 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
473 }
474
475 if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
476 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
477 if (r < 0)
478 return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
479 }
480
481 r = sd_rtnl_message_route_set_scope(req, route->scope);
482 if (r < 0)
483 return log_link_error_errno(link, r, "Could not set scope: %m");
484
485 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
486 if (r < 0)
487 return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
488
489 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
490 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
491 if (r < 0)
492 return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
493 }
494
495 r = netlink_call_async(link->manager->rtnl, NULL, req,
496 callback ?: route_remove_handler,
497 link_netlink_destroy_callback, link);
498 if (r < 0)
499 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
500
501 link_ref(link);
502
503 return 0;
504 }
505
506 int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
507 Route *route = userdata;
508 int r;
509
510 assert(route);
511
512 r = route_remove(route, route->link, NULL);
513 if (r < 0)
514 log_warning_errno(r, "Could not remove route: %m");
515 else
516 route_free(route);
517
518 return 1;
519 }
520
521 static int append_nexthop_one(Route *route, MultipathRoute *m, struct rtattr **rta, size_t offset) {
522 struct rtnexthop *rtnh;
523 struct rtattr *new_rta;
524 int r;
525
526 assert(route);
527 assert(m);
528 assert(rta);
529 assert(*rta);
530
531 new_rta = realloc(*rta, RTA_ALIGN((*rta)->rta_len) + RTA_SPACE(sizeof(struct rtnexthop)));
532 if (!new_rta)
533 return -ENOMEM;
534 *rta = new_rta;
535
536 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
537 *rtnh = (struct rtnexthop) {
538 .rtnh_len = sizeof(*rtnh),
539 .rtnh_ifindex = m->ifindex,
540 .rtnh_hops = m->weight > 0 ? m->weight - 1 : 0,
541 };
542
543 (*rta)->rta_len += sizeof(struct rtnexthop);
544
545 if (route->family == m->gateway.family) {
546 r = rtattr_append_attribute(rta, RTA_GATEWAY, &m->gateway.address, FAMILY_ADDRESS_SIZE(m->gateway.family));
547 if (r < 0)
548 goto clear;
549 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
550 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family));
551 } else {
552 r = rtattr_append_attribute(rta, RTA_VIA, &m->gateway, FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
553 if (r < 0)
554 goto clear;
555 rtnh = (struct rtnexthop *)((uint8_t *) *rta + offset);
556 rtnh->rtnh_len += RTA_SPACE(FAMILY_ADDRESS_SIZE(m->gateway.family) + sizeof(m->gateway.family));
557 }
558
559 return 0;
560
561 clear:
562 (*rta)->rta_len -= sizeof(struct rtnexthop);
563 return r;
564 }
565
566 static int append_nexthops(Route *route, sd_netlink_message *req) {
567 _cleanup_free_ struct rtattr *rta = NULL;
568 struct rtnexthop *rtnh;
569 MultipathRoute *m;
570 size_t offset;
571 Iterator i;
572 int r;
573
574 if (ordered_set_isempty(route->multipath_routes))
575 return 0;
576
577 rta = new(struct rtattr, 1);
578 if (!rta)
579 return -ENOMEM;
580
581 *rta = (struct rtattr) {
582 .rta_type = RTA_MULTIPATH,
583 .rta_len = RTA_LENGTH(0),
584 };
585 offset = (uint8_t *) RTA_DATA(rta) - (uint8_t *) rta;
586
587 ORDERED_SET_FOREACH(m, route->multipath_routes, i) {
588 r = append_nexthop_one(route, m, &rta, offset);
589 if (r < 0)
590 return r;
591
592 rtnh = (struct rtnexthop *)((uint8_t *) rta + offset);
593 offset = (uint8_t *) RTNH_NEXT(rtnh) - (uint8_t *) rta;
594 }
595
596 r = sd_netlink_message_append_data(req, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
597 if (r < 0)
598 return r;
599
600 return 0;
601 }
602
603 int route_configure(
604 Route *route,
605 Link *link,
606 link_netlink_message_handler_t callback) {
607
608 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
609 _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
610 int r;
611
612 assert(link);
613 assert(link->manager);
614 assert(link->manager->rtnl);
615 assert(link->ifindex > 0);
616 assert(IN_SET(route->family, AF_INET, AF_INET6));
617 assert(callback);
618
619 if (route_get(link, route, NULL) <= 0 &&
620 set_size(link->routes) >= routes_max())
621 return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
622 "Too many routes are configured, refusing: %m");
623
624 if (DEBUG_LOGGING) {
625 _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
626 char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
627
628 if (!in_addr_is_null(route->family, &route->dst)) {
629 (void) in_addr_to_string(route->family, &route->dst, &dst);
630 (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen);
631 }
632 if (!in_addr_is_null(route->family, &route->src))
633 (void) in_addr_to_string(route->family, &route->src, &src);
634 if (!in_addr_is_null(route->family, &route->gw))
635 (void) in_addr_to_string(route->family, &route->gw, &gw);
636 if (!in_addr_is_null(route->family, &route->prefsrc))
637 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
638
639 log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
640 strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc),
641 format_route_scope(route->scope, scope, sizeof(scope)),
642 format_route_table(route->table, table, sizeof(table)),
643 format_route_protocol(route->protocol, protocol, sizeof(protocol)),
644 strna(route_type_to_string(route->type)));
645 }
646
647 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
648 RTM_NEWROUTE, route->family,
649 route->protocol);
650 if (r < 0)
651 return log_link_error_errno(link, r, "Could not create RTM_NEWROUTE message: %m");
652
653 if (in_addr_is_null(route->family, &route->gw) == 0) {
654 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
655 if (r < 0)
656 return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
657
658 r = sd_rtnl_message_route_set_family(req, route->family);
659 if (r < 0)
660 return log_link_error_errno(link, r, "Could not set route family: %m");
661 }
662
663 if (route->dst_prefixlen > 0) {
664 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
665 if (r < 0)
666 return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
667
668 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
669 if (r < 0)
670 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
671 }
672
673 if (route->src_prefixlen > 0) {
674 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
675 if (r < 0)
676 return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
677
678 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
679 if (r < 0)
680 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
681 }
682
683 if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
684 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
685 if (r < 0)
686 return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
687 }
688
689 r = sd_rtnl_message_route_set_scope(req, route->scope);
690 if (r < 0)
691 return log_link_error_errno(link, r, "Could not set scope: %m");
692
693 if (route->gateway_onlink >= 0)
694 SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
695
696 r = sd_rtnl_message_route_set_flags(req, route->flags);
697 if (r < 0)
698 return log_link_error_errno(link, r, "Could not set flags: %m");
699
700 if (route->table != RT_TABLE_MAIN) {
701 if (route->table < 256) {
702 r = sd_rtnl_message_route_set_table(req, route->table);
703 if (r < 0)
704 return log_link_error_errno(link, r, "Could not set route table: %m");
705 } else {
706 r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
707 if (r < 0)
708 return log_link_error_errno(link, r, "Could not set route table: %m");
709
710 /* Table attribute to allow more than 256. */
711 r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
712 if (r < 0)
713 return log_link_error_errno(link, r, "Could not append RTA_TABLE attribute: %m");
714 }
715 }
716
717 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
718 if (r < 0)
719 return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
720
721 r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
722 if (r < 0)
723 return log_link_error_errno(link, r, "Could not append RTA_PREF attribute: %m");
724
725 if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
726 r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
727 DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
728 if (r < 0)
729 return log_link_error_errno(link, r, "Could not append RTA_EXPIRES attribute: %m");
730 }
731
732 r = sd_rtnl_message_route_set_type(req, route->type);
733 if (r < 0)
734 return log_link_error_errno(link, r, "Could not set route type: %m");
735
736 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
737 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
738 if (r < 0)
739 return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
740 }
741
742 if (route->ttl_propagate >= 0) {
743 r = sd_netlink_message_append_u8(req, RTA_TTL_PROPAGATE, route->ttl_propagate);
744 if (r < 0)
745 return log_link_error_errno(link, r, "Could not append RTA_TTL_PROPAGATE attribute: %m");
746 }
747
748 r = sd_netlink_message_open_container(req, RTA_METRICS);
749 if (r < 0)
750 return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
751
752 if (route->mtu > 0) {
753 r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
754 if (r < 0)
755 return log_link_error_errno(link, r, "Could not append RTAX_MTU attribute: %m");
756 }
757
758 if (route->initcwnd > 0) {
759 r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
760 if (r < 0)
761 return log_link_error_errno(link, r, "Could not append RTAX_INITCWND attribute: %m");
762 }
763
764 if (route->initrwnd > 0) {
765 r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
766 if (r < 0)
767 return log_link_error_errno(link, r, "Could not append RTAX_INITRWND attribute: %m");
768 }
769
770 if (route->quickack >= 0) {
771 r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
772 if (r < 0)
773 return log_link_error_errno(link, r, "Could not append RTAX_QUICKACK attribute: %m");
774 }
775
776 if (route->fast_open_no_cookie >= 0) {
777 r = sd_netlink_message_append_u32(req, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
778 if (r < 0)
779 return log_link_error_errno(link, r, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
780 }
781
782 r = sd_netlink_message_close_container(req);
783 if (r < 0)
784 return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
785
786 r = append_nexthops(route, req);
787 if (r < 0)
788 return log_link_error_errno(link, r, "Could not append RTA_MULTIPATH attribute: %m");
789
790 r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
791 link_netlink_destroy_callback, link);
792 if (r < 0)
793 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
794
795 link_ref(link);
796
797 r = route_add(link, route, &route);
798 if (r < 0)
799 return log_link_error_errno(link, r, "Could not add route: %m");
800
801 /* TODO: drop expiration handling once it can be pushed into the kernel */
802 if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
803 r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
804 route->lifetime, 0, route_expire_handler, route);
805 if (r < 0)
806 return log_link_error_errno(link, r, "Could not arm expiration timer: %m");
807 }
808
809 sd_event_source_unref(route->expire);
810 route->expire = TAKE_PTR(expire);
811
812 return 1;
813 }
814
815 int network_add_ipv4ll_route(Network *network) {
816 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
817 int r;
818
819 assert(network);
820
821 if (!network->ipv4ll_route)
822 return 0;
823
824 /* IPv4LLRoute= is in [Network] section. */
825 r = route_new_static(network, NULL, 0, &n);
826 if (r < 0)
827 return r;
828
829 r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
830 if (r < 0)
831 return r;
832
833 n->family = AF_INET;
834 n->dst_prefixlen = 16;
835 n->scope = RT_SCOPE_LINK;
836 n->scope_set = true;
837 n->table_set = true;
838 n->priority = IPV4LL_ROUTE_METRIC;
839 n->protocol = RTPROT_STATIC;
840
841 TAKE_PTR(n);
842 return 0;
843 }
844
845 int network_add_default_route_on_device(Network *network) {
846 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
847 int r;
848
849 assert(network);
850
851 if (!network->default_route_on_device)
852 return 0;
853
854 /* DefaultRouteOnDevice= is in [Network] section. */
855 r = route_new_static(network, NULL, 0, &n);
856 if (r < 0)
857 return r;
858
859 n->family = AF_INET;
860 n->scope = RT_SCOPE_LINK;
861 n->scope_set = true;
862 n->protocol = RTPROT_STATIC;
863
864 TAKE_PTR(n);
865 return 0;
866 }
867
868 static const char * const route_type_table[__RTN_MAX] = {
869 [RTN_UNICAST] = "unicast",
870 [RTN_LOCAL] = "local",
871 [RTN_BROADCAST] = "broadcast",
872 [RTN_ANYCAST] = "anycast",
873 [RTN_MULTICAST] = "multicast",
874 [RTN_BLACKHOLE] = "blackhole",
875 [RTN_UNREACHABLE] = "unreachable",
876 [RTN_PROHIBIT] = "prohibit",
877 [RTN_THROW] = "throw",
878 [RTN_NAT] = "nat",
879 [RTN_XRESOLVE] = "xresolve",
880 };
881
882 assert_cc(__RTN_MAX <= UCHAR_MAX);
883 DEFINE_STRING_TABLE_LOOKUP(route_type, int);
884
885 static const char * const route_scope_table[] = {
886 [RT_SCOPE_UNIVERSE] = "global",
887 [RT_SCOPE_SITE] = "site",
888 [RT_SCOPE_LINK] = "link",
889 [RT_SCOPE_HOST] = "host",
890 [RT_SCOPE_NOWHERE] = "nowhere",
891 };
892
893 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int);
894
895 const char *format_route_scope(int scope, char *buf, size_t size) {
896 const char *s;
897 char *p = buf;
898
899 s = route_scope_to_string(scope);
900 if (s)
901 strpcpy(&p, size, s);
902 else
903 strpcpyf(&p, size, "%d", scope);
904
905 return buf;
906 }
907
908 static const char * const route_table_table[] = {
909 [RT_TABLE_DEFAULT] = "default",
910 [RT_TABLE_MAIN] = "main",
911 [RT_TABLE_LOCAL] = "local",
912 };
913
914 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
915
916 const char *format_route_table(int table, char *buf, size_t size) {
917 const char *s;
918 char *p = buf;
919
920 s = route_table_to_string(table);
921 if (s)
922 strpcpy(&p, size, s);
923 else
924 strpcpyf(&p, size, "%d", table);
925
926 return buf;
927 }
928
929 static const char * const route_protocol_table[] = {
930 [RTPROT_KERNEL] = "kernel",
931 [RTPROT_BOOT] = "boot",
932 [RTPROT_STATIC] = "static",
933 };
934
935 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int);
936
937 static const char * const route_protocol_full_table[] = {
938 [RTPROT_REDIRECT] = "redirect",
939 [RTPROT_KERNEL] = "kernel",
940 [RTPROT_BOOT] = "boot",
941 [RTPROT_STATIC] = "static",
942 [RTPROT_GATED] = "gated",
943 [RTPROT_RA] = "ra",
944 [RTPROT_MRT] = "mrt",
945 [RTPROT_ZEBRA] = "zebra",
946 [RTPROT_BIRD] = "bird",
947 [RTPROT_DNROUTED] = "dnrouted",
948 [RTPROT_XORP] = "xorp",
949 [RTPROT_NTK] = "ntk",
950 [RTPROT_DHCP] = "dhcp",
951 [RTPROT_MROUTED] = "mrouted",
952 [RTPROT_BABEL] = "babel",
953 [RTPROT_BGP] = "bgp",
954 [RTPROT_ISIS] = "isis",
955 [RTPROT_OSPF] = "ospf",
956 [RTPROT_RIP] = "rip",
957 [RTPROT_EIGRP] = "eigrp",
958 };
959
960 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int);
961
962 const char *format_route_protocol(int protocol, char *buf, size_t size) {
963 const char *s;
964 char *p = buf;
965
966 s = route_protocol_full_to_string(protocol);
967 if (s)
968 strpcpy(&p, size, s);
969 else
970 strpcpyf(&p, size, "%d", protocol);
971
972 return buf;
973 }
974
975 int config_parse_gateway(
976 const char *unit,
977 const char *filename,
978 unsigned line,
979 const char *section,
980 unsigned section_line,
981 const char *lvalue,
982 int ltype,
983 const char *rvalue,
984 void *data,
985 void *userdata) {
986
987 Network *network = userdata;
988 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
989 int r;
990
991 assert(filename);
992 assert(section);
993 assert(lvalue);
994 assert(rvalue);
995 assert(data);
996
997 if (streq(section, "Network")) {
998 /* we are not in an Route section, so treat
999 * this as the special '0' section */
1000 r = route_new_static(network, NULL, 0, &n);
1001 if (r < 0)
1002 return r;
1003 } else {
1004 r = route_new_static(network, filename, section_line, &n);
1005 if (r < 0)
1006 return r;
1007
1008 if (streq(rvalue, "dhcp")) {
1009 n->gateway_from_dhcp = true;
1010 TAKE_PTR(n);
1011 return 0;
1012 }
1013 }
1014
1015 if (n->family == AF_UNSPEC)
1016 r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
1017 else
1018 r = in_addr_from_string(n->family, rvalue, &n->gw);
1019 if (r < 0) {
1020 log_syntax(unit, LOG_ERR, filename, line, r,
1021 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
1022 return 0;
1023 }
1024
1025 TAKE_PTR(n);
1026 return 0;
1027 }
1028
1029 int config_parse_preferred_src(
1030 const char *unit,
1031 const char *filename,
1032 unsigned line,
1033 const char *section,
1034 unsigned section_line,
1035 const char *lvalue,
1036 int ltype,
1037 const char *rvalue,
1038 void *data,
1039 void *userdata) {
1040
1041 Network *network = userdata;
1042 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1043 int r;
1044
1045 assert(filename);
1046 assert(section);
1047 assert(lvalue);
1048 assert(rvalue);
1049 assert(data);
1050
1051 r = route_new_static(network, filename, section_line, &n);
1052 if (r < 0)
1053 return r;
1054
1055 if (n->family == AF_UNSPEC)
1056 r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
1057 else
1058 r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
1059 if (r < 0) {
1060 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1061 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
1062 return 0;
1063 }
1064
1065 TAKE_PTR(n);
1066 return 0;
1067 }
1068
1069 int config_parse_destination(
1070 const char *unit,
1071 const char *filename,
1072 unsigned line,
1073 const char *section,
1074 unsigned section_line,
1075 const char *lvalue,
1076 int ltype,
1077 const char *rvalue,
1078 void *data,
1079 void *userdata) {
1080
1081 Network *network = userdata;
1082 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1083 union in_addr_union *buffer;
1084 unsigned char *prefixlen;
1085 int r;
1086
1087 assert(filename);
1088 assert(section);
1089 assert(lvalue);
1090 assert(rvalue);
1091 assert(data);
1092
1093 r = route_new_static(network, filename, section_line, &n);
1094 if (r < 0)
1095 return r;
1096
1097 if (streq(lvalue, "Destination")) {
1098 buffer = &n->dst;
1099 prefixlen = &n->dst_prefixlen;
1100 } else if (streq(lvalue, "Source")) {
1101 buffer = &n->src;
1102 prefixlen = &n->src_prefixlen;
1103 } else
1104 assert_not_reached(lvalue);
1105
1106 if (n->family == AF_UNSPEC)
1107 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
1108 else
1109 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
1110 if (r < 0) {
1111 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1112 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
1113 return 0;
1114 }
1115
1116 TAKE_PTR(n);
1117 return 0;
1118 }
1119
1120 int config_parse_route_priority(
1121 const char *unit,
1122 const char *filename,
1123 unsigned line,
1124 const char *section,
1125 unsigned section_line,
1126 const char *lvalue,
1127 int ltype,
1128 const char *rvalue,
1129 void *data,
1130 void *userdata) {
1131
1132 Network *network = userdata;
1133 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1134 int r;
1135
1136 assert(filename);
1137 assert(section);
1138 assert(lvalue);
1139 assert(rvalue);
1140 assert(data);
1141
1142 r = route_new_static(network, filename, section_line, &n);
1143 if (r < 0)
1144 return r;
1145
1146 r = safe_atou32(rvalue, &n->priority);
1147 if (r < 0) {
1148 log_syntax(unit, LOG_ERR, filename, line, r,
1149 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
1150 return 0;
1151 }
1152
1153 TAKE_PTR(n);
1154 return 0;
1155 }
1156
1157 int config_parse_route_scope(
1158 const char *unit,
1159 const char *filename,
1160 unsigned line,
1161 const char *section,
1162 unsigned section_line,
1163 const char *lvalue,
1164 int ltype,
1165 const char *rvalue,
1166 void *data,
1167 void *userdata) {
1168
1169 Network *network = userdata;
1170 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1171 int r;
1172
1173 assert(filename);
1174 assert(section);
1175 assert(lvalue);
1176 assert(rvalue);
1177 assert(data);
1178
1179 r = route_new_static(network, filename, section_line, &n);
1180 if (r < 0)
1181 return r;
1182
1183 r = route_scope_from_string(rvalue);
1184 if (r < 0) {
1185 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue);
1186 return 0;
1187 }
1188
1189 n->scope = r;
1190 n->scope_set = true;
1191 TAKE_PTR(n);
1192 return 0;
1193 }
1194
1195 int config_parse_route_table(
1196 const char *unit,
1197 const char *filename,
1198 unsigned line,
1199 const char *section,
1200 unsigned section_line,
1201 const char *lvalue,
1202 int ltype,
1203 const char *rvalue,
1204 void *data,
1205 void *userdata) {
1206
1207 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1208 Network *network = userdata;
1209 int r;
1210
1211 assert(filename);
1212 assert(section);
1213 assert(lvalue);
1214 assert(rvalue);
1215 assert(data);
1216
1217 r = route_new_static(network, filename, section_line, &n);
1218 if (r < 0)
1219 return r;
1220
1221 r = route_table_from_string(rvalue);
1222 if (r >= 0)
1223 n->table = r;
1224 else {
1225 r = safe_atou32(rvalue, &n->table);
1226 if (r < 0) {
1227 log_syntax(unit, LOG_ERR, filename, line, r,
1228 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
1229 return 0;
1230 }
1231 }
1232
1233 n->table_set = true;
1234 TAKE_PTR(n);
1235 return 0;
1236 }
1237
1238 int config_parse_gateway_onlink(
1239 const char *unit,
1240 const char *filename,
1241 unsigned line,
1242 const char *section,
1243 unsigned section_line,
1244 const char *lvalue,
1245 int ltype,
1246 const char *rvalue,
1247 void *data,
1248 void *userdata) {
1249
1250 Network *network = userdata;
1251 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1252 int r;
1253
1254 assert(filename);
1255 assert(section);
1256 assert(lvalue);
1257 assert(rvalue);
1258 assert(data);
1259
1260 r = route_new_static(network, filename, section_line, &n);
1261 if (r < 0)
1262 return r;
1263
1264 r = parse_boolean(rvalue);
1265 if (r < 0) {
1266 log_syntax(unit, LOG_ERR, filename, line, r,
1267 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
1268 return 0;
1269 }
1270
1271 n->gateway_onlink = r;
1272
1273 TAKE_PTR(n);
1274 return 0;
1275 }
1276
1277 int config_parse_ipv6_route_preference(
1278 const char *unit,
1279 const char *filename,
1280 unsigned line,
1281 const char *section,
1282 unsigned section_line,
1283 const char *lvalue,
1284 int ltype,
1285 const char *rvalue,
1286 void *data,
1287 void *userdata) {
1288
1289 Network *network = userdata;
1290 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1291 int r;
1292
1293 r = route_new_static(network, filename, section_line, &n);
1294 if (r < 0)
1295 return r;
1296
1297 if (streq(rvalue, "low"))
1298 n->pref = ICMPV6_ROUTER_PREF_LOW;
1299 else if (streq(rvalue, "medium"))
1300 n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
1301 else if (streq(rvalue, "high"))
1302 n->pref = ICMPV6_ROUTER_PREF_HIGH;
1303 else {
1304 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route preference: %s", rvalue);
1305 return 0;
1306 }
1307
1308 TAKE_PTR(n);
1309 return 0;
1310 }
1311
1312 int config_parse_route_protocol(
1313 const char *unit,
1314 const char *filename,
1315 unsigned line,
1316 const char *section,
1317 unsigned section_line,
1318 const char *lvalue,
1319 int ltype,
1320 const char *rvalue,
1321 void *data,
1322 void *userdata) {
1323
1324 Network *network = userdata;
1325 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1326 int r;
1327
1328 r = route_new_static(network, filename, section_line, &n);
1329 if (r < 0)
1330 return r;
1331
1332 r = route_protocol_from_string(rvalue);
1333 if (r >= 0)
1334 n->protocol = r;
1335 else {
1336 r = safe_atou8(rvalue , &n->protocol);
1337 if (r < 0) {
1338 log_syntax(unit, LOG_ERR, filename, line, r,
1339 "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
1340 return 0;
1341 }
1342 }
1343
1344 TAKE_PTR(n);
1345 return 0;
1346 }
1347
1348 int config_parse_route_type(
1349 const char *unit,
1350 const char *filename,
1351 unsigned line,
1352 const char *section,
1353 unsigned section_line,
1354 const char *lvalue,
1355 int ltype,
1356 const char *rvalue,
1357 void *data,
1358 void *userdata) {
1359
1360 Network *network = userdata;
1361 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1362 int t, r;
1363
1364 r = route_new_static(network, filename, section_line, &n);
1365 if (r < 0)
1366 return r;
1367
1368 t = route_type_from_string(rvalue);
1369 if (t < 0) {
1370 log_syntax(unit, LOG_ERR, filename, line, 0,
1371 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
1372 return 0;
1373 }
1374
1375 n->type = (unsigned char) t;
1376
1377 TAKE_PTR(n);
1378 return 0;
1379 }
1380
1381 int config_parse_tcp_window(
1382 const char *unit,
1383 const char *filename,
1384 unsigned line,
1385 const char *section,
1386 unsigned section_line,
1387 const char *lvalue,
1388 int ltype,
1389 const char *rvalue,
1390 void *data,
1391 void *userdata) {
1392
1393 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1394 Network *network = userdata;
1395 uint64_t k;
1396 int r;
1397
1398 assert(filename);
1399 assert(section);
1400 assert(lvalue);
1401 assert(rvalue);
1402 assert(data);
1403
1404 r = route_new_static(network, filename, section_line, &n);
1405 if (r < 0)
1406 return r;
1407
1408 r = parse_size(rvalue, 1024, &k);
1409 if (r < 0) {
1410 log_syntax(unit, LOG_ERR, filename, line, r,
1411 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
1412 return 0;
1413 }
1414 if (k > UINT32_MAX) {
1415 log_syntax(unit, LOG_ERR, filename, line, 0,
1416 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
1417 return 0;
1418 }
1419
1420 if (streq(lvalue, "InitialCongestionWindow"))
1421 n->initcwnd = k;
1422 else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
1423 n->initrwnd = k;
1424 else
1425 assert_not_reached("Invalid TCP window type.");
1426
1427 TAKE_PTR(n);
1428 return 0;
1429 }
1430
1431 int config_parse_quickack(
1432 const char *unit,
1433 const char *filename,
1434 unsigned line,
1435 const char *section,
1436 unsigned section_line,
1437 const char *lvalue,
1438 int ltype,
1439 const char *rvalue,
1440 void *data,
1441 void *userdata) {
1442
1443 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1444 Network *network = userdata;
1445 int k, r;
1446
1447 assert(filename);
1448 assert(section);
1449 assert(lvalue);
1450 assert(rvalue);
1451 assert(data);
1452
1453 r = route_new_static(network, filename, section_line, &n);
1454 if (r < 0)
1455 return r;
1456
1457 k = parse_boolean(rvalue);
1458 if (k < 0) {
1459 log_syntax(unit, LOG_ERR, filename, line, k,
1460 "Failed to parse TCP quickack, ignoring: %s", rvalue);
1461 return 0;
1462 }
1463
1464 n->quickack = !!k;
1465 TAKE_PTR(n);
1466 return 0;
1467 }
1468
1469 int config_parse_fast_open_no_cookie(
1470 const char *unit,
1471 const char *filename,
1472 unsigned line,
1473 const char *section,
1474 unsigned section_line,
1475 const char *lvalue,
1476 int ltype,
1477 const char *rvalue,
1478 void *data,
1479 void *userdata) {
1480
1481 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1482 Network *network = userdata;
1483 int k, r;
1484
1485 assert(filename);
1486 assert(section);
1487 assert(lvalue);
1488 assert(rvalue);
1489 assert(data);
1490
1491 r = route_new_static(network, filename, section_line, &n);
1492 if (r < 0)
1493 return r;
1494
1495 k = parse_boolean(rvalue);
1496 if (k < 0) {
1497 log_syntax(unit, LOG_ERR, filename, line, k,
1498 "Failed to parse TCP fastopen no cookie, ignoring: %s", rvalue);
1499 return 0;
1500 }
1501
1502 n->fast_open_no_cookie = k;
1503 TAKE_PTR(n);
1504 return 0;
1505 }
1506
1507 int config_parse_route_mtu(
1508 const char *unit,
1509 const char *filename,
1510 unsigned line,
1511 const char *section,
1512 unsigned section_line,
1513 const char *lvalue,
1514 int ltype,
1515 const char *rvalue,
1516 void *data,
1517 void *userdata) {
1518
1519 Network *network = userdata;
1520 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1521 int r;
1522
1523 assert(filename);
1524 assert(section);
1525 assert(lvalue);
1526 assert(rvalue);
1527 assert(data);
1528
1529 r = route_new_static(network, filename, section_line, &n);
1530 if (r < 0)
1531 return r;
1532
1533 r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &n->mtu, userdata);
1534 if (r < 0)
1535 return r;
1536
1537 TAKE_PTR(n);
1538 return 0;
1539 }
1540
1541 int config_parse_route_ttl_propagate(
1542 const char *unit,
1543 const char *filename,
1544 unsigned line,
1545 const char *section,
1546 unsigned section_line,
1547 const char *lvalue,
1548 int ltype,
1549 const char *rvalue,
1550 void *data,
1551 void *userdata) {
1552
1553 Network *network = userdata;
1554 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1555 int r, k;
1556
1557 assert(filename);
1558 assert(section);
1559 assert(lvalue);
1560 assert(rvalue);
1561 assert(data);
1562
1563 r = route_new_static(network, filename, section_line, &n);
1564 if (r < 0)
1565 return r;
1566
1567 k = parse_boolean(rvalue);
1568 if (k < 0) {
1569 log_syntax(unit, LOG_ERR, filename, line, k,
1570 "Failed to parse TTLPropagate= value, ignoring: %s", rvalue);
1571 return 0;
1572 }
1573
1574 n->ttl_propagate = k;
1575
1576 TAKE_PTR(n);
1577 return 0;
1578 }
1579
1580 int config_parse_multipath_route(
1581 const char *unit,
1582 const char *filename,
1583 unsigned line,
1584 const char *section,
1585 unsigned section_line,
1586 const char *lvalue,
1587 int ltype,
1588 const char *rvalue,
1589 void *data,
1590 void *userdata) {
1591
1592 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1593 _cleanup_free_ char *word = NULL, *buf = NULL;
1594 _cleanup_free_ MultipathRoute *m = NULL;
1595 Network *network = userdata;
1596 const char *p, *ip, *dev;
1597 union in_addr_union a;
1598 int family, r;
1599
1600 assert(filename);
1601 assert(section);
1602 assert(lvalue);
1603 assert(rvalue);
1604 assert(data);
1605
1606 r = route_new_static(network, filename, section_line, &n);
1607 if (r < 0)
1608 return r;
1609
1610 if (isempty(rvalue)) {
1611 n->multipath_routes = ordered_set_free_free(n->multipath_routes);
1612 return 0;
1613 }
1614
1615 m = new0(MultipathRoute, 1);
1616 if (!m)
1617 return log_oom();
1618
1619 p = rvalue;
1620 r = extract_first_word(&p, &word, NULL, 0);
1621 if (r == -ENOMEM)
1622 return log_oom();
1623 if (r <= 0) {
1624 log_syntax(unit, LOG_ERR, filename, line, r,
1625 "Invalid multipath route option, ignoring assignment: %s", rvalue);
1626 return 0;
1627 }
1628
1629 dev = strchr(word, '@');
1630 if (dev) {
1631 buf = strndup(word, dev - word);
1632 if (!buf)
1633 return log_oom();
1634 ip = buf;
1635 dev++;
1636 } else
1637 ip = word;
1638
1639 r = in_addr_from_string_auto(ip, &family, &a);
1640 if (r < 0) {
1641 log_syntax(unit, LOG_ERR, filename, line, r,
1642 "Invalid multipath route gateway '%s', ignoring assignment: %m", rvalue);
1643 return 0;
1644 }
1645 m->gateway.address = a;
1646 m->gateway.family = family;
1647
1648 if (dev) {
1649 r = parse_ifindex_or_ifname(dev, &m->ifindex);
1650 if (r < 0) {
1651 log_syntax(unit, LOG_ERR, filename, line, r,
1652 "Invalid interface name or index, ignoring assignment: %s", dev);
1653 return 0;
1654 }
1655 }
1656
1657 if (!isempty(p)) {
1658 r = safe_atou32(p, &m->weight);
1659 if (r < 0) {
1660 log_syntax(unit, LOG_ERR, filename, line, r,
1661 "Invalid multipath route weight, ignoring assignment: %s", p);
1662 return 0;
1663 }
1664 if (m->weight == 0 || m->weight > 256) {
1665 log_syntax(unit, LOG_ERR, filename, line, 0,
1666 "Invalid multipath route weight, ignoring assignment: %s", p);
1667 return 0;
1668 }
1669 }
1670
1671 r = ordered_set_ensure_allocated(&n->multipath_routes, NULL);
1672 if (r < 0)
1673 return log_oom();
1674
1675 r = ordered_set_put(n->multipath_routes, m);
1676 if (r < 0) {
1677 log_syntax(unit, LOG_ERR, filename, line, r,
1678 "Failed to store multipath route, ignoring assignment: %m");
1679 return 0;
1680 }
1681
1682 TAKE_PTR(m);
1683 TAKE_PTR(n);
1684 return 0;
1685 }
1686
1687 int route_section_verify(Route *route, Network *network) {
1688 if (section_is_invalid(route->section))
1689 return -EINVAL;
1690
1691 if (route->family == AF_UNSPEC) {
1692 assert(route->section);
1693
1694 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
1695 "%s: Route section without Gateway=, Destination=, Source=, "
1696 "or PreferredSource= field configured. "
1697 "Ignoring [Route] section from line %u.",
1698 route->section->filename, route->section->line);
1699 }
1700
1701 if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
1702 route->table = RT_TABLE_LOCAL;
1703
1704 if (!route->scope_set && route->family != AF_INET6) {
1705 if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
1706 route->scope = RT_SCOPE_HOST;
1707 else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
1708 route->scope = RT_SCOPE_LINK;
1709 }
1710
1711 if (network->n_static_addresses == 0 &&
1712 in_addr_is_null(route->family, &route->gw) == 0 &&
1713 route->gateway_onlink < 0) {
1714 log_warning("%s: Gateway= without static address configured. "
1715 "Enabling GatewayOnLink= option.",
1716 network->filename);
1717 route->gateway_onlink = true;
1718 }
1719
1720 return 0;
1721 }