Coverage Report

Created: 2026-10-28 06:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/network/networkd-route.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3
#include <linux/ipv6_route.h>
4
#include <net/if.h>
5
#include <stdio.h>
6
7
#include "sd-ndisc-protocol.h"
8
#include "sd-netlink.h"
9
10
#include "alloc-util.h"
11
#include "conf-parser.h"
12
#include "errno-util.h"
13
#include "event-util.h"
14
#include "netlink-util.h"
15
#include "networkd-address.h"
16
#include "networkd-ipv4ll.h"
17
#include "networkd-link.h"
18
#include "networkd-manager.h"
19
#include "networkd-network.h"
20
#include "networkd-nexthop.h"
21
#include "networkd-queue.h"
22
#include "networkd-route.h"
23
#include "networkd-route-util.h"
24
#include "ordered-set.h"
25
#include "parse-util.h"
26
#include "set.h"
27
#include "siphash24.h"
28
#include "string-util.h"
29
#include "vrf.h"
30
#include "wireguard.h"
31
32
95.0k
static Route* route_detach_impl(Route *route) {
33
95.0k
        assert(route);
34
95.0k
        assert(!!route->network + !!route->manager + !!route->wireguard <= 1);
35
36
95.0k
        if (route->network) {
37
35.6k
                assert(route->section);
38
35.6k
                hashmap_remove(route->network->routes_by_section, route->section);
39
35.6k
                route->network = NULL;
40
35.6k
                return route;
41
35.6k
        }
42
43
59.3k
        if (route->manager) {
44
0
                route_detach_from_nexthop(route);
45
0
                set_remove(route->manager->routes, route);
46
0
                route->manager = NULL;
47
0
                return route;
48
0
        }
49
50
59.3k
        if (route->wireguard) {
51
6.26k
                set_remove(route->wireguard->routes, route);
52
6.26k
                route->wireguard = NULL;
53
6.26k
                return route;
54
6.26k
        }
55
56
53.1k
        return NULL;
57
59.3k
}
58
59
41.9k
void route_detach(Route *route) {
60
41.9k
        route_unref(route_detach_impl(route));
61
41.9k
}
62
63
53.1k
static Route* route_free(Route *route) {
64
53.1k
        if (!route)
65
0
                return NULL;
66
67
53.1k
        route_detach_impl(route);
68
69
53.1k
        config_section_free(route->section);
70
53.1k
        route_nexthops_done(route);
71
53.1k
        route_metric_done(&route->metric);
72
53.1k
        sd_event_source_disable_unref(route->expire);
73
74
53.1k
        return mfree(route);
75
53.1k
}
76
77
265k
DEFINE_TRIVIAL_REF_UNREF_FUNC(Route, route, route_free);
Unexecuted instantiation: route_ref
Unexecuted instantiation: route_unref
78
265k
79
265k
static void route_hash_func(const Route *route, struct siphash *state) {
80
32.1k
        assert(route);
81
82
32.1k
        siphash24_compress_typesafe(route->family, state);
83
84
32.1k
        switch (route->family) {
85
19.8k
        case AF_INET:
86
                /* First, the table, destination prefix, priority, and tos (dscp), are used to find routes.
87
                 * See fib_table_insert(), fib_find_node(), and fib_find_alias() in net/ipv4/fib_trie.c of the kernel. */
88
19.8k
                siphash24_compress_typesafe(route->table, state);
89
19.8k
                in_addr_hash_func(&route->dst, route->family, state);
90
19.8k
                siphash24_compress_typesafe(route->dst_prefixlen, state);
91
19.8k
                siphash24_compress_typesafe(route->priority, state);
92
19.8k
                siphash24_compress_typesafe(route->tos, state);
93
94
                /* Then, protocol, scope, type, flags, prefsrc, metrics (RTAX_* attributes), and nexthops (gateways)
95
                 * are used to find routes. See fib_find_info() in net/ipv4/fib_semantics.c of the kernel. */
96
19.8k
                siphash24_compress_typesafe(route->protocol, state);
97
19.8k
                siphash24_compress_typesafe(route->scope, state);
98
19.8k
                siphash24_compress_typesafe(route->type, state);
99
19.8k
                unsigned flags = route->flags & ~RTNH_COMPARE_MASK;
100
19.8k
                siphash24_compress_typesafe(flags, state);
101
19.8k
                in_addr_hash_func(&route->prefsrc, route->family, state);
102
103
                /* nexthops (id, number of nexthops, nexthop) */
104
19.8k
                route_nexthops_hash_func(route, state);
105
106
                /* metrics */
107
19.8k
                route_metric_hash_func(&route->metric, state);
108
19.8k
                break;
109
110
12.2k
        case AF_INET6:
111
                /* First, table and destination prefix are used for classifying routes.
112
                 * See fib6_add() and fib6_add_1() in net/ipv6/ip6_fib.c of the kernel. */
113
12.2k
                siphash24_compress_typesafe(route->table, state);
114
12.2k
                in_addr_hash_func(&route->dst, route->family, state);
115
12.2k
                siphash24_compress_typesafe(route->dst_prefixlen, state);
116
117
                /* Then, source prefix is used. See fib6_add(). */
118
12.2k
                in_addr_hash_func(&route->src, route->family, state);
119
12.2k
                siphash24_compress_typesafe(route->src_prefixlen, state);
120
121
                /* See fib6_add_rt2node(). */
122
12.2k
                siphash24_compress_typesafe(route->priority, state);
123
124
                /* See rt6_duplicate_nexthop() in include/net/ip6_route.h of the kernel.
125
                 * Here, we hash nexthop in a similar way as the one for IPv4. */
126
12.2k
                route_nexthops_hash_func(route, state);
127
128
                /* Unlike IPv4 routes, metrics are not taken into account. */
129
12.2k
                break;
130
131
0
        default:
132
0
                assert_not_reached();
133
32.1k
        }
134
32.1k
}
135
136
18.5k
static int route_compare_func(const Route *a, const Route *b) {
137
18.5k
        int r;
138
139
18.5k
        r = CMP(a->family, b->family);
140
18.5k
        if (r != 0)
141
1.27k
                return r;
142
143
17.2k
        switch (a->family) {
144
6.89k
        case AF_INET:
145
6.89k
                r = CMP(a->table, b->table);
146
6.89k
                if (r != 0)
147
2.35k
                        return r;
148
149
4.54k
                r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
150
4.54k
                if (r != 0)
151
1.80k
                        return r;
152
153
2.73k
                r = CMP(a->dst_prefixlen, b->dst_prefixlen);
154
2.73k
                if (r != 0)
155
189
                        return r;
156
157
2.55k
                r = CMP(a->priority, b->priority);
158
2.55k
                if (r != 0)
159
164
                        return r;
160
161
2.38k
                r = CMP(a->tos, b->tos);
162
2.38k
                if (r != 0)
163
0
                        return r;
164
165
2.38k
                r = CMP(a->protocol, b->protocol);
166
2.38k
                if (r != 0)
167
0
                        return r;
168
169
2.38k
                r = CMP(a->scope, b->scope);
170
2.38k
                if (r != 0)
171
0
                        return r;
172
173
2.38k
                r = CMP(a->type, b->type);
174
2.38k
                if (r != 0)
175
0
                        return r;
176
177
2.38k
                r = CMP(a->flags & ~RTNH_COMPARE_MASK, b->flags & ~RTNH_COMPARE_MASK);
178
2.38k
                if (r != 0)
179
0
                        return r;
180
181
2.38k
                r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
182
2.38k
                if (r != 0)
183
0
                        return r;
184
185
2.38k
                r = route_nexthops_compare_func(a, b);
186
2.38k
                if (r != 0)
187
0
                        return r;
188
189
2.38k
                return route_metric_compare_func(&a->metric, &b->metric);
190
191
10.3k
        case AF_INET6:
192
10.3k
                r = CMP(a->table, b->table);
193
10.3k
                if (r != 0)
194
564
                        return r;
195
196
9.78k
                r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
197
9.78k
                if (r != 0)
198
273
                        return r;
199
200
9.51k
                r = CMP(a->dst_prefixlen, b->dst_prefixlen);
201
9.51k
                if (r != 0)
202
248
                        return r;
203
204
9.26k
                r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
205
9.26k
                if (r != 0)
206
0
                        return r;
207
208
9.26k
                r = CMP(a->src_prefixlen, b->src_prefixlen);
209
9.26k
                if (r != 0)
210
0
                        return r;
211
212
9.26k
                r = CMP(a->priority, b->priority);
213
9.26k
                if (r != 0)
214
477
                        return r;
215
216
8.78k
                return route_nexthops_compare_func(a, b);
217
218
0
        default:
219
0
                assert_not_reached();
220
17.2k
        }
221
17.2k
}
222
223
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
224
                route_hash_ops,
225
                Route,
226
                route_hash_func,
227
                route_compare_func,
228
                route_detach);
229
230
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
231
                route_hash_ops_unref,
232
                Route,
233
                route_hash_func,
234
                route_compare_func,
235
                route_unref);
236
237
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
238
                route_section_hash_ops,
239
                ConfigSection,
240
                config_section_hash_func,
241
                config_section_compare_func,
242
                Route,
243
                route_detach);
244
245
53.1k
int route_new(Route **ret) {
246
53.1k
        _cleanup_(route_unrefp) Route *route = NULL;
247
248
53.1k
        assert(ret);
249
250
53.1k
        route = new(Route, 1);
251
53.1k
        if (!route)
252
0
                return -ENOMEM;
253
254
53.1k
        *route = (Route) {
255
53.1k
                .n_ref = 1,
256
53.1k
                .family = AF_UNSPEC,
257
53.1k
                .scope = RT_SCOPE_UNIVERSE,
258
53.1k
                .protocol = RTPROT_UNSPEC,
259
53.1k
                .type = RTN_UNICAST,
260
53.1k
                .table = RT_TABLE_MAIN,
261
53.1k
                .lifetime_usec = USEC_INFINITY,
262
53.1k
                .gateway_onlink = -1,
263
53.1k
        };
264
265
53.1k
        *ret = TAKE_PTR(route);
266
267
53.1k
        return 0;
268
53.1k
}
269
270
59.5k
int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
271
59.5k
        _cleanup_(config_section_freep) ConfigSection *n = NULL;
272
59.5k
        _cleanup_(route_unrefp) Route *route = NULL;
