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