]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-route.c
network: include NLMSGERR_ATTR_MSG attribute in error message
[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 sd_event_source_unref(route->expire);
148
149 free(route);
150 }
151
152 static void route_hash_func(const Route *route, struct siphash *state) {
153 assert(route);
154
155 siphash24_compress(&route->family, sizeof(route->family), state);
156
157 switch (route->family) {
158 case AF_INET:
159 case AF_INET6:
160 siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state);
161 siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state);
162
163 siphash24_compress(&route->src_prefixlen, sizeof(route->src_prefixlen), state);
164 siphash24_compress(&route->src, FAMILY_ADDRESS_SIZE(route->family), state);
165
166 siphash24_compress(&route->gw, FAMILY_ADDRESS_SIZE(route->family), state);
167
168 siphash24_compress(&route->prefsrc, FAMILY_ADDRESS_SIZE(route->family), state);
169
170 siphash24_compress(&route->tos, sizeof(route->tos), state);
171 siphash24_compress(&route->priority, sizeof(route->priority), state);
172 siphash24_compress(&route->table, sizeof(route->table), state);
173 siphash24_compress(&route->protocol, sizeof(route->protocol), state);
174 siphash24_compress(&route->scope, sizeof(route->scope), state);
175 siphash24_compress(&route->type, sizeof(route->type), state);
176
177 siphash24_compress(&route->initcwnd, sizeof(route->initcwnd), state);
178 siphash24_compress(&route->initrwnd, sizeof(route->initrwnd), state);
179
180 break;
181 default:
182 /* treat any other address family as AF_UNSPEC */
183 break;
184 }
185 }
186
187 static int route_compare_func(const Route *a, const Route *b) {
188 int r;
189
190 r = CMP(a->family, b->family);
191 if (r != 0)
192 return r;
193
194 switch (a->family) {
195 case AF_INET:
196 case AF_INET6:
197 r = CMP(a->dst_prefixlen, b->dst_prefixlen);
198 if (r != 0)
199 return r;
200
201 r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
202 if (r != 0)
203 return r;
204
205 r = CMP(a->src_prefixlen, b->src_prefixlen);
206 if (r != 0)
207 return r;
208
209 r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
210 if (r != 0)
211 return r;
212
213 r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
214 if (r != 0)
215 return r;
216
217 r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
218 if (r != 0)
219 return r;
220
221 r = CMP(a->tos, b->tos);
222 if (r != 0)
223 return r;
224
225 r = CMP(a->priority, b->priority);
226 if (r != 0)
227 return r;
228
229 r = CMP(a->table, b->table);
230 if (r != 0)
231 return r;
232
233 r = CMP(a->protocol, b->protocol);
234 if (r != 0)
235 return r;
236
237 r = CMP(a->scope, b->scope);
238 if (r != 0)
239 return r;
240
241 r = CMP(a->type, b->type);
242 if (r != 0)
243 return r;
244
245 r = CMP(a->initcwnd, b->initcwnd);
246 if (r != 0)
247 return r;
248
249 r = CMP(a->initrwnd, b->initrwnd);
250 if (r != 0)
251 return r;
252
253 return 0;
254 default:
255 /* treat any other address family as AF_UNSPEC */
256 return 0;
257 }
258 }
259
260 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
261 route_hash_ops,
262 Route,
263 route_hash_func,
264 route_compare_func,
265 route_free);
266
267 bool route_equal(Route *r1, Route *r2) {
268 if (r1 == r2)
269 return true;
270
271 if (!r1 || !r2)
272 return false;
273
274 return route_compare_func(r1, r2) == 0;
275 }
276
277 int route_get(Link *link, Route *in, Route **ret) {
278
279 Route *existing;
280
281 assert(link);
282 assert(in);
283
284 existing = set_get(link->routes, in);
285 if (existing) {
286 if (ret)
287 *ret = existing;
288 return 1;
289 }
290
291 existing = set_get(link->routes_foreign, in);
292 if (existing) {
293 if (ret)
294 *ret = existing;
295 return 0;
296 }
297
298 return -ENOENT;
299 }
300
301 static int route_add_internal(Link *link, Set **routes, Route *in, Route **ret) {
302
303 _cleanup_(route_freep) Route *route = NULL;
304 int r;
305
306 assert(link);
307 assert(routes);
308 assert(in);
309
310 r = route_new(&route);
311 if (r < 0)
312 return r;
313
314 route->family = in->family;
315 route->src = in->src;
316 route->src_prefixlen = in->src_prefixlen;
317 route->dst = in->dst;
318 route->dst_prefixlen = in->dst_prefixlen;
319 route->gw = in->gw;
320 route->prefsrc = in->prefsrc;
321 route->scope = in->scope;
322 route->protocol = in->protocol;
323 route->type = in->type;
324 route->tos = in->tos;
325 route->priority = in->priority;
326 route->table = in->table;
327 route->initcwnd = in->initcwnd;
328 route->initrwnd = in->initrwnd;
329 route->lifetime = in->lifetime;
330
331 r = set_ensure_allocated(routes, &route_hash_ops);
332 if (r < 0)
333 return r;
334
335 r = set_put(*routes, 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_allocated(&link->routes, &route_hash_ops);
369 if (r < 0)
370 return r;
371
372 r = set_put(link->routes, route);
373 if (r < 0)
374 return r;
375
376 set_remove(link->routes_foreign, route);
377 } else if (r == 1) {
378 /* Route exists, do nothing */
379 ;
380 } else
381 return r;
382
383 if (ret)
384 *ret = route;
385
386 return 0;
387 }
388
389 static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
390 int r;
391
392 assert(m);
393 assert(link);
394 assert(link->ifname);
395
396 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
397 return 1;
398
399 r = sd_netlink_message_get_errno(m);
400 if (r < 0 && r != -ESRCH)
401 log_link_message_warning_errno(link, m, r, "Could not drop route, ignoring");
402
403 return 1;
404 }
405
406 int route_remove(Route *route, Link *link,
407 link_netlink_message_handler_t callback) {
408
409 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
410 int r;
411
412 assert(link);
413 assert(link->manager);
414 assert(link->manager->rtnl);
415 assert(link->ifindex > 0);
416 assert(IN_SET(route->family, AF_INET, AF_INET6));
417
418 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
419 RTM_DELROUTE, route->family,
420 route->protocol);
421 if (r < 0)
422 return log_link_error_errno(link, r, "Could not create RTM_DELROUTE message: %m");
423
424 if (DEBUG_LOGGING) {
425 _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
426 char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
427
428 if (!in_addr_is_null(route->family, &route->dst)) {
429 (void) in_addr_to_string(route->family, &route->dst, &dst);
430 (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen);
431 }
432 if (!in_addr_is_null(route->family, &route->src))
433 (void) in_addr_to_string(route->family, &route->src, &src);
434 if (!in_addr_is_null(route->family, &route->gw))
435 (void) in_addr_to_string(route->family, &route->gw, &gw);
436 if (!in_addr_is_null(route->family, &route->prefsrc))
437 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
438
439 log_link_debug(link, "Removing route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
440 strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc),
441 format_route_scope(route->scope, scope, sizeof(scope)),
442 format_route_table(route->table, table, sizeof(table)),
443 format_route_protocol(route->protocol, protocol, sizeof(protocol)),
444 strna(route_type_to_string(route->type)));
445 }
446
447 if (in_addr_is_null(route->family, &route->gw) == 0) {
448 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
449 if (r < 0)
450 return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
451 }
452
453 if (route->dst_prefixlen) {
454 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
455 if (r < 0)
456 return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
457
458 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
459 if (r < 0)
460 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
461 }
462
463 if (route->src_prefixlen) {
464 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
465 if (r < 0)
466 return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
467
468 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
469 if (r < 0)
470 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
471 }
472
473 if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
474 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
475 if (r < 0)
476 return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
477 }
478
479 r = sd_rtnl_message_route_set_scope(req, route->scope);
480 if (r < 0)
481 return log_link_error_errno(link, r, "Could not set scope: %m");
482
483 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
484 if (r < 0)
485 return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
486
487 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
488 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
489 if (r < 0)
490 return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
491 }
492
493 r = netlink_call_async(link->manager->rtnl, NULL, req,
494 callback ?: route_remove_handler,
495 link_netlink_destroy_callback, link);
496 if (r < 0)
497 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
498
499 link_ref(link);
500
501 return 0;
502 }
503
504 int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
505 Route *route = userdata;
506 int r;
507
508 assert(route);
509
510 r = route_remove(route, route->link, NULL);
511 if (r < 0)
512 log_warning_errno(r, "Could not remove route: %m");
513 else
514 route_free(route);
515
516 return 1;
517 }
518
519 int route_configure(
520 Route *route,
521 Link *link,
522 link_netlink_message_handler_t callback) {
523
524 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
525 _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL;
526 int r;
527
528 assert(link);
529 assert(link->manager);
530 assert(link->manager->rtnl);
531 assert(link->ifindex > 0);
532 assert(IN_SET(route->family, AF_INET, AF_INET6));
533 assert(callback);
534
535 if (route_get(link, route, NULL) <= 0 &&
536 set_size(link->routes) >= routes_max())
537 return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
538 "Too many routes are configured, refusing: %m");
539
540 if (DEBUG_LOGGING) {
541 _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
542 char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX];
543
544 if (!in_addr_is_null(route->family, &route->dst)) {
545 (void) in_addr_to_string(route->family, &route->dst, &dst);
546 (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen);
547 }
548 if (!in_addr_is_null(route->family, &route->src))
549 (void) in_addr_to_string(route->family, &route->src, &src);
550 if (!in_addr_is_null(route->family, &route->gw))
551 (void) in_addr_to_string(route->family, &route->gw, &gw);
552 if (!in_addr_is_null(route->family, &route->prefsrc))
553 (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
554
555 log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
556 strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc),
557 format_route_scope(route->scope, scope, sizeof(scope)),
558 format_route_table(route->table, table, sizeof(table)),
559 format_route_protocol(route->protocol, protocol, sizeof(protocol)),
560 strna(route_type_to_string(route->type)));
561 }
562
563 r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
564 RTM_NEWROUTE, route->family,
565 route->protocol);
566 if (r < 0)
567 return log_link_error_errno(link, r, "Could not create RTM_NEWROUTE message: %m");
568
569 if (in_addr_is_null(route->family, &route->gw) == 0) {
570 r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
571 if (r < 0)
572 return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
573
574 r = sd_rtnl_message_route_set_family(req, route->family);
575 if (r < 0)
576 return log_link_error_errno(link, r, "Could not set route family: %m");
577 }
578
579 if (route->dst_prefixlen > 0) {
580 r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
581 if (r < 0)
582 return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
583
584 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
585 if (r < 0)
586 return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
587 }
588
589 if (route->src_prefixlen > 0) {
590 r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
591 if (r < 0)
592 return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
593
594 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
595 if (r < 0)
596 return log_link_error_errno(link, r, "Could not set source prefix length: %m");
597 }
598
599 if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
600 r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
601 if (r < 0)
602 return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
603 }
604
605 r = sd_rtnl_message_route_set_scope(req, route->scope);
606 if (r < 0)
607 return log_link_error_errno(link, r, "Could not set scope: %m");
608
609 if (route->gateway_onlink >= 0)
610 SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
611
612 r = sd_rtnl_message_route_set_flags(req, route->flags);
613 if (r < 0)
614 return log_link_error_errno(link, r, "Could not set flags: %m");
615
616 if (route->table != RT_TABLE_MAIN) {
617 if (route->table < 256) {
618 r = sd_rtnl_message_route_set_table(req, route->table);
619 if (r < 0)
620 return log_link_error_errno(link, r, "Could not set route table: %m");
621 } else {
622 r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
623 if (r < 0)
624 return log_link_error_errno(link, r, "Could not set route table: %m");
625
626 /* Table attribute to allow more than 256. */
627 r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
628 if (r < 0)
629 return log_link_error_errno(link, r, "Could not append RTA_TABLE attribute: %m");
630 }
631 }
632
633 r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
634 if (r < 0)
635 return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
636
637 r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
638 if (r < 0)
639 return log_link_error_errno(link, r, "Could not append RTA_PREF attribute: %m");
640
641 if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
642 r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
643 DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
644 if (r < 0)
645 return log_link_error_errno(link, r, "Could not append RTA_EXPIRES attribute: %m");
646 }
647
648 r = sd_rtnl_message_route_set_type(req, route->type);
649 if (r < 0)
650 return log_link_error_errno(link, r, "Could not set route type: %m");
651
652 if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
653 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
654 if (r < 0)
655 return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
656 }
657
658 if (route->ttl_propagate >= 0) {
659 r = sd_netlink_message_append_u8(req, RTA_TTL_PROPAGATE, route->ttl_propagate);
660 if (r < 0)
661 return log_link_error_errno(link, r, "Could not append RTA_TTL_PROPAGATE attribute: %m");
662 }
663
664 r = sd_netlink_message_open_container(req, RTA_METRICS);
665 if (r < 0)
666 return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
667
668 if (route->mtu > 0) {
669 r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
670 if (r < 0)
671 return log_link_error_errno(link, r, "Could not append RTAX_MTU attribute: %m");
672 }
673
674 if (route->initcwnd > 0) {
675 r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
676 if (r < 0)
677 return log_link_error_errno(link, r, "Could not append RTAX_INITCWND attribute: %m");
678 }
679
680 if (route->initrwnd > 0) {
681 r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
682 if (r < 0)
683 return log_link_error_errno(link, r, "Could not append RTAX_INITRWND attribute: %m");
684 }
685
686 if (route->quickack >= 0) {
687 r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
688 if (r < 0)
689 return log_link_error_errno(link, r, "Could not append RTAX_QUICKACK attribute: %m");
690 }
691
692 if (route->fast_open_no_cookie >= 0) {
693 r = sd_netlink_message_append_u32(req, RTAX_FASTOPEN_NO_COOKIE, route->fast_open_no_cookie);
694 if (r < 0)
695 return log_link_error_errno(link, r, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m");
696 }
697
698 r = sd_netlink_message_close_container(req);
699 if (r < 0)
700 return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
701
702 r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
703 link_netlink_destroy_callback, link);
704 if (r < 0)
705 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
706
707 link_ref(link);
708
709 r = route_add(link, route, &route);
710 if (r < 0)
711 return log_link_error_errno(link, r, "Could not add route: %m");
712
713 /* TODO: drop expiration handling once it can be pushed into the kernel */
714 if (route->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) {
715 r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
716 route->lifetime, 0, route_expire_handler, route);
717 if (r < 0)
718 return log_link_error_errno(link, r, "Could not arm expiration timer: %m");
719 }
720
721 sd_event_source_unref(route->expire);
722 route->expire = TAKE_PTR(expire);
723
724 return 1;
725 }
726
727 int network_add_ipv4ll_route(Network *network) {
728 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
729 int r;
730
731 assert(network);
732
733 if (!network->ipv4ll_route)
734 return 0;
735
736 /* IPv4LLRoute= is in [Network] section. */
737 r = route_new_static(network, NULL, 0, &n);
738 if (r < 0)
739 return r;
740
741 r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
742 if (r < 0)
743 return r;
744
745 n->family = AF_INET;
746 n->dst_prefixlen = 16;
747 n->scope = RT_SCOPE_LINK;
748 n->scope_set = true;
749 n->table_set = true;
750 n->priority = IPV4LL_ROUTE_METRIC;
751 n->protocol = RTPROT_STATIC;
752
753 TAKE_PTR(n);
754 return 0;
755 }
756
757 int network_add_default_route_on_device(Network *network) {
758 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
759 int r;
760
761 assert(network);
762
763 if (!network->default_route_on_device)
764 return 0;
765
766 /* DefaultRouteOnDevice= is in [Network] section. */
767 r = route_new_static(network, NULL, 0, &n);
768 if (r < 0)
769 return r;
770
771 n->family = AF_INET;
772 n->scope = RT_SCOPE_LINK;
773 n->scope_set = true;
774 n->protocol = RTPROT_STATIC;
775
776 TAKE_PTR(n);
777 return 0;
778 }
779
780 static const char * const route_type_table[__RTN_MAX] = {
781 [RTN_UNICAST] = "unicast",
782 [RTN_LOCAL] = "local",
783 [RTN_BROADCAST] = "broadcast",
784 [RTN_ANYCAST] = "anycast",
785 [RTN_MULTICAST] = "multicast",
786 [RTN_BLACKHOLE] = "blackhole",
787 [RTN_UNREACHABLE] = "unreachable",
788 [RTN_PROHIBIT] = "prohibit",
789 [RTN_THROW] = "throw",
790 [RTN_NAT] = "nat",
791 [RTN_XRESOLVE] = "xresolve",
792 };
793
794 assert_cc(__RTN_MAX <= UCHAR_MAX);
795 DEFINE_STRING_TABLE_LOOKUP(route_type, int);
796
797 static const char * const route_scope_table[] = {
798 [RT_SCOPE_UNIVERSE] = "global",
799 [RT_SCOPE_SITE] = "site",
800 [RT_SCOPE_LINK] = "link",
801 [RT_SCOPE_HOST] = "host",
802 [RT_SCOPE_NOWHERE] = "nowhere",
803 };
804
805 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int);
806
807 const char *format_route_scope(int scope, char *buf, size_t size) {
808 const char *s;
809 char *p = buf;
810
811 s = route_scope_to_string(scope);
812 if (s)
813 strpcpy(&p, size, s);
814 else
815 strpcpyf(&p, size, "%d", scope);
816
817 return buf;
818 }
819
820 static const char * const route_table_table[] = {
821 [RT_TABLE_DEFAULT] = "default",
822 [RT_TABLE_MAIN] = "main",
823 [RT_TABLE_LOCAL] = "local",
824 };
825
826 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int);
827
828 const char *format_route_table(int table, char *buf, size_t size) {
829 const char *s;
830 char *p = buf;
831
832 s = route_table_to_string(table);
833 if (s)
834 strpcpy(&p, size, s);
835 else
836 strpcpyf(&p, size, "%d", table);
837
838 return buf;
839 }
840
841 static const char * const route_protocol_table[] = {
842 [RTPROT_KERNEL] = "kernel",
843 [RTPROT_BOOT] = "boot",
844 [RTPROT_STATIC] = "static",
845 };
846
847 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int);
848
849 static const char * const route_protocol_full_table[] = {
850 [RTPROT_REDIRECT] = "redirect",
851 [RTPROT_KERNEL] = "kernel",
852 [RTPROT_BOOT] = "boot",
853 [RTPROT_STATIC] = "static",
854 [RTPROT_GATED] = "gated",
855 [RTPROT_RA] = "ra",
856 [RTPROT_MRT] = "mrt",
857 [RTPROT_ZEBRA] = "zebra",
858 [RTPROT_BIRD] = "bird",
859 [RTPROT_DNROUTED] = "dnrouted",
860 [RTPROT_XORP] = "xorp",
861 [RTPROT_NTK] = "ntk",
862 [RTPROT_DHCP] = "dhcp",
863 [RTPROT_MROUTED] = "mrouted",
864 [RTPROT_BABEL] = "babel",
865 [RTPROT_BGP] = "bgp",
866 [RTPROT_ISIS] = "isis",
867 [RTPROT_OSPF] = "ospf",
868 [RTPROT_RIP] = "rip",
869 [RTPROT_EIGRP] = "eigrp",
870 };
871
872 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int);
873
874 const char *format_route_protocol(int protocol, char *buf, size_t size) {
875 const char *s;
876 char *p = buf;
877
878 s = route_protocol_full_to_string(protocol);
879 if (s)
880 strpcpy(&p, size, s);
881 else
882 strpcpyf(&p, size, "%d", protocol);
883
884 return buf;
885 }
886
887 int config_parse_gateway(
888 const char *unit,
889 const char *filename,
890 unsigned line,
891 const char *section,
892 unsigned section_line,
893 const char *lvalue,
894 int ltype,
895 const char *rvalue,
896 void *data,
897 void *userdata) {
898
899 Network *network = userdata;
900 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
901 int r;
902
903 assert(filename);
904 assert(section);
905 assert(lvalue);
906 assert(rvalue);
907 assert(data);
908
909 if (streq(section, "Network")) {
910 /* we are not in an Route section, so treat
911 * this as the special '0' section */
912 r = route_new_static(network, NULL, 0, &n);
913 } else
914 r = route_new_static(network, filename, section_line, &n);
915 if (r < 0)
916 return r;
917
918 if (n->family == AF_UNSPEC)
919 r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
920 else
921 r = in_addr_from_string(n->family, rvalue, &n->gw);
922 if (r < 0) {
923 log_syntax(unit, LOG_ERR, filename, line, r,
924 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
925 return 0;
926 }
927
928 TAKE_PTR(n);
929 return 0;
930 }
931
932 int config_parse_preferred_src(
933 const char *unit,
934 const char *filename,
935 unsigned line,
936 const char *section,
937 unsigned section_line,
938 const char *lvalue,
939 int ltype,
940 const char *rvalue,
941 void *data,
942 void *userdata) {
943
944 Network *network = userdata;
945 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
946 int r;
947
948 assert(filename);
949 assert(section);
950 assert(lvalue);
951 assert(rvalue);
952 assert(data);
953
954 r = route_new_static(network, filename, section_line, &n);
955 if (r < 0)
956 return r;
957
958 if (n->family == AF_UNSPEC)
959 r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
960 else
961 r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
962 if (r < 0) {
963 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
964 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
965 return 0;
966 }
967
968 TAKE_PTR(n);
969 return 0;
970 }
971
972 int config_parse_destination(
973 const char *unit,
974 const char *filename,
975 unsigned line,
976 const char *section,
977 unsigned section_line,
978 const char *lvalue,
979 int ltype,
980 const char *rvalue,
981 void *data,
982 void *userdata) {
983
984 Network *network = userdata;
985 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
986 union in_addr_union *buffer;
987 unsigned char *prefixlen;
988 int r;
989
990 assert(filename);
991 assert(section);
992 assert(lvalue);
993 assert(rvalue);
994 assert(data);
995
996 r = route_new_static(network, filename, section_line, &n);
997 if (r < 0)
998 return r;
999
1000 if (streq(lvalue, "Destination")) {
1001 buffer = &n->dst;
1002 prefixlen = &n->dst_prefixlen;
1003 } else if (streq(lvalue, "Source")) {
1004 buffer = &n->src;
1005 prefixlen = &n->src_prefixlen;
1006 } else
1007 assert_not_reached(lvalue);
1008
1009 if (n->family == AF_UNSPEC)
1010 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
1011 else
1012 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
1013 if (r < 0) {
1014 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
1015 "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
1016 return 0;
1017 }
1018
1019 TAKE_PTR(n);
1020 return 0;
1021 }
1022
1023 int config_parse_route_priority(
1024 const char *unit,
1025 const char *filename,
1026 unsigned line,
1027 const char *section,
1028 unsigned section_line,
1029 const char *lvalue,
1030 int ltype,
1031 const char *rvalue,
1032 void *data,
1033 void *userdata) {
1034
1035 Network *network = userdata;
1036 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1037 int r;
1038
1039 assert(filename);
1040 assert(section);
1041 assert(lvalue);
1042 assert(rvalue);
1043 assert(data);
1044
1045 r = route_new_static(network, filename, section_line, &n);
1046 if (r < 0)
1047 return r;
1048
1049 r = safe_atou32(rvalue, &n->priority);
1050 if (r < 0) {
1051 log_syntax(unit, LOG_ERR, filename, line, r,
1052 "Could not parse route priority \"%s\", ignoring assignment: %m", rvalue);
1053 return 0;
1054 }
1055
1056 TAKE_PTR(n);
1057 return 0;
1058 }
1059
1060 int config_parse_route_scope(
1061 const char *unit,
1062 const char *filename,
1063 unsigned line,
1064 const char *section,
1065 unsigned section_line,
1066 const char *lvalue,
1067 int ltype,
1068 const char *rvalue,
1069 void *data,
1070 void *userdata) {
1071
1072 Network *network = userdata;
1073 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1074 int r;
1075
1076 assert(filename);
1077 assert(section);
1078 assert(lvalue);
1079 assert(rvalue);
1080 assert(data);
1081
1082 r = route_new_static(network, filename, section_line, &n);
1083 if (r < 0)
1084 return r;
1085
1086 r = route_scope_from_string(rvalue);
1087 if (r < 0) {
1088 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue);
1089 return 0;
1090 }
1091
1092 n->scope = r;
1093 n->scope_set = true;
1094 TAKE_PTR(n);
1095 return 0;
1096 }
1097
1098 int config_parse_route_table(
1099 const char *unit,
1100 const char *filename,
1101 unsigned line,
1102 const char *section,
1103 unsigned section_line,
1104 const char *lvalue,
1105 int ltype,
1106 const char *rvalue,
1107 void *data,
1108 void *userdata) {
1109
1110 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1111 Network *network = userdata;
1112 int r;
1113
1114 assert(filename);
1115 assert(section);
1116 assert(lvalue);
1117 assert(rvalue);
1118 assert(data);
1119
1120 r = route_new_static(network, filename, section_line, &n);
1121 if (r < 0)
1122 return r;
1123
1124 r = route_table_from_string(rvalue);
1125 if (r >= 0)
1126 n->table = r;
1127 else {
1128 r = safe_atou32(rvalue, &n->table);
1129 if (r < 0) {
1130 log_syntax(unit, LOG_ERR, filename, line, r,
1131 "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
1132 return 0;
1133 }
1134 }
1135
1136 n->table_set = true;
1137 TAKE_PTR(n);
1138 return 0;
1139 }
1140
1141 int config_parse_gateway_onlink(
1142 const char *unit,
1143 const char *filename,
1144 unsigned line,
1145 const char *section,
1146 unsigned section_line,
1147 const char *lvalue,
1148 int ltype,
1149 const char *rvalue,
1150 void *data,
1151 void *userdata) {
1152
1153 Network *network = userdata;
1154 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1155 int r;
1156
1157 assert(filename);
1158 assert(section);
1159 assert(lvalue);
1160 assert(rvalue);
1161 assert(data);
1162
1163 r = route_new_static(network, filename, section_line, &n);
1164 if (r < 0)
1165 return r;
1166
1167 r = parse_boolean(rvalue);
1168 if (r < 0) {
1169 log_syntax(unit, LOG_ERR, filename, line, r,
1170 "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
1171 return 0;
1172 }
1173
1174 n->gateway_onlink = r;
1175
1176 TAKE_PTR(n);
1177 return 0;
1178 }
1179
1180 int config_parse_ipv6_route_preference(
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 r = route_new_static(network, filename, section_line, &n);
1197 if (r < 0)
1198 return r;
1199
1200 if (streq(rvalue, "low"))
1201 n->pref = ICMPV6_ROUTER_PREF_LOW;
1202 else if (streq(rvalue, "medium"))
1203 n->pref = ICMPV6_ROUTER_PREF_MEDIUM;
1204 else if (streq(rvalue, "high"))
1205 n->pref = ICMPV6_ROUTER_PREF_HIGH;
1206 else {
1207 log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route preference: %s", rvalue);
1208 return 0;
1209 }
1210
1211 TAKE_PTR(n);
1212 return 0;
1213 }
1214
1215 int config_parse_route_protocol(
1216 const char *unit,
1217 const char *filename,
1218 unsigned line,
1219 const char *section,
1220 unsigned section_line,
1221 const char *lvalue,
1222 int ltype,
1223 const char *rvalue,
1224 void *data,
1225 void *userdata) {
1226
1227 Network *network = userdata;
1228 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1229 int r;
1230
1231 r = route_new_static(network, filename, section_line, &n);
1232 if (r < 0)
1233 return r;
1234
1235 r = route_protocol_from_string(rvalue);
1236 if (r >= 0)
1237 n->protocol = r;
1238 else {
1239 r = safe_atou8(rvalue , &n->protocol);
1240 if (r < 0) {
1241 log_syntax(unit, LOG_ERR, filename, line, r,
1242 "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
1243 return 0;
1244 }
1245 }
1246
1247 TAKE_PTR(n);
1248 return 0;
1249 }
1250
1251 int config_parse_route_type(
1252 const char *unit,
1253 const char *filename,
1254 unsigned line,
1255 const char *section,
1256 unsigned section_line,
1257 const char *lvalue,
1258 int ltype,
1259 const char *rvalue,
1260 void *data,
1261 void *userdata) {
1262
1263 Network *network = userdata;
1264 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1265 int t, r;
1266
1267 r = route_new_static(network, filename, section_line, &n);
1268 if (r < 0)
1269 return r;
1270
1271 t = route_type_from_string(rvalue);
1272 if (t < 0) {
1273 log_syntax(unit, LOG_ERR, filename, line, 0,
1274 "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
1275 return 0;
1276 }
1277
1278 n->type = (unsigned char) t;
1279
1280 TAKE_PTR(n);
1281 return 0;
1282 }
1283
1284 int config_parse_tcp_window(
1285 const char *unit,
1286 const char *filename,
1287 unsigned line,
1288 const char *section,
1289 unsigned section_line,
1290 const char *lvalue,
1291 int ltype,
1292 const char *rvalue,
1293 void *data,
1294 void *userdata) {
1295
1296 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1297 Network *network = userdata;
1298 uint64_t k;
1299 int r;
1300
1301 assert(filename);
1302 assert(section);
1303 assert(lvalue);
1304 assert(rvalue);
1305 assert(data);
1306
1307 r = route_new_static(network, filename, section_line, &n);
1308 if (r < 0)
1309 return r;
1310
1311 r = parse_size(rvalue, 1024, &k);
1312 if (r < 0) {
1313 log_syntax(unit, LOG_ERR, filename, line, r,
1314 "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
1315 return 0;
1316 }
1317 if (k > UINT32_MAX) {
1318 log_syntax(unit, LOG_ERR, filename, line, 0,
1319 "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
1320 return 0;
1321 }
1322
1323 if (streq(lvalue, "InitialCongestionWindow"))
1324 n->initcwnd = k;
1325 else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
1326 n->initrwnd = k;
1327 else
1328 assert_not_reached("Invalid TCP window type.");
1329
1330 TAKE_PTR(n);
1331 return 0;
1332 }
1333
1334 int config_parse_quickack(
1335 const char *unit,
1336 const char *filename,
1337 unsigned line,
1338 const char *section,
1339 unsigned section_line,
1340 const char *lvalue,
1341 int ltype,
1342 const char *rvalue,
1343 void *data,
1344 void *userdata) {
1345
1346 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1347 Network *network = userdata;
1348 int k, r;
1349
1350 assert(filename);
1351 assert(section);
1352 assert(lvalue);
1353 assert(rvalue);
1354 assert(data);
1355
1356 r = route_new_static(network, filename, section_line, &n);
1357 if (r < 0)
1358 return r;
1359
1360 k = parse_boolean(rvalue);
1361 if (k < 0) {
1362 log_syntax(unit, LOG_ERR, filename, line, k,
1363 "Failed to parse TCP quickack, ignoring: %s", rvalue);
1364 return 0;
1365 }
1366
1367 n->quickack = !!k;
1368 TAKE_PTR(n);
1369 return 0;
1370 }
1371
1372 int config_parse_fast_open_no_cookie(
1373 const char *unit,
1374 const char *filename,
1375 unsigned line,
1376 const char *section,
1377 unsigned section_line,
1378 const char *lvalue,
1379 int ltype,
1380 const char *rvalue,
1381 void *data,
1382 void *userdata) {
1383
1384 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1385 Network *network = userdata;
1386 int k, r;
1387
1388 assert(filename);
1389 assert(section);
1390 assert(lvalue);
1391 assert(rvalue);
1392 assert(data);
1393
1394 r = route_new_static(network, filename, section_line, &n);
1395 if (r < 0)
1396 return r;
1397
1398 k = parse_boolean(rvalue);
1399 if (k < 0) {
1400 log_syntax(unit, LOG_ERR, filename, line, k,
1401 "Failed to parse TCP fastopen no cookie, ignoring: %s", rvalue);
1402 return 0;
1403 }
1404
1405 n->fast_open_no_cookie = k;
1406 TAKE_PTR(n);
1407 return 0;
1408 }
1409
1410 int config_parse_route_mtu(
1411 const char *unit,
1412 const char *filename,
1413 unsigned line,
1414 const char *section,
1415 unsigned section_line,
1416 const char *lvalue,
1417 int ltype,
1418 const char *rvalue,
1419 void *data,
1420 void *userdata) {
1421
1422 Network *network = userdata;
1423 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1424 int r;
1425
1426 assert(filename);
1427 assert(section);
1428 assert(lvalue);
1429 assert(rvalue);
1430 assert(data);
1431
1432 r = route_new_static(network, filename, section_line, &n);
1433 if (r < 0)
1434 return r;
1435
1436 r = config_parse_mtu(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &n->mtu, userdata);
1437 if (r < 0)
1438 return r;
1439
1440 TAKE_PTR(n);
1441 return 0;
1442 }
1443
1444 int config_parse_route_ttl_propagate(
1445 const char *unit,
1446 const char *filename,
1447 unsigned line,
1448 const char *section,
1449 unsigned section_line,
1450 const char *lvalue,
1451 int ltype,
1452 const char *rvalue,
1453 void *data,
1454 void *userdata) {
1455
1456 Network *network = userdata;
1457 _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
1458 int r, k;
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 < 0)
1468 return r;
1469
1470 k = parse_boolean(rvalue);
1471 if (k < 0) {
1472 log_syntax(unit, LOG_ERR, filename, line, k,
1473 "Failed to parse TTLPropagate= value, ignoring: %s", rvalue);
1474 return 0;
1475 }
1476
1477 n->ttl_propagate = k;
1478
1479 TAKE_PTR(n);
1480 return 0;
1481 }
1482
1483 int route_section_verify(Route *route, Network *network) {
1484 if (section_is_invalid(route->section))
1485 return -EINVAL;
1486
1487 if (route->family == AF_UNSPEC) {
1488 assert(route->section);
1489
1490 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
1491 "%s: Route section without Gateway=, Destination=, Source=, "
1492 "or PreferredSource= field configured. "
1493 "Ignoring [Route] section from line %u.",
1494 route->section->filename, route->section->line);
1495 }
1496
1497 if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
1498 route->table = RT_TABLE_LOCAL;
1499
1500 if (!route->scope_set && route->family != AF_INET6) {
1501 if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
1502 route->scope = RT_SCOPE_HOST;
1503 else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
1504 route->scope = RT_SCOPE_LINK;
1505 }
1506
1507 if (network->n_static_addresses == 0 &&
1508 in_addr_is_null(route->family, &route->gw) == 0 &&
1509 route->gateway_onlink < 0) {
1510 log_warning("%s: Gateway= without static address configured. "
1511 "Enabling GatewayOnLink= option.",
1512 network->filename);
1513 route->gateway_onlink = true;
1514 }
1515
1516 return 0;
1517 }