273
59.5k
        int r;
274
275
59.5k
        assert(network);
276
59.5k
        assert(ret);
277
59.5k
        assert(filename);
278
59.5k
        assert(section_line > 0);
279
280
59.5k
        r = config_section_new(filename, section_line, &n);
281
59.5k
        if (r < 0)
282
0
                return r;
283
284
59.5k
        route = hashmap_get(network->routes_by_section, n);
285
59.5k
        if (route) {
286
23.8k
                *ret = TAKE_PTR(route);
287
23.8k
                return 0;
288
23.8k
        }
289
290
35.6k
        if (hashmap_size(network->routes_by_section) >= routes_max())
291
0
                return -E2BIG;
292
293
35.6k
        r = route_new(&route);
294
35.6k
        if (r < 0)
295
0
                return r;
296
297
35.6k
        route->protocol = RTPROT_STATIC;
298
35.6k
        route->network = network;
299
35.6k
        route->section = TAKE_PTR(n);
300
35.6k
        route->source = NETWORK_CONFIG_SOURCE_STATIC;
301
302
35.6k
        r = hashmap_ensure_put(&network->routes_by_section, &route_section_hash_ops, route->section, route);
303
35.6k
        if (r < 0)
304
0
                return r;
305
306
35.6k
        *ret = TAKE_PTR(route);
307
35.6k
        return 0;
308
35.6k
}
309
310
0
static int route_attach(Manager *manager, Route *route) {
311
0
        int r;
312
313
0
        assert(manager);
314
0
        assert(route);
315
0
        assert(!route->network);
316
0
        assert(!route->wireguard);
317
318
0
        r = set_ensure_put(&manager->routes, &route_hash_ops, route);
319
0
        if (r < 0)
320
0
                return r;
321
0
        if (r == 0)
322
0
                return -EEXIST;
323
324
0
        route->manager = manager;
325
0
        return 0;
326
0
}
327
328
0
int route_get(Manager *manager, const Route *route, Route **ret) {
329
0
        Route *existing;
330
331
0
        assert(manager);
332
0
        assert(route);
333
334
0
        existing = set_get(manager->routes, route);
335
0
        if (!existing)
336
0
                return -ENOENT;
337
338
0
        if (ret)
339
0
                *ret = existing;
340
341
0
        return 0;
342
0
}
343
344
0
static int route_get_link(Manager *manager, const Route *route, Link **ret) {
345
0
        int r;
346
347
0
        assert(manager);
348
0
        assert(route);
349
350
0
        if (route->nexthop_id != 0) {
351
0
                NextHop *nh;
352
353
0
                r = nexthop_get_by_id(manager, route->nexthop_id, &nh);
354
0
                if (r < 0)
355
0
                        return r;
356
357
0
                return link_get_by_index(manager, nh->ifindex, ret);
358
0
        }
359
360
0
        return route_nexthop_get_link(manager, &route->nexthop, ret);
361
0
}
362
363
0
bool route_is_bound_to_link(const Route *route, Link *link) {
364
0
        assert(route);
365
0
        assert(link);
366
0
        assert(link->manager);
367
368
0
        Link *route_link;
369
0
        if (route_get_link(link->manager, route, &route_link) < 0)
370
0
                return false;
371
372
0
        return route_link->ifindex == link->ifindex;
373
0
}
374
375
0
int route_get_request(Manager *manager, const Route *route, Request **ret) {
376
0
        Request *req;
377
378
0
        assert(manager);
379
0
        assert(route);
380
381
0
        req = ordered_set_get(manager->request_queue,
382
0
                              &(const Request) {
383
0
                                      .type = REQUEST_TYPE_ROUTE,
384
0
                                      .userdata = (void*) route,
385
0
                                      .hash_func = (hash_func_t) route_hash_func,
386
0
                                      .compare_func = (compare_func_t) route_compare_func,
387
0
                              });
388
0
        if (!req)
389
0
                return -ENOENT;
390
391
0
        if (ret)
392
0
                *ret = req;
393
0
        return 0;
394
0
}
395
396
0
int route_dup(const Route *src, const RouteNextHop *nh, Route **ret) {
397
0
        _cleanup_(route_unrefp) Route *dest = NULL;
398
0
        int r;
399
400
0
        assert(src);
401
0
        assert(ret);
402
403
0
        dest = newdup(Route, src, 1);
404
0
        if (!dest)
405
0
                return -ENOMEM;
406
407
        /* Unset number of reference and all pointers */
408
0
        dest->n_ref = 1;
409
0
        dest->manager = NULL;
410
0
        dest->network = NULL;
411
0
        dest->wireguard = NULL;
412
0
        dest->section = NULL;
413
0
        dest->nexthop = ROUTE_NEXTHOP_NULL;
414
0
        dest->nexthops = NULL;
415
0
        dest->metric = ROUTE_METRIC_NULL;
416
0
        dest->expire = NULL;
417
418
0
        r = route_nexthops_copy(src, nh, dest);
419
0
        if (r < 0)
420
0
                return r;
421
422
0
        r = route_metric_copy(&src->metric, &dest->metric);
423
0
        if (r < 0)
424
0
                return r;
425
426
0
        *ret = TAKE_PTR(dest);
427
0
        return 0;
428
0
}
429
430
0
static int route_to_string(const Route *route, Manager *manager, char **ret) {
431
0
        _cleanup_free_ char *nexthop = NULL, *prefsrc = NULL,
432
0
                *table = NULL, *scope = NULL, *proto = NULL, *flags = NULL;
433
0
        const char *dst, *src;
434
435
0
        assert(route);
436
0
        assert(manager);
437
0
        assert(ret);
438
439
0
        dst = in_addr_is_set(route->family, &route->dst) || route->dst_prefixlen > 0 ?
440
0
                IN_ADDR_PREFIX_TO_STRING(route->family, &route->dst, route->dst_prefixlen) : NULL;
441
0
        src = in_addr_is_set(route->family, &route->src) || route->src_prefixlen > 0 ?
442
0
                IN_ADDR_PREFIX_TO_STRING(route->family, &route->src, route->src_prefixlen) : NULL;
443
444
0
        (void) route_nexthops_to_string(route, &nexthop);
445
446
0
        if (in_addr_is_set(route->family, &route->prefsrc))
447
0
                (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
448
0
        (void) route_scope_to_string_alloc(route->scope, &scope);
449
0
        (void) manager_get_route_table_to_string(manager, route->table, /* append_num= */ true, &table);
450
0
        (void) route_protocol_full_to_string_alloc(route->protocol, &proto);
451
0
        (void) route_flags_to_string_alloc(route->flags, &flags);
452
453
0
        if (asprintf(ret,
454
0
                     "dst: %s, src: %s, %s, prefsrc: %s, "
455
0
                     "table: %s, priority: %"PRIu32", "
456
0
                     "proto: %s, scope: %s, "
457
0
                     "type: %s, flags: %s",
458
0
                     strna(dst), strna(src), strna(nexthop), strna(prefsrc),
459
0
                     strna(table), route->priority,
460
0
                     strna(proto), strna(scope),
461
0
                     strna(route_type_to_string(route->type)), strna(flags)) < 0)
462
0
                return -ENOMEM;
463
464
0
        return 0;
465
0
}
466
467
0
void log_route_debug(const Route *route, const char *str, Manager *manager) {
468
0
        _cleanup_free_ char *state = NULL, *route_str = NULL;
469
0
        Link *link = NULL;
470
471
0
        assert(route);
472
0
        assert(str);
473
0
        assert(manager);
474
475
0
        if (!DEBUG_LOGGING)
476
0
                return;
477
478
0
        (void) route_get_link(manager, route, &link);
479
0
        (void) network_config_state_to_string_alloc(route->state, &state);
480
0
        (void) route_to_string(route, manager, &route_str);
481
482
0
        log_link_debug(link, "%s %s route (%s): %s",
483
0
                       str, strna(network_config_source_to_string(route->source)), strna(state), strna(route_str));
484
0
}
485
486
0
static void route_forget(Manager *manager, Route *route, const char *msg) {
487
0
        assert(manager);
488
0
        assert(route);
489
0
        assert(msg);
490
491
0
        Request *req;
492
0
        if (route_get_request(manager, route, &req) >= 0)
493
0
                route_enter_removed(req->userdata);
494
495
0
        if (!route->manager && route_get(manager, route, &route) < 0)
496
0
                return;
497
498
0
        route_enter_removed(route);
499
0
        log_route_debug(route, msg, manager);
500
0
        route_detach(route);
501
0
}
502
503
0
static int route_set_netlink_message(const Route *route, sd_netlink_message *m) {
504
0
        int r;
505
506
0
        assert(route);
507
0
        assert(m);
508
509
        /* rtmsg header (and relevant attributes) */
510
0
        if (route->dst_prefixlen > 0) {
511
0
                r = netlink_message_append_in_addr_union(m, RTA_DST, route->family, &route->dst);
512
0
                if (r < 0)
513
0
                        return r;
514
515
0
                r = sd_rtnl_message_route_set_dst_prefixlen(m, route->dst_prefixlen);
516
0
                if (r < 0)
517
0
                        return r;
518
0
        }
519
520
0
        if (route->src_prefixlen > 0) {
521
0
                r = netlink_message_append_in_addr_union(m, RTA_SRC, route->family, &route->src);
522
0
                if (r < 0)
523
0
                        return r;
524
525
0
                r = sd_rtnl_message_route_set_src_prefixlen(m, route->src_prefixlen);
526
0
                if (r < 0)
527
0
                        return r;
528
0
        }
529
530
0
        r = sd_rtnl_message_route_set_tos(m, route->tos);
531
0
        if (r < 0)
532
0
                return r;
533
534
0
        r = sd_rtnl_message_route_set_scope(m, route->scope);
535
0
        if (r < 0)
536
0
                return r;
537
538
0
        r = sd_rtnl_message_route_set_type(m, route->type);
539
0
        if (r < 0)
540
0
                return r;
541
542
0
        r = sd_rtnl_message_route_set_flags(m, route->flags & ~RTNH_COMPARE_MASK);
543
0
        if (r < 0)
544
0
                return r;
545
546
        /* attributes */
547
0
        r = sd_netlink_message_append_u32(m, RTA_PRIORITY, route->priority);
548
0
        if (r < 0)
549
0
                return r;
550
551
0
        if (in_addr_is_set(route->family, &route->prefsrc)) {
552
0
                r = netlink_message_append_in_addr_union(m, RTA_PREFSRC, route->family, &route->prefsrc);
553
0
                if (r < 0)
554
0
                        return r;
555
0
        }
556
557
0
        if (route->table < 256) {
558
0
                r = sd_rtnl_message_route_set_table(m, route->table);
559
0
                if (r < 0)
560
0
                        return r;
561
0
        } else {
562
0
                r = sd_rtnl_message_route_set_table(m, RT_TABLE_UNSPEC);
563
0
                if (r < 0)
564
0
                        return r;
565
566
                /* Table attribute to allow more than 256. */
567
0
                r = sd_netlink_message_append_u32(m, RTA_TABLE, route->table);
568
0
                if (r < 0)
569
0
                        return r;
570
0
        }
571
572
0
        r = sd_netlink_message_append_u8(m, RTA_PREF, route->pref);
573
0
        if (r < 0)
574
0
                return r;
575
576
        /* nexthops */
577
0
        r = route_nexthops_set_netlink_message(route, m);
578
0
        if (r < 0)
579
0
                return r;
580
581
        /* metrics */
582
0
        r = route_metric_set_netlink_message(&route->metric, m);
583
0
        if (r < 0)
584
0
                return r;
585
586
0
        return 0;
587
0
}
588
589
0
static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, RemoveRequest *rreq) {
590
0
        int r;
591
592
0
        assert(m);
593
0
        assert(rreq);
594
595
0
        Manager *manager = ASSERT_PTR(rreq->manager);
596
0
        Route *route = ASSERT_PTR(rreq->userdata);
597
598
0
        r = sd_netlink_message_get_errno(m);
599
0
        if (r < 0) {
600
0
                log_message_full_errno(m,
601
0
                                       (r == -ESRCH || /* the route is already removed? */
602
0
                                        (r == -EINVAL && route->nexthop_id != 0) || /* The nexthop is already removed? */
603
0
                                        !route->manager) ? /* already detached? */
604
0
                                       LOG_DEBUG : LOG_WARNING,
605
0
                                       r, "Could not drop route, ignoring");
606
607
                /* If the route cannot be removed, then assume the route is already removed. */
608
0
                route_forget(manager, route, "Forgetting");
609
0
        }
610
611
0
        return 1;
612
0
}
613
614
0
int route_remove(Route *route, Manager *manager) {
615
0
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
616
0
        Link *link = NULL;
617
0
        int r;
618
619
0
        assert(route);
620
0
        assert(manager);
621
622
0
        if (manager->state == MANAGER_STOPPED)
623
0
                return 0; /* The remove request will not be queued anyway. Suppress logging below. */
624
625
        /* If the route is remembered, then use the remembered object. */
626
0
        (void) route_get(manager, route, &route);
627
628
0
        log_route_debug(route, "Removing", manager);
629
630
        /* For logging. */
631
0
        (void) route_get_link(manager, route, &link);
632
633
0
        r = sd_rtnl_message_new_route(manager->rtnl, &m, RTM_DELROUTE, route->family, route->protocol);
634
0
        if (r < 0)
635
0
                return log_link_warning_errno(link, r, "Could not create netlink message: %m");
636
637
0
        r = route_set_netlink_message(route, m);
638
0
        if (r < 0)
639
0
                return log_link_warning_errno(link, r, "Could not fill netlink message: %m");
640
641
0
        r = manager_remove_request_add(manager, route, route, manager->rtnl, m, route_remove_handler);
642
0
        if (r < 0)
643
0
                return log_link_warning_errno(link, r, "Could not queue rtnetlink message: %m");
644
645
0
        route_enter_removing(route);
646
0
        return 0;
647
0
}
648
649
0
int route_remove_and_cancel(Route *route, Manager *manager) {
650
0
        _cleanup_(request_unrefp) Request *req = NULL;
651
0
        bool waiting = false;
652
653
0
        assert(route);
654
0
        assert(manager);
655
656
        /* If the route is remembered by the manager, then use the remembered object. */
657
0
        (void) route_get(manager, route, &route);
658
659
        /* Cancel the request for the route. If the request is already called but we have not received the
660
         * notification about the request, then explicitly remove the route. */
661
0
        if (route_get_request(manager, route, &req) >= 0) {
662
0
                request_ref(req); /* avoid the request freed by request_detach() */
663
0
                waiting = req->waiting_reply;
664
0
                request_detach(req);
665
0
                route_cancel_requesting(route);
666
0
        }
667
668
        /* If we know that the route will come or already exists, remove it. */
669
0
        if (waiting || (route->manager && route_exists(route)))
670
0
                return route_remove(route, manager);
671
672
0
        return 0;
673
0
}
674
675
0
static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
676
0
        Route *route = ASSERT_PTR(userdata);
677
0
        int r;
678
679
0
        if (!route->manager)
680
0
                return 0; /* already detached. */
681
682
0
        r = route_remove(route, route->manager);
683
0
        if (r < 0) {
684
0
                Link *link = NULL;
685
0
                (void) route_get_link(route->manager, route, &link);
686
0
                log_link_warning_errno(link, r, "Could not remove route: %m");
687
0
                if (link)
688
0
                        link_enter_failed(link);
689
0
        }
690
691
0
        return 1;
692
0
}
693
694
0
static int route_setup_timer(Route *route, const struct rta_cacheinfo *cacheinfo) {
695
0
        int r;
696
697
0
        assert(route);
698
699
0
        if (cacheinfo && cacheinfo->rta_expires != 0)
700
0
                route->expiration_managed_by_kernel = true;
701
702
0
        if (route->lifetime_usec == USEC_INFINITY || /* We do not request expiration for the route. */
703
0
            route->expiration_managed_by_kernel) {   /* We have received nonzero expiration previously. The expiration is managed by the kernel. */
704
0
                route->expire = sd_event_source_disable_unref(route->expire);
705
0
                return 0;
706
0
        }
707
708
0
        Manager *manager = ASSERT_PTR(route->manager);
709
0
        r = event_reset_time(manager->event, &route->expire, CLOCK_BOOTTIME,
710
0
                             route->lifetime_usec, 0, route_expire_handler, route, 0, "route-expiration", true);
711
0
        if (r < 0) {
712
0
                Link *link = NULL;
713
0
                (void) route_get_link(manager, route, &link);
714
0
                return log_link_warning_errno(link, r, "Failed to configure expiration timer for route, ignoring: %m");
715
0
        }
716
717
0
        log_route_debug(route, "Configured expiration timer for", manager);
718
0
        return 1;
719
0
}
720
721
0
static int route_update_by_request(Route *route, Request *req) {
722
0
        assert(route);
723
0
        assert(req);
724
725
0
        Route *rt = ASSERT_PTR(req->userdata);
726
727
0
        route->provider = rt->provider;
728
0
        route->source = rt->source;
729
0
        route->lifetime_usec = rt->lifetime_usec;
730
731
0
        return 0;
732
0
}
733
734
0
static int route_update_on_existing_one(Request *req, Route *requested) {
735
0
        Manager *manager = ASSERT_PTR(ASSERT_PTR(req)->manager);
736
0
        Route *existing;
737
0
        int r;
738
739
0
        assert(requested);
740
741
0
        if (route_get(manager, requested, &existing) < 0)
742
0
                return 0;
743
744
0
        r = route_update_by_request(existing, req);
745
0
        if (r < 0)
746
0
                return r;
747
748
0
        r = route_setup_timer(existing, NULL);
749
0
        if (r < 0)
750
0
                return r;
751
752
        /* This may be a bug in the kernel, but the MTU of an IPv6 route can be updated only when the
753
         * route has an expiration timer managed by the kernel (not by us). See fib6_add_rt2node() in
754
         * net/ipv6/ip6_fib.c of the kernel. */
755
0
        if (existing->family == AF_INET6 &&
756
0
            existing->expiration_managed_by_kernel) {
757
0
                r = route_metric_set(&existing->metric, RTAX_MTU, route_metric_get(&requested->metric, RTAX_MTU));
758
0
                if (r < 0)
759
0
                        return r;
760
0
        }
761
762
0
        route_enter_configured(existing);
763
0
        return 0;
764
0
}
765
766
0
static int route_update_on_existing(Request *req) {
767
0
        Route *rt = ASSERT_PTR(ASSERT_PTR(req)->userdata);
768
0
        int r;
769
770
0
        if (!req->manager)
771
                /* Already detached? At least there are two possibilities then.
772
                 * 1) The interface is removed, and all queued requests for the interface are cancelled.
773
                 * 2) networkd is now stopping, hence all queued requests are cancelled.
774
                 * Anyway, we can ignore the request, and there is nothing we can do. */
775
0
                return 0;
776
777
0
        if (rt->family == AF_INET || ordered_set_isempty(rt->nexthops))
778
0
                return route_update_on_existing_one(req, rt);
779
780
0
        RouteNextHop *nh;
781
0
        ORDERED_SET_FOREACH(nh, rt->nexthops) {
782
0
                _cleanup_(route_unrefp) Route *dup = NULL;
783
784
0
                r = route_dup(rt, nh, &dup);
785
0
                if (r < 0)
786
0
                        return r;
787
788
0
                r = route_update_on_existing_one(req, dup);
789
0
                if (r < 0)
790
0
                        return r;
791
0
        }
792
793
0
        return 0;
794
0
}
795
796
0
int route_configure_handler_internal(sd_netlink_message *m, Request *req, Route *route) {
797
0
        int r;
798
799
0
        assert(m);
800
0
        assert(req);
801
0
        assert(route);
802
803
0
        Link *link = ASSERT_PTR(req->link);
804
805
0
        r = sd_netlink_message_get_errno(m);
806
0
        if (r == -EEXIST) {
807
                /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE notification, so
808
                 * here we need to update the state, provider, source, timer, and so on. */
809
0
                r = route_update_on_existing(req);
810
0
                if (r < 0) {
811
0
                        log_link_warning_errno(link, r, "Failed to update existing route: %m");
812
0
                        link_enter_failed(link);
813
0
                        return 0;
814
0
                }
815
816
0
                return 1;
817
0
        }
818
0
        if (r < 0) {
819
0
                _cleanup_free_ char *str = NULL;
820
0
                (void) route_to_string(route, link->manager, &str);
821
0
                log_link_message_warning_errno(link, m, r, "Failed to configure %s route (%s)",
822
0
                                               network_config_source_to_string(route->source), strna(str));
823
0
                link_enter_failed(link);
824
0
                return 0;
825
0
        }
826
827
0
        return 1;
828
0
}
829
830
0
static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link, Request *req) {
831
0
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
832
0
        int r;
833
834
0
        assert(route);
835
0
        assert(link);
836
0
        assert(link->manager);
837
0
        assert(req);
838
839
0
        log_route_debug(route, "Configuring", link->manager);
840
841
0
        r = sd_rtnl_message_new_route(link->manager->rtnl, &m, RTM_NEWROUTE, route->family, route->protocol);
842
0
        if (r < 0)
843
0
                return r;
844
845
0
        r = route_set_netlink_message(route, m);
846
0
        if (r < 0)
847
0
                return r;
848
849
0
        if (lifetime_sec != UINT32_MAX) {
850
0
                r = sd_netlink_message_append_u32(m, RTA_EXPIRES, lifetime_sec);
851
0
                if (r < 0)
852
0
                        return r;
853
0
        }
854
855
0
        return request_call_netlink_async(link->manager->rtnl, m, req);
856
0
}
857
858
0
static int route_requeue_request(Request *req, Link *link, const Route *route) {
859
0
        _unused_ _cleanup_(request_unrefp) Request *req_unref = NULL;
860
0
        _cleanup_(route_unrefp) Route *tmp = NULL;
861
0
        int r;
862
863
0
        assert(req);
864
0
        assert(link);
865
0
        assert(link->manager);
866
0
        assert(route);
867
868
        /* It is not possible to adjust the Route object owned by Request, as it is used as a key to manage
869
         * Request objects in the queue. Hence, we need to re-request with the updated Route object. */
870
871
0
        if (!route_nexthops_needs_adjust(route))
872
0
                return 0; /* The Route object does not need the adjustment. Continue with it. */
873
874
0
        r = route_dup(route, NULL, &tmp);
875
0
        if (r < 0)
876
0
                return r;
877
878
0
        r = route_adjust_nexthops(tmp, link);
879
0
        if (r <= 0)
880
0
                return r;
881
882
0
        if (route_compare_func(route, tmp) == 0 && route->type == tmp->type)
883
0
                return 0; /* No effective change?? That's OK. */
884
885
        /* Avoid the request to be freed by request_detach(). */
886
0
        req_unref = request_ref(req);
887
888
        /* Detach the request from the queue, to make not the new request is deduped.
889
         * Why this is necessary? IPv6 routes with different type may be handled as the same,
890
         * As commented in route_adjust_nexthops(), we need to configure the adjusted type,
891
         * otherwise we cannot remove the route on reconfigure or so. If we request the new Route object
892
         * without detaching the current request, the new request is deduped, and the route is configured
893
         * with unmodified type. */
894
0
        request_detach(req);
895
896
        /* Request the route with the adjusted Route object combined with the same other parameters. */
897
0
        r = link_requeue_request(link, req, tmp, NULL);
898
0
        if (r < 0)
899
0
                return r;
900
0
        if (r == 0)
901
0
                return 1; /* Already queued?? That's OK. Maybe, [Route] section is effectively duplicated. */
902
903
0
        TAKE_PTR(tmp);
904
0
        return 1; /* New request is queued. Finish to process this request. */
905
0
}
906
907
0
static int route_is_ready_to_configure(const Route *route, Link *link) {
908
0
        assert(route);
909
0
        assert(link);
910
911
0
        if (!link_is_ready_to_configure(link, /* allow_unmanaged= */ false))
912
0
                return false;
913
914
0
        if (in_addr_is_set(route->family, &route->prefsrc) > 0) {
915
0
                Address *a;
916
917
0
                if (manager_get_address(link->manager, route->family, &route->prefsrc, &a) < 0)
918
0
                        return false;
919
920
0
                if (!address_is_ready(a))
921
0
                        return false;
922
0
        }
923
924
0
        return route_nexthops_is_ready_to_configure(route, link->manager);
925
0
}
926
927
0
static int route_process_request(Request *req, Link *link, Route *route) {
928
0
        Route *existing;
929
0
        int r;
930
931
0
        assert(req);
932
0
        assert(link);
933
0
        assert(link->manager);
934
0
        assert(route);
935
936
0
        r = route_is_ready_to_configure(route, link);
937
0
        if (r < 0)
938
0
                return log_link_warning_errno(link, r, "Failed to check if route is ready to configure: %m");
939
0
        if (r == 0)
940
0
                return 0;
941
942
0
        usec_t now_usec;
943
0
        assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
944
0
        uint32_t sec = usec_to_sec(route->lifetime_usec, now_usec);
945
0
        if (sec == 0) {
946
0
                log_link_debug(link, "Refuse to configure %s route with zero lifetime.",
947
0
                               network_config_source_to_string(route->source));
948
949
0
                route_cancel_requesting(route);
950
0
                if (route_get(link->manager, route, &existing) >= 0)
951
0
                        route_cancel_requesting(existing);
952
0
                return 1;
953
0
        }
954
955
0
        r = route_requeue_request(req, link, route);
956
0
        if (r != 0)
957
0
                return r;
958
959
0
        r = route_configure(route, sec, link, req);
960
0
        if (r < 0)
961
0
                return log_link_warning_errno(link, r, "Failed to configure route: %m");
962
963
0
        route_enter_configuring(route);
964
0
        if (route_get(link->manager, route, &existing) >= 0)
965
0
                route_enter_configuring(existing);
966
0
        return 1;
967
0
}
968
969
static int link_request_route_one(
970
                Link *link,
971
                const Route *route,
972
                const RouteNextHop *nh,
973
                unsigned *message_counter,
974
0
                route_netlink_handler_t netlink_handler) {
975
976
0
        _cleanup_(route_unrefp) Route *tmp = NULL;
977
0
        Route *existing = NULL;
978
0
        int r;
979
980
0
        assert(link);
981
0
        assert(link->manager);
982
0
        assert(route);
983
984
0
        r = route_dup(route, nh, &tmp);
985
0
        if (r < 0)
986
0
                return r;
987
988
0
        r = route_adjust_nexthops(tmp, link);
989
0
        if (r < 0)
990
0
                return r;
991
992
0
        if (route_get(link->manager, tmp, &existing) >= 0)
993
                /* Copy state for logging below. */
994
0
                tmp->state = existing->state;
995
996
0
        log_route_debug(tmp, "Requesting", link->manager);
997
0
        r = link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
998
0
                                    tmp,
999
0
                                    route_unref,
1000
0
                                    route_hash_func,
1001
0
                                    route_compare_func,
1002
0
                                    route_process_request,
1003
0
                                    message_counter,
1004
0
                                    netlink_handler,
1005
0
                                    NULL);
1006
0
        if (r <= 0)
1007
0
                return r;
1008
1009
0
        route_enter_requesting(tmp);
1010
0
        if (existing)
1011
0
                route_enter_requesting(existing);
1012
1013
0
        TAKE_PTR(tmp);
1014
0
        return 1;
1015
0
}
1016
1017
int link_request_route(
1018
                Link *link,
1019
                const Route *route,
1020
                unsigned *message_counter,
1021
0
                route_netlink_handler_t netlink_handler) {
1022
1023
0
        int r;
1024
1025
0
        assert(link);
1026
0
        assert(link->manager);
1027
0
        assert(route);
1028
0
        assert(route->source != NETWORK_CONFIG_SOURCE_FOREIGN);
1029
1030
0
        if (route->family == AF_INET || route_is_reject(route) || ordered_set_isempty(route->nexthops))
1031
0
                return link_request_route_one(link, route, NULL, message_counter, netlink_handler);
1032
1033
0
        RouteNextHop *nh;
1034
0
        ORDERED_SET_FOREACH(nh, route->nexthops) {
1035
0
                r = link_request_route_one(link, route, nh, message_counter, netlink_handler);
1036
0
                if (r < 0)
1037
0
                        return r;
1038
0
        }
1039
1040
0
        return 0;
1041
0
}
1042
1043
0
static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
1044
0
        int r;
1045
1046
0
        assert(req);
1047
0
        assert(link);
1048
0
        assert(route);
1049
1050
0
        r = route_configure_handler_internal(m, req, route);
1051
0
        if (r <= 0)
1052
0
                return r;
1053
1054
0
        if (link->static_route_messages == 0) {
1055
0
                log_link_debug(link, "Routes set");
1056
0
                link->static_routes_configured = true;
1057
0
                link_check_ready(link);
1058
0
        }
1059
1060
0
        return 1;
1061
0
}
1062
1063
0
static int link_request_wireguard_routes(Link *link, bool only_ipv4) {
1064
0
        Route *route;
1065
0
        int r;
1066
1067
0
        assert(link);
1068
1069
0
        if (!link->netdev || link->netdev->kind != NETDEV_KIND_WIREGUARD)
1070
0
                return 0;
1071
1072
0
        Wireguard *w = WIREGUARD(link->netdev);
1073
1074
0
        SET_FOREACH(route, w->routes) {
1075
0
                if (only_ipv4 && route->family != AF_INET)
1076
0
                        continue;
1077
1078
0
                r = link_request_route(link, route, &link->static_route_messages, static_route_handler);
1079
0
                if (r < 0)
1080
0
                        return r;
1081
0
        }
1082
1083
0
        return 0;
1084
0
}
1085
1086
0
int link_request_static_routes(Link *link, bool only_ipv4) {
1087
0
        Route *route;
1088
0
        int r;
1089
1090
0
        assert(link);
1091
0
        assert(link->network);
1092
1093
0
        link->static_routes_configured = false;
1094
1095
0
        HASHMAP_FOREACH(route, link->network->routes_by_section) {
1096
0
                if (route->source != NETWORK_CONFIG_SOURCE_STATIC)
1097
0
                        continue;
1098
1099
0
                if (only_ipv4 && route->family != AF_INET)
1100
0
                        continue;
1101
1102
0
                r = link_request_route(link, route, &link->static_route_messages, static_route_handler);
1103
0
                if (r < 0)
1104
0
                        return r;
1105
0
        }
1106
1107
0
        r = link_request_wireguard_routes(link, only_ipv4);
1108
0
        if (r < 0)
1109
0
                return r;
1110
1111
0
        if (link->static_route_messages == 0) {
1112
0
                link->static_routes_configured = true;
1113
0
                link_check_ready(link);
1114
0
        } else {
1115
0
                log_link_debug(link, "Requesting routes");
1116
0
                link_set_state(link, LINK_STATE_CONFIGURING);
1117
0
        }
1118
1119
0
        return 0;
1120
0
}
1121
1122
static int process_route_one(
1123
                Manager *manager,
1124
                uint16_t type,
1125
                Route *tmp,
1126
0
                const struct rta_cacheinfo *cacheinfo) {
1127
1128
0
        Route *route = NULL;
1129
0
        Link *link = NULL;
1130
0
        bool is_new = false, update_dhcp4;
1131
0
        int r;
1132
1133
0
        assert(manager);
1134
0
        assert(tmp);
1135
0
        assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE));
1136
1137
0
        (void) route_get(manager, tmp, &route);
1138
0
        (void) route_get_link(manager, tmp, &link);
1139
1140
0
        update_dhcp4 = link && tmp->family == AF_INET6 && tmp->dst_prefixlen == 0;
1141
1142
0
        switch (type) {
1143
0
        case RTM_NEWROUTE: {
1144
0
                Request *req = NULL;
1145
0
                (void) route_get_request(manager, tmp, &req);
1146
1147
0
                if (!route) {
1148
0
                        if (!manager->manage_foreign_routes && !(req && req->waiting_reply)) {
1149
0
                                route_enter_configured(tmp);
1150
0
                                log_route_debug(tmp, "Ignoring received", manager);
1151
0
                                return 0;
1152
0
                        }
1153
1154
                        /* If we do not know the route, then save it. */
1155
0
                        r = route_attach(manager, tmp);
1156
0
                        if (r < 0) {
1157
0
                                log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
1158
0
                                return 0;
1159
0
                        }
1160
1161
0
                        route = route_ref(tmp);
1162
0
                        is_new = true;
1163
1164
0
                } else {
1165
                        /* Update remembered route with the received notification. */
1166
1167
                        /* Here, update weight only when a non-zero weight is received. As the kernel does
1168
                         * not provide the weight of a single-path route. In such case, tmp->nexthop.weight
1169
                         * is zero, hence we should not overwrite the known weight of the route. */
1170
0
                        if (tmp->nexthop.weight != 0)
1171
0
                                route->nexthop.weight = tmp->nexthop.weight;
1172
0
                }
1173
1174
                /* Also update information that cannot be obtained through netlink notification. */
1175
0
                if (req && req->waiting_reply) {
1176
0
                        r = route_update_by_request(route, req);
1177
0
                        if (r < 0) {
1178
0
                                log_link_warning_errno(link, r, "Failed to update route by request: %m");
1179
0
                                link_enter_failed(link);
1180
0
                                return 0;
1181
0
                        }
1182
1183
                        /* We configure IPv6 multipath route separately. When the first path is configured,
1184
                         * the kernel does not provide the weight of the path. So, we need to adjust it here.
1185
                         * Hopefully, the weight is assigned correctly. */
1186
0
                        if (route->nexthop.weight == 0) {
1187
0
                                Route *rt = ASSERT_PTR(req->userdata);
1188
0
                                route->nexthop.weight = rt->nexthop.weight;
1189
0
                        }
1190
0
                }
1191
1192
0
                route_attach_to_nexthop(route);
1193
1194
0
                route_enter_configured(route);
1195
0
                log_route_debug(route, is_new ? "Received new" : "Received remembered", manager);
1196
1197
0
                (void) route_setup_timer(route, cacheinfo);
1198
1199
0
                break;
1200
0
        }
1201
0
        case RTM_DELROUTE:
1202
0
                if (route)
1203
0
                        route_forget(manager, route, "Forgetting removed");
1204
0
                else
1205
0
                        log_route_debug(tmp,
1206
0
                                        manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring removed",
1207
0
                                        manager);
1208
0
                break;
1209
1210
0
        default:
1211
0
                assert_not_reached();
1212
0
        }
1213
1214
0
        if (update_dhcp4) {
1215
0
                r = dhcp4_update_ipv6_connectivity(link);
1216
0
                if (r < 0) {
1217
0
                        log_link_warning_errno(link, r, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");
1218
0
                        link_enter_failed(link);
1219
0
                }
1220
0
        }
1221
1222
0
        return 1;
1223
0
}
1224
1225
0
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
1226
0
        _cleanup_(route_unrefp) Route *tmp = NULL;
1227
0
        int r;
1228
1229
0
        assert(rtnl);
1230
0
        assert(message);
1231
0
        assert(m);
1232
1233
0
        if (sd_netlink_message_is_error(message)) {
1234
0
                r = sd_netlink_message_get_errno(message);
1235
0
                if (r < 0)
1236
0
                        log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
1237
1238
0
                return 0;
1239
0
        }
1240
1241
0
        uint16_t type;
1242
0
        r = sd_netlink_message_get_type(message, &type);
1243
0
        if (r < 0) {
1244
0
                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
1245
0
                return 0;
1246
0
        } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
1247
0
                log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
1248
0
                return 0;
1249
0
        }
1250
1251
0
        r = route_new(&tmp);
1252
0
        if (r < 0)
1253
0
                return log_oom();
1254
1255
        /* rtmsg header */
1256
0
        r = sd_rtnl_message_route_get_family(message, &tmp->family);
1257
0
        if (r < 0) {
1258
0
                log_warning_errno(r, "rtnl: received route message without family, ignoring: %m");
1259
0
                return 0;
1260
0
        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
1261
0
                log_debug("rtnl: received route message with invalid family '%i', ignoring.", tmp->family);
1262
0
                return 0;
1263
0
        }
1264
1265
0
        r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
1266
0
        if (r < 0) {
1267
0
                log_warning_errno(r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
1268
0
                return 0;
1269
0
        }
1270
1271
0
        r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
1272
0
        if (r < 0) {
1273
0
                log_warning_errno(r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
1274
0
                return 0;
1275
0
        }
1276
1277
0
        r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
1278
0
        if (r < 0) {
1279
0
                log_warning_errno(r, "rtnl: received route message with invalid tos, ignoring: %m");
1280
0
                return 0;
1281
0
        }
1282
1283
0
        r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
1284
0
        if (r < 0) {
1285
0
                log_warning_errno(r, "rtnl: received route message without route protocol, ignoring: %m");
1286
0
                return 0;
1287
0
        }
1288
1289
0
        r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
1290
0
        if (r < 0) {
1291
0
                log_warning_errno(r, "rtnl: received route message with invalid scope, ignoring: %m");
1292
0
                return 0;
1293
0
        }
1294
1295
0
        r = sd_rtnl_message_route_get_type(message, &tmp->type);
1296
0
        if (r < 0) {
1297
0
                log_warning_errno(r, "rtnl: received route message with invalid type, ignoring: %m");
1298
0
                return 0;
1299
0
        }
1300
1301
0
        r = sd_rtnl_message_route_get_flags(message, &tmp->flags);
1302
0
        if (r < 0) {
1303
0
                log_warning_errno(r, "rtnl: received route message without route flags, ignoring: %m");
1304
0
                return 0;
1305
0
        }
1306
1307
        /* attributes */
1308
0
        r = netlink_message_read_in_addr_union(message, RTA_DST, tmp->family, &tmp->dst);
1309
0
        if (r < 0 && r != -ENODATA) {
1310
0
                log_warning_errno(r, "rtnl: received route message without valid destination, ignoring: %m");
1311
0
                return 0;
1312
0
        }
1313
1314
0
        r = netlink_message_read_in_addr_union(message, RTA_SRC, tmp->family, &tmp->src);
1315
0
        if (r < 0 && r != -ENODATA) {
1316
0
                log_warning_errno(r, "rtnl: received route message without valid source, ignoring: %m");
1317
0
                return 0;
1318
0
        }
1319
1320
0
        r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
1321
0
        if (r < 0 && r != -ENODATA) {
1322
0
                log_warning_errno(r, "rtnl: received route message with invalid priority, ignoring: %m");
1323
0
                return 0;
1324
0
        }
1325
1326
0
        r = netlink_message_read_in_addr_union(message, RTA_PREFSRC, tmp->family, &tmp->prefsrc);
1327
0
        if (r < 0 && r != -ENODATA) {
1328
0
                log_warning_errno(r, "rtnl: received route message without valid preferred source, ignoring: %m");
1329
0
                return 0;
1330
0
        }
1331
1332
0
        r = sd_netlink_message_read_u32(message, RTA_TABLE, &tmp->table);
1333
0
        if (r == -ENODATA) {
1334
0
                unsigned char table;
1335
1336
0
                r = sd_rtnl_message_route_get_table(message, &table);
1337
0
                if (r >= 0)
1338
0
                        tmp->table = table;
1339
0
        }
1340
0
        if (r < 0) {
1341
0
                log_warning_errno(r, "rtnl: received route message with invalid table, ignoring: %m");
1342
0
                return 0;
1343
0
        }
1344
1345
0
        r = sd_netlink_message_read_u8(message, RTA_PREF, &tmp->pref);
1346
0
        if (r < 0 && r != -ENODATA) {
1347
0
                log_warning_errno(r, "rtnl: received route message with invalid preference, ignoring: %m");
1348
0
                return 0;
1349
0
        }
1350
1351
        /* nexthops */
1352
0
        if (route_nexthops_read_netlink_message(tmp, message) < 0)
1353
0
                return 0;
1354
1355
        /* metrics */
1356
0
        if (route_metric_read_netlink_message(&tmp->metric, message) < 0)
1357
0
                return 0;
1358
1359
0
        bool has_cacheinfo;
1360
0
        struct rta_cacheinfo cacheinfo;
1361
0
        r = sd_netlink_message_read(message, RTA_CACHEINFO, sizeof(cacheinfo), &cacheinfo);
1362
0
        if (r < 0 && r != -ENODATA) {
1363
0
                log_warning_errno(r, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
1364
0
                return 0;
1365
0
        }
1366
0
        has_cacheinfo = r >= 0;
1367
1368
0
        if (tmp->family == AF_INET || ordered_set_isempty(tmp->nexthops))
1369
0
                return process_route_one(m, type, tmp, has_cacheinfo ? &cacheinfo : NULL);
1370
1371
0
        RouteNextHop *nh;
1372
0
        ORDERED_SET_FOREACH(nh, tmp->nexthops) {
1373
0
                _cleanup_(route_unrefp) Route *dup = NULL;
1374
1375
0
                r = route_dup(tmp, nh, &dup);
1376
0
                if (r < 0)
1377
0
                        return log_oom();
1378
1379
0
                r = process_route_one(m, type, dup, has_cacheinfo ? &cacheinfo : NULL);
1380
0
                if (r < 0)
1381
0
                        return r;
1382
0
        }
1383
1384
0
        return 1;
1385
0
}
1386
1387
0
void manager_mark_routes(Manager *manager, Link *link, NetworkConfigSource source) {
1388
0
        Route *route;
1389
1390
0
        assert(manager);
1391
1392
0
        SET_FOREACH(route, manager->routes) {
1393
0
                if (route->source != source)
1394
0
                        continue;
1395
1396
0
                if (link) {
1397
0
                        Link *route_link;
1398
1399
0
                        if (route_get_link(manager, route, &route_link) < 0)
1400
0
                                continue;
1401
0
                        if (route_link != link)
1402
0
                                continue;
1403
0
                }
1404
1405
0
                route_mark(route);
1406
0
        }
1407
0
}
1408
1409
0
static bool route_by_kernel(const Route *route) {
1410
0
        assert(route);
1411
1412
0
        if (route->protocol == RTPROT_KERNEL)
1413
0
                return true;
1414
1415
        /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
1416
         * multicast with RTPROT_BOOT. Do not touch it. */
1417
0
        if (route->protocol == RTPROT_BOOT &&
1418
0
            route->family == AF_INET6 &&
1419
0
            route->dst_prefixlen == 8 &&
1420
0
            in6_addr_equal(&route->dst.in6, & (struct in6_addr) {{{ 0xff,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }}}))
1421
0
                return true;
1422
1423
0
        return false;
1424
0
}
1425
1426
0
bool route_can_update(Manager *manager, const Route *existing, const Route *requesting) {
1427
0
        int r;
1428
1429
0
        assert(manager);
1430
0
        assert(existing);
1431
0
        assert(requesting);
1432
1433
0
        if (route_compare_func(existing, requesting) != 0) {
1434
0
                log_route_debug(existing, "Cannot update route, as the existing route is different", manager);
1435
0
                return false;
1436
0
        }
1437
1438
0
        switch (existing->family) {
1439
0
        case AF_INET:
1440
0
                if (existing->nexthop.weight != requesting->nexthop.weight) {
1441
0
                        log_debug("Cannot update route: existing weight: %u, requesting weight: %u",
1442
0
                                  existing->nexthop.weight, requesting->nexthop.weight);
1443
0
                        return false;
1444
0
                }
1445
0
                return true;
1446
1447
0
        case AF_INET6:
1448
0
                if (existing->protocol != requesting->protocol) {
1449
0
                        if (DEBUG_LOGGING) {
1450
0
                                _cleanup_free_ char *ex = NULL, *req = NULL;
1451
1452
0
                                r = route_protocol_to_string_alloc(existing->protocol, &ex);
1453
0
                                if (r < 0)
1454
0
                                        return false;
1455
1456
0
                                r = route_protocol_to_string_alloc(requesting->protocol, &req);
1457
0
                                if (r < 0)
1458
0
                                        return false;
1459
1460
0
                                log_debug("Cannot update route: existing protocol: %s, requesting protocol: %s", ex, req);
1461
0
                        }
1462
1463
0
                        return false;
1464
0
                }
1465
0
                if (existing->type != requesting->type) {
1466
0
                        log_debug("Cannot update route: existing type: %s, requesting type: %s",
1467
0
                                  route_type_to_string(existing->type),
1468
0
                                  route_type_to_string(requesting->type));
1469
1470
0
                        return false;
1471
0
                }
1472
0
                if ((existing->flags & ~RTNH_COMPARE_MASK) != (requesting->flags & ~RTNH_COMPARE_MASK)) {
1473
0
                        if (DEBUG_LOGGING) {
1474
0
                                _cleanup_free_ char *ex = NULL, *req = NULL;
1475
1476
0
                                r = route_flags_to_string_alloc(existing->flags, &ex);
1477
0
                                if (r < 0)
1478
0
                                        return false;
1479
1480
0
                                r = route_flags_to_string_alloc(requesting->flags, &req);
1481
0
                                if (r < 0)
1482
0
                                        return false;
1483
1484
0
                                log_debug("Cannot update route: existing flags: %s, requesting flags: %s", ex, req);
1485
0
                        }
1486
1487
0
                        return false;
1488
0
                }
1489
0
                if (!in6_addr_equal(&existing->prefsrc.in6, &requesting->prefsrc.in6)) {
1490
0
                        log_debug("Cannot update route: existing preferred source: %s, requesting preferred source: %s",
1491
0
                                  IN6_ADDR_TO_STRING(&existing->prefsrc.in6),
1492
0
                                  IN6_ADDR_TO_STRING(&requesting->prefsrc.in6));
1493
0
                        return false;
1494
0
                }
1495
0
                if (existing->pref != requesting->pref) {
1496
0
                        log_debug("Cannot update route: existing preference: %u, requesting preference: %u",
1497
0
                                  existing->pref, requesting->pref);
1498
0
                        return false;
1499
0
                }
1500
0
                if (existing->expiration_managed_by_kernel && requesting->lifetime_usec == USEC_INFINITY) {
1501
0
                        log_route_debug(existing,
1502
0
                                        "Cannot update route: the expiration is managed by the kernel and requested lifetime is infinite",
1503
0
                                        manager);
1504
0
                        return false; /* We cannot disable expiration timer in the kernel. */
1505
0
                }
1506
0
                if (!route_metric_can_update(&existing->metric, &requesting->metric, existing->expiration_managed_by_kernel)) {
1507
0
                        log_route_debug(existing,
1508
0
                                        "Cannot update route: expiration is managed by the kernel or metrics differ",
1509
0
                                        manager);
1510
0
                        return false;
1511
0
                }
1512
0
                if (existing->nexthop.weight != requesting->nexthop.weight) {
1513
0
                        log_debug("Cannot update route: existing weight: %u, requesting weight: %u",
1514
0
                                  existing->nexthop.weight, requesting->nexthop.weight);
1515
0
                        return false;
1516
0
                }
1517
0
                return true;
1518
1519
0
        default:
1520
0
                assert_not_reached();
1521
0
        }
1522
0
}
1523
1524
0
static int link_unmark_route(Link *link, const Route *route, const RouteNextHop *nh) {
1525
0
        _cleanup_(route_unrefp) Route *tmp = NULL;
1526
0
        Route *existing;
1527
0
        int r;
1528
1529
0
        assert(link);
1530
0
        assert(route);
1531
1532
0
        r = route_dup(route, nh, &tmp);
1533
0
        if (r < 0)
1534
0
                return r;
1535
1536
0
        r = route_adjust_nexthops(tmp, link);
1537
0
        if (r < 0)
1538
0
                return r;
1539
1540
0
        if (route_get(link->manager, tmp, &existing) < 0)
1541
0
                return 0;
1542
1543
0
        if (!route_can_update(link->manager, existing, tmp))
1544
0
                return 0;
1545
1546
0
        route_unmark(existing);
1547
0
        return 1;
1548
0
}
1549
1550
0
int link_drop_routes(Link *link, bool only_static) {
1551
0
        Route *route;
1552
0
        Link *other;
1553
0
        int r = 0;
1554
1555
0
        assert(link);
1556
0
        assert(link->manager);
1557
1558
        /* First, mark all routes. */
1559
0
        SET_FOREACH(route, link->manager->routes) {
1560
                /* Do not touch routes managed by the kernel. */
1561
0
                if (route_by_kernel(route))
1562
0
                        continue;
1563
1564
                /* Ignore routes not assigned yet or already removed. */
1565
0
                if (!route_exists(route))
1566
0
                        continue;
1567
1568
0
                if (!link_should_mark_config(link, only_static, route->source, route->protocol))
1569
0
                        continue;
1570
1571
0
                Link *route_link = NULL;
1572
0
                if (route_get_link(link->manager, route, &route_link) >= 0 && route_link != link) {
1573
                        /* When we also mark foreign routes, do not mark routes assigned to other interfaces.
1574
                         * Otherwise, routes assigned to unmanaged interfaces will be dropped.
1575
                         * Note, route_get_link() does not provide assigned link for routes with an
1576
                         * unreachable type or IPv4 multipath routes. So, the current implementation does not
1577
                         * support managing such routes by other daemon or so, unless ManageForeignRoutes=no. */
1578
0
                        if (!only_static)
1579
0
                                continue;
1580
1581
                        /* When we mark only static routes, do not mark routes assigned to links that we do
1582
                         * not know the assignment of .network files to the interfaces. Otherwise, if an
1583
                         * interface is in the pending state, even if the .network file to be assigned to the
1584
                         * interface has KeepConfiguration=yes, routes on the interface will be removed.
1585
                         * This is especially important when systemd-networkd is restarted. */
1586
0
                        if (!IN_SET(route_link->state, LINK_STATE_UNMANAGED, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1587
0
                                continue;
1588
0
                }
1589
1590
0
                route_mark(route);
1591
0
        }
1592
1593
        /* Then, unmark all routes requested by active links. */
1594
0
        HASHMAP_FOREACH(other, link->manager->links_by_index) {
1595
0
                if (only_static && other == link)
1596
0
                        continue;
1597
1598
0
                if (!IN_SET(other->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
1599
0
                        continue;
1600
1601
0
                HASHMAP_FOREACH(route, other->network->routes_by_section) {
1602
0
                        if (route->source != NETWORK_CONFIG_SOURCE_STATIC)
1603
0
                                continue;
1604
1605
0
                        if (route->family == AF_INET || ordered_set_isempty(route->nexthops)) {
1606
0
                                r = link_unmark_route(other, route, NULL);
1607
0
                                if (r < 0)
1608
0
                                        return r;
1609
1610
0
                        } else {
1611
0
                                RouteNextHop *nh;
1612
0
                                ORDERED_SET_FOREACH(nh, route->nexthops) {
1613
0
                                        r = link_unmark_route(other, route, nh);
1614
0
                                        if (r < 0)
1615
0
                                                return r;
1616
0
                                }
1617
0
                        }
1618
0
                }
1619
1620
                /* Also unmark routes requested in .netdev file. */
1621
0
                if (other->netdev && other->netdev->kind == NETDEV_KIND_WIREGUARD) {
1622
0
                        Wireguard *w = WIREGUARD(other->netdev);
1623
1624
0
                        SET_FOREACH(route, w->routes) {
1625
0
                                r = link_unmark_route(other, route, NULL);
1626
0
                                if (r < 0)
1627
0
                                        return r;
1628
0
                        }
1629
0
                }
1630
0
        }
1631
1632
        /* Finally, remove all marked routes. */
1633
0
        SET_FOREACH(route, link->manager->routes) {
1634
0
                if (!route_is_marked(route))
1635
0
                        continue;
1636
1637
0
                RET_GATHER(r, route_remove(route, link->manager));
1638
0
        }
1639
1640
0
        return r;
1641
0
}
1642
1643
0
void link_forget_routes(Link *link) {
1644
0
        assert(link);
1645
0
        assert(link->ifindex > 0);
1646
0
        assert(!link_is_up(link));
1647
1648
        /* When an interface went down, IPv4 non-local routes bound to the interface are silently removed by
1649
         * the kernel, without any notifications. Let's forget them in that case. Otherwise, when the link
1650
         * goes up later, the configuration order of routes may be confused by the nonexistent routes.
1651
         * See issue #35047. */
1652
1653
0
        Route *route;
1654
0
        SET_FOREACH(route, link->manager->routes) {
1655
                // TODO: handle multipath routes
1656
0
                if (route->nexthop.ifindex != link->ifindex)
1657
0
                        continue;
1658
0
                if (route->family != AF_INET)
1659
0
                        continue;
1660
                // TODO: check RTN_NAT and RTN_XRESOLVE
1661
0
                if (!IN_SET(route->type, RTN_UNICAST, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
1662
0
                        continue;
1663
1664
0
                route_forget(link->manager, route, "Forgetting silently removed");
1665
0
        }
1666
0
}
1667
1668
24.4k
int network_add_ipv4ll_route(Network *network) {
1669
24.4k
        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1670
24.4k
        unsigned section_line;
1671
24.4k
        int r;
1672
1673
24.4k
        assert(network);
1674
1675
24.4k
        if (!network->ipv4ll_route)
1676
24.4k
                return 0;
1677
1678
29
        r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
1679
29
        if (r < 0)
1680
0
                return r;
1681
1682
        /* IPv4LLRoute= is in [Network] section. */
1683
29
        r = route_new_static(network, network->filename, section_line, &route);
1684
29
        if (r < 0)
1685
0
                return r;
1686
1687
29
        r = in_addr_from_string(AF_INET, "169.254.0.0", &route->dst);
1688
29
        if (r < 0)
1689
0
                return r;
1690
1691
29
        route->family = AF_INET;
1692
29
        route->dst_prefixlen = 16;
1693
29
        route->scope = RT_SCOPE_LINK;
1694
29
        route->scope_set = true;
1695
29
        route->table_set = true;
1696
29
        route->priority = IPV4LL_ROUTE_METRIC;
1697
29
        route->protocol = RTPROT_STATIC;
1698
1699
29
        TAKE_PTR(route);
1700
29
        return 0;
1701
29
}
1702
1703
24.4k
int network_add_default_route_on_device(Network *network) {
1704
24.4k
        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
1705
24.4k
        unsigned section_line;
1706
24.4k
        int r;
1707
1708
24.4k
        assert(network);
1709
1710
24.4k
        if (!network->default_route_on_device)
1711
24.4k
                return 0;
1712
1713
19
        r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
1714
19
        if (r < 0)
1715
0
                return r;
1716
1717
        /* DefaultRouteOnDevice= is in [Network] section. */
1718
19
        r = route_new_static(network, network->filename, section_line, &route);
1719
19
        if (r < 0)
1720
0
                return r;
1721
1722
19
        route->family = AF_INET;
1723
19
        route->scope = RT_SCOPE_LINK;
1724
19
        route->scope_set = true;
1725
19
        route->protocol = RTPROT_STATIC;
1726
1727
19
        TAKE_PTR(route);
1728
19
        return 0;
1729
19
}
1730
1731
static int config_parse_preferred_src(
1732
                const char *unit,
1733
                const char *filename,
1734
                unsigned line,
1735
                const char *section,
1736
                unsigned section_line,
1737
                const char *lvalue,
1738
                int ltype,
1739
                const char *rvalue,
1740
                void *data,
1741
971
                void *userdata) {
1742
1743
971
        Route *route = ASSERT_PTR(userdata);
1744
971
        int r;
1745
1746
971
        if (isempty(rvalue)) {
1747
194
                route->prefsrc_set = false;
1748
194
                route->prefsrc = IN_ADDR_NULL;
1749
194
                return 1;
1750
194
        }
1751
1752
777
        r = parse_boolean(rvalue);
1753
777
        if (r == 0) {
1754
                /* Accepts only no. That prohibits prefsrc set by DHCP lease. */
1755
194
                route->prefsrc_set = true;
1756
194
                route->prefsrc = IN_ADDR_NULL;
1757
194
                return 1;
1758
194
        }
1759
1760
583
        if (route->family == AF_UNSPEC)
1761
203
                r = in_addr_from_string_auto(rvalue, &route->family, &route->prefsrc);
1762
380
        else
1763
380
                r = in_addr_from_string(route->family, rvalue, &route->prefsrc);
1764
583
        if (r < 0)
1765
389
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
1766
1767
194
        route->prefsrc_set = true;
1768
194
        return 1;
1769
583
}
1770
1771
static int config_parse_route_destination(
1772
                const char *unit,
1773
                const char *filename,
1774
                unsigned line,
1775
                const char *section,
1776
                unsigned section_line,
1777
                const char *lvalue,
1778
                int ltype,
1779
                const char *rvalue,
1780
                void *data,
1781
3.19k
                void *userdata) {
1782
1783
3.19k
        Route *route = ASSERT_PTR(userdata);
1784
3.19k
        union in_addr_union *buffer;
1785
3.19k
        unsigned char *prefixlen;
1786
3.19k
        int r;
1787
1788
3.19k
        assert(lvalue);
1789
3.19k
        assert(rvalue);
1790
1791
3.19k
        if (streq(lvalue, "Destination")) {
1792
1.00k
                buffer = &route->dst;
1793
1.00k
                prefixlen = &route->dst_prefixlen;
1794
2.19k
        } else if (streq(lvalue, "Source")) {
1795
2.19k
                buffer = &route->src;
1796
2.19k
                prefixlen = &route->src_prefixlen;
1797
2.19k
        } else
1798
0
                assert_not_reached();
1799
1800
3.19k
        if (route->family == AF_UNSPEC)
1801
2.80k
                r = in_addr_prefix_from_string_auto(rvalue, &route->family, buffer, prefixlen);
1802
388
        else
1803
388
                r = in_addr_prefix_from_string(rvalue, route->family, buffer, prefixlen);
1804
3.19k
        if (r < 0)
1805
650
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
1806
1807
2.54k
        (void) in_addr_mask(route->family, buffer, *prefixlen);
1808
2.54k
        return 1;
1809
3.19k
}
1810
1811
static int config_parse_route_priority(
1812
                const char *unit,
1813
                const char *filename,
1814
                unsigned line,
1815
                const char *section,
1816
                unsigned section_line,
1817
                const char *lvalue,
1818
                int ltype,
1819
                const char *rvalue,
1820
                void *data,
1821
597
                void *userdata) {
1822
1823
597
        Route *route = ASSERT_PTR(userdata);
1824
597
        int r;
1825
1826
597
        assert(rvalue);
1827
1828
597
        r = safe_atou32(rvalue, &route->priority);
1829
597
        if (r < 0)
1830
197
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
1831
1832
400
        route->priority_set = true;
1833
400
        return 1;
1834
597
}
1835
1836
static int config_parse_route_scope(
1837
                const char *unit,
1838
                const char *filename,
1839
                unsigned line,
1840
                const char *section,
1841
                unsigned section_line,
1842
                const char *lvalue,
1843
                int ltype,
1844
                const char *rvalue,
1845
                void *data,
1846
912
                void *userdata) {
1847
1848
912
        Route *route = ASSERT_PTR(userdata);
1849
912
        int r;
1850
1851
912
        assert(rvalue);
1852
1853
912
        r = route_scope_from_string(rvalue);
1854
912
        if (r < 0)
1855
314
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
1856
1857
598
        route->scope = r;
1858
598
        route->scope_set = true;
1859
598
        return 1;
1860
912
}
1861
1862
static int config_parse_route_table(
1863
                const char *unit,
1864
                const char *filename,
1865
                unsigned line,
1866
                const char *section,
1867
                unsigned section_line,
1868
                const char *lvalue,
1869
                int ltype,
1870
                const char *rvalue,
1871
                void *data,
1872
1.13k
                void *userdata) {
1873
1874
1.13k
        Route *route = ASSERT_PTR(userdata);
1875
2.27k
        Manager *manager = ASSERT_PTR(ASSERT_PTR(route->network)->manager);
1876
2.27k
        int r;
1877
1878
2.27k
        assert(rvalue);
1879
1880
2.27k
        r = manager_get_route_table_from_string(manager, rvalue, &route->table);
1881
1.13k
        if (r < 0)
1882
503
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
1883
1884
634
        route->table_set = true;
1885
634
        return 1;
1886
1.13k
}
1887
1888
static int config_parse_route_preference(
1889
                const char *unit,
1890
                const char *filename,
1891
                unsigned line,
1892
                const char *section,
1893
                unsigned section_line,
1894
                const char *lvalue,
1895
                int ltype,
1896
                const char *rvalue,
1897
                void *data,
1898
841
                void *userdata) {
1899
1900
841
        Route *route = ASSERT_PTR(userdata);
1901
1902
841
        assert(rvalue);
1903
1904
841
        if (streq(rvalue, "low"))
1905
194
                route->pref = SD_NDISC_PREFERENCE_LOW;
1906
647
        else if (streq(rvalue, "medium"))
1907
198
                route->pref = SD_NDISC_PREFERENCE_MEDIUM;
1908
449
        else if (streq(rvalue, "high"))
1909
196
                route->pref = SD_NDISC_PREFERENCE_HIGH;
1910
253
        else
1911
253
                return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
1912
1913
588
        route->pref_set = true;
1914
588
        return 1;
1915
841
}
1916
1917
static int config_parse_route_protocol(
1918
                const char *unit,
1919
                const char *filename,
1920
                unsigned line,
1921
                const char *section,
1922
                unsigned section_line,
1923
                const char *lvalue,
1924
                int ltype,
1925
                const char *rvalue,
1926
                void *data,
1927
404
                void *userdata) {
1928
1929
404
        unsigned char *p = ASSERT_PTR(data);
1930
404
        int r;
1931
1932
404
        assert(rvalue);
1933
1934
404
        r = route_protocol_from_string(rvalue);
1935
404
        if (r < 0)
1936
205
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
1937
1938
199
        *p = (unsigned char) r;
1939
199
        return 1;
1940
404
}
1941
1942
static int config_parse_route_type(
1943
                const char *unit,
1944
                const char *filename,
1945
                unsigned line,
1946
                const char *section,
1947
                unsigned section_line,
1948
                const char *lvalue,
1949
                int ltype,
1950
                const char *rvalue,
1951
                void *data,
1952
2.76k
                void *userdata) {
1953
1954
2.76k
        unsigned char *p = ASSERT_PTR(data);
1955
2.76k
        int r;
1956
1957
2.76k
        assert(rvalue);
1958
1959
2.76k
        r = route_type_from_string(rvalue);
1960
2.76k
        if (r < 0)
1961
497
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
1962
1963
2.26k
        *p = (unsigned char) r;
1964
2.26k
        return 1;
1965
2.76k
}
1966
1967
int config_parse_route_section(
1968
                const char *unit,
1969
                const char *filename,
1970
                unsigned line,
1971
                const char *section,
1972
                unsigned section_line,
1973
                const char *lvalue,
1974
                int ltype,
1975
                const char *rvalue,
1976
                void *data,
1977
59.7k
                void *userdata) {
1978
1979
59.7k
        static const ConfigSectionParser table[_ROUTE_CONF_PARSER_MAX] = {
1980
59.7k
                [ROUTE_DESTINATION]               = { .parser = config_parse_route_destination,      .ltype = 0,                       .offset = 0,                                                   },
1981
59.7k
                [ROUTE_PREFERRED_SOURCE]          = { .parser = config_parse_preferred_src,          .ltype = 0,                       .offset = 0,                                                   },
1982
59.7k
                [ROUTE_PRIORITY]                  = { .parser = config_parse_route_priority,         .ltype = 0,                       .offset = 0,                                                   },
1983
59.7k
                [ROUTE_SCOPE]                     = { .parser = config_parse_route_scope,            .ltype = 0,                       .offset = 0,                                                   },
1984
59.7k
                [ROUTE_TABLE]                     = { .parser = config_parse_route_table,            .ltype = 0,                       .offset = 0,                                                   },
1985
59.7k
                [ROUTE_PREFERENCE]                = { .parser = config_parse_route_preference,       .ltype = 0,                       .offset = 0,                                                   },
1986
59.7k
                [ROUTE_PROTOCOL]                  = { .parser = config_parse_route_protocol,         .ltype = 0,                       .offset = offsetof(Route, protocol),                           },
1987
59.7k
                [ROUTE_TYPE]                      = { .parser = config_parse_route_type,             .ltype = 0,                       .offset = offsetof(Route, type),                               },
1988
59.7k
                [ROUTE_GATEWAY_NETWORK]           = { .parser = config_parse_gateway,                .ltype = 0,                       .offset = 0,                                                   },
1989
59.7k
                [ROUTE_GATEWAY]                   = { .parser = config_parse_gateway,                .ltype = 1,                       .offset = 0,                                                   },
1990
59.7k
                [ROUTE_GATEWAY_ONLINK]            = { .parser = config_parse_tristate,               .ltype = 0,                       .offset = offsetof(Route, gateway_onlink),                     },
1991
59.7k
                [ROUTE_MULTIPATH]                 = { .parser = config_parse_multipath_route,        .ltype = 0,                       .offset = offsetof(Route, nexthops),                           },
1992
59.7k
                [ROUTE_NEXTHOP]                   = { .parser = config_parse_route_nexthop,          .ltype = 0,                       .offset = offsetof(Route, nexthop_id),                         },
1993
59.7k
                [ROUTE_METRIC_MTU]                = { .parser = config_parse_route_metric,           .ltype = RTAX_MTU,                .offset = 0,                                                   },
1994
59.7k
                [ROUTE_METRIC_ADVMSS]             = { .parser = config_parse_route_metric,           .ltype = RTAX_ADVMSS,             .offset = 0,                                                   },
1995
59.7k
                [ROUTE_METRIC_HOPLIMIT]           = { .parser = config_parse_route_metric,           .ltype = RTAX_HOPLIMIT,           .offset = 0,                                                   },
1996
59.7k
                [ROUTE_METRIC_INITCWND]           = { .parser = config_parse_route_metric,           .ltype = RTAX_INITCWND,           .offset = 0,                                                   },
1997
59.7k
                [ROUTE_METRIC_RTO_MIN]            = { .parser = config_parse_route_metric,           .ltype = RTAX_RTO_MIN,            .offset = 0,                                                   },
1998
59.7k
                [ROUTE_METRIC_INITRWND]           = { .parser = config_parse_route_metric,           .ltype = RTAX_INITRWND,           .offset = 0,                                                   },
1999
59.7k
                [ROUTE_METRIC_QUICKACK]           = { .parser = config_parse_route_metric,           .ltype = RTAX_QUICKACK,           .offset = 0,                                                   },
2000
59.7k
                [ROUTE_METRIC_CC_ALGO]            = { .parser = config_parse_string,                 .ltype = 0,                       .offset = offsetof(Route, metric.tcp_congestion_control_algo), },
2001
59.7k
                [ROUTE_METRIC_FASTOPEN_NO_COOKIE] = { .parser = config_parse_route_metric,           .ltype = RTAX_FASTOPEN_NO_COOKIE, .offset = 0,                                                   },
2002
59.7k
        };
2003
2004
59.7k
        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
2005
59.7k
        Network *network = ASSERT_PTR(userdata);
2006
59.7k
        int r;
2007
2008
59.7k
        assert(filename);
2009
2010
59.7k
        if (streq(section, "Network")) {
2011
26.3k
                assert(streq_ptr(lvalue, "Gateway"));
2012
2013
                /* Clear all previously defined routes when Gateway= (empty) is set in [Network] section */
2014
26.3k
                if (isempty(rvalue)) {
2015
200
                        network->routes_by_section = hashmap_free(network->routes_by_section);
2016
200
                        return 0;
2017
200
                }
2018
2019
                /* we are not in an Route section, so use line number instead */
2020
26.1k
                r = route_new_static(network, filename, line, &route);
2021
26.1k
        } else
2022
33.3k
                r = route_new_static(network, filename, section_line, &route);
2023
59.5k
        if (r == -ENOMEM)
2024
0
                return log_oom();
2025
59.5k
        if (r < 0) {
2026
0
                log_syntax(unit, LOG_WARNING, filename, line, r,
2027
0
                           "Failed to allocate route, ignoring assignment: %m");
2028
0
                return 0;
2029
0
        }
2030
2031
59.5k
        r = config_section_parse(table, ELEMENTSOF(table),
2032
59.5k
                                 unit, filename, line, section, section_line, lvalue, ltype, rvalue, route);
2033
59.5k
        if (r <= 0)
2034
34.6k
                return r;
2035
2036
24.9k
        TAKE_PTR(route);
2037
24.9k
        return 0;
2038
59.5k
}
2039
2040
40.4k
int route_section_verify(Route *route) {
2041
40.4k
        int r;
2042
2043
40.4k
        assert(route);
2044
40.4k
        assert(route->section);
2045
2046
40.4k
        if (section_is_invalid(route->section))
2047
14.9k
                return -EINVAL;
2048
2049
        /* Currently, we do not support static route with finite lifetime. */
2050
40.4k
        assert(route->lifetime_usec == USEC_INFINITY);
2051
2052
25.4k
        r = route_section_verify_nexthops(route);
2053
25.4k
        if (r < 0)
2054
2.95k
                return r;
2055
2056
        /* table */
2057
22.5k
        if (!route->table_set && route->network && route->network->vrf) {
2058
0
                route->table = VRF(route->network->vrf)->table;
2059
0
                route->table_set = true;
2060
0
        }
2061
2062
22.5k
        if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
2063
516
                route->table = RT_TABLE_LOCAL;
2064
2065
        /* scope */
2066
22.5k
        if (!route->scope_set && route->family == AF_INET) {
2067
9.70k
                if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
2068
322
                        route->scope = RT_SCOPE_HOST;
2069
9.38k
                else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
2070
194
                        route->scope = RT_SCOPE_LINK;
2071
9.18k
                else if (IN_SET(route->type, RTN_UNICAST, RTN_UNSPEC) &&
2072
8.99k
                         !route->gateway_from_dhcp_or_ra &&
2073
8.79k
                         !in_addr_is_set(route->nexthop.family, &route->nexthop.gw) &&
2074
8.38k
                         ordered_set_isempty(route->nexthops) &&
2075
8.18k
                         route->nexthop_id == 0)
2076
7.94k
                        route->scope = RT_SCOPE_LINK;
2077
9.70k
        }
2078
2079
        /* IPv6 route */
2080
22.5k
        if (route->family == AF_INET6) {
2081
12.7k
                if (route->scope != RT_SCOPE_UNIVERSE) {
2082
196
                        log_section_warning(route->section, "Scope= is specified for IPv6 route. It will be ignored.");
2083
196
                        route->scope = RT_SCOPE_UNIVERSE;
2084
196
                }
2085
2086
12.7k
                if (route->priority == 0)
2087
10.4k
                        route->priority = IP6_RT_PRIO_USER;
2088
12.7k
        }
2089
2090
22.5k
        return 0;
2091
22.5k
}
2092
2093
3.22k
void network_drop_invalid_routes(Network *network) {
2094
3.22k
        Route *route;
2095
2096
3.22k
        assert(network);
2097
2098
3.22k
        HASHMAP_FOREACH(route, network->routes_by_section)
2099
22.9k
                if (route_section_verify(route) < 0)
2100
17.9k
                        route_detach(route);
2101
3.22k
}