• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 13380515387

17 Feb 2025 09:20PM UTC coverage: 71.822% (+0.1%) from 71.714%
13380515387

push

github

DaanDeMeyer
ukify: print all remaining log-like output to stderr

We want to be able to capture stdout for json and such, so convert
all remaining logging to stderr.

293883 of 409184 relevant lines covered (71.82%)

716959.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.9
/src/network/networkd-route.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <linux/if.h>
4
#include <linux/ipv6_route.h>
5
#include <linux/nexthop.h>
6

7
#include "alloc-util.h"
8
#include "event-util.h"
9
#include "netlink-util.h"
10
#include "networkd-address.h"
11
#include "networkd-ipv4ll.h"
12
#include "networkd-manager.h"
13
#include "networkd-network.h"
14
#include "networkd-nexthop.h"
15
#include "networkd-queue.h"
16
#include "networkd-route-util.h"
17
#include "networkd-route.h"
18
#include "parse-util.h"
19
#include "string-util.h"
20
#include "strv.h"
21
#include "vrf.h"
22
#include "wireguard.h"
23

24
static Route* route_detach_impl(Route *route) {
21,422✔
25
        assert(route);
21,422✔
26
        assert(!!route->network + !!route->manager + !!route->wireguard <= 1);
21,422✔
27

28
        if (route->network) {
21,422✔
29
                assert(route->section);
329✔
30
                hashmap_remove(route->network->routes_by_section, route->section);
329✔
31
                route->network = NULL;
329✔
32
                return route;
329✔
33
        }
34

35
        if (route->manager) {
21,093✔
36
                route_detach_from_nexthop(route);
6,678✔
37
                set_remove(route->manager->routes, route);
6,678✔
38
                route->manager = NULL;
6,678✔
39
                return route;
6,678✔
40
        }
41

42
        if (route->wireguard) {
14,415✔
43
                set_remove(route->wireguard->routes, route);
96✔
44
                route->wireguard = NULL;
96✔
45
                return route;
96✔
46
        }
47

48
        return NULL;
49
}
50

51
void route_detach(Route *route) {
7,103✔
52
        route_unref(route_detach_impl(route));
7,103✔
53
}
7,103✔
54

55
static Route* route_free(Route *route) {
14,319✔
56
        if (!route)
14,319✔
57
                return NULL;
58

59
        route_detach_impl(route);
14,319✔
60

61
        config_section_free(route->section);
14,319✔
62
        route_nexthops_done(route);
14,319✔
63
        route_metric_done(&route->metric);
14,319✔
64
        sd_event_source_disable_unref(route->expire);
14,319✔
65

66
        return mfree(route);
14,319✔
67
}
68

69
DEFINE_TRIVIAL_REF_UNREF_FUNC(Route, route, route_free);
28,656✔
70

71
static void route_hash_func(const Route *route, struct siphash *state) {
49,550✔
72
        assert(route);
49,550✔
73

74
        siphash24_compress_typesafe(route->family, state);
49,550✔
75

76
        switch (route->family) {
49,550✔
77
        case AF_INET:
24,561✔
78
                /* First, the table, destination prefix, priority, and tos (dscp), are used to find routes.
79
                 * See fib_table_insert(), fib_find_node(), and fib_find_alias() in net/ipv4/fib_trie.c of the kernel. */
80
                siphash24_compress_typesafe(route->table, state);
24,561✔
81
                in_addr_hash_func(&route->dst, route->family, state);
24,561✔
82
                siphash24_compress_typesafe(route->dst_prefixlen, state);
24,561✔
83
                siphash24_compress_typesafe(route->priority, state);
24,561✔
84
                siphash24_compress_typesafe(route->tos, state);
24,561✔
85

86
                /* Then, protocol, scope, type, flags, prefsrc, metrics (RTAX_* attributes), and nexthops (gateways)
87
                 * are used to find routes. See fib_find_info() in net/ipv4/fib_semantics.c of the kernel. */
88
                siphash24_compress_typesafe(route->protocol, state);
24,561✔
89
                siphash24_compress_typesafe(route->scope, state);
24,561✔
90
                siphash24_compress_typesafe(route->type, state);
24,561✔
91
                unsigned flags = route->flags & ~RTNH_COMPARE_MASK;
24,561✔
92
                siphash24_compress_typesafe(flags, state);
24,561✔
93
                in_addr_hash_func(&route->prefsrc, route->family, state);
24,561✔
94

95
                /* nexthops (id, number of nexthops, nexthop) */
96
                route_nexthops_hash_func(route, state);
24,561✔
97

98
                /* metrics */
99
                route_metric_hash_func(&route->metric, state);
24,561✔
100
                break;
49,550✔
101

102
        case AF_INET6:
24,989✔
103
                /* First, table and destination prefix are used for classifying routes.
104
                 * See fib6_add() and fib6_add_1() in net/ipv6/ip6_fib.c of the kernel. */
105
                siphash24_compress_typesafe(route->table, state);
24,989✔
106
                in_addr_hash_func(&route->dst, route->family, state);
24,989✔
107
                siphash24_compress_typesafe(route->dst_prefixlen, state);
24,989✔
108

109
                /* Then, source prefix is used. See fib6_add(). */
110
                in_addr_hash_func(&route->src, route->family, state);
24,989✔
111
                siphash24_compress_typesafe(route->src_prefixlen, state);
24,989✔
112

113
                /* See fib6_add_rt2node(). */
114
                siphash24_compress_typesafe(route->priority, state);
24,989✔
115

116
                /* See rt6_duplicate_nexthop() in include/net/ip6_route.h of the kernel.
117
                 * Here, we hash nexthop in a similar way as the one for IPv4. */
118
                route_nexthops_hash_func(route, state);
24,989✔
119

120
                /* Unlike IPv4 routes, metrics are not taken into account. */
121
                break;
122

123
        default:
124
                /* treat any other address family as AF_UNSPEC */
125
                break;
126
        }
127
}
49,550✔
128

129
static int route_compare_func(const Route *a, const Route *b) {
24,756✔
130
        int r;
24,756✔
131

132
        r = CMP(a->family, b->family);
24,756✔
133
        if (r != 0)
21,104✔
134
                return r;
5,484✔
135

136
        switch (a->family) {
19,272✔
137
        case AF_INET:
8,981✔
138
                r = CMP(a->table, b->table);
8,981✔
139
                if (r != 0)
8,626✔
140
                        return r;
1,469✔
141

142
                r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
7,512✔
143
                if (r != 0)
7,512✔
144
                        return r;
145

146
                r = CMP(a->dst_prefixlen, b->dst_prefixlen);
5,163✔
147
                if (r != 0)
5,163✔
148
                        return r;
×
149

150
                r = CMP(a->priority, b->priority);
5,163✔
151
                if (r != 0)
5,149✔
152
                        return r;
14✔
153

154
                r = CMP(a->tos, b->tos);
5,149✔
155
                if (r != 0)
5,149✔
156
                        return r;
×
157

158
                r = CMP(a->protocol, b->protocol);
5,149✔
159
                if (r != 0)
5,149✔
160
                        return r;
×
161

162
                r = CMP(a->scope, b->scope);
5,149✔
163
                if (r != 0)
5,149✔
164
                        return r;
×
165

166
                r = CMP(a->type, b->type);
5,149✔
167
                if (r != 0)
5,143✔
168
                        return r;
6✔
169

170
                r = CMP(a->flags & ~RTNH_COMPARE_MASK, b->flags & ~RTNH_COMPARE_MASK);
5,143✔
171
                if (r != 0)
5,143✔
172
                        return r;
5✔
173

174
                r = memcmp(&a->prefsrc, &b->prefsrc, FAMILY_ADDRESS_SIZE(a->family));
5,138✔
175
                if (r != 0)
5,138✔
176
                        return r;
177

178
                r = route_nexthops_compare_func(a, b);
5,123✔
179
                if (r != 0)
5,123✔
180
                        return r;
181

182
                return route_metric_compare_func(&a->metric, &b->metric);
5,120✔
183

184
        case AF_INET6:
10,291✔
185
                r = CMP(a->table, b->table);
10,291✔
186
                if (r != 0)
9,972✔
187
                        return r;
1,260✔
188

189
                r = memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family));
9,031✔
190
                if (r != 0)
9,031✔
191
                        return r;
192

193
                r = CMP(a->dst_prefixlen, b->dst_prefixlen);
7,525✔
194
                if (r != 0)
7,525✔
195
                        return r;
×
196

197
                r = memcmp(&a->src, &b->src, FAMILY_ADDRESS_SIZE(a->family));
7,525✔
198
                if (r != 0)
7,525✔
199
                        return r;
200

201
                r = CMP(a->src_prefixlen, b->src_prefixlen);
7,525✔
202
                if (r != 0)
7,525✔
203
                        return r;
×
204

205
                r = CMP(a->priority, b->priority);
7,525✔
206
                if (r != 0)
7,509✔
207
                        return r;
31✔
208

209
                return route_nexthops_compare_func(a, b);
7,494✔
210

211
        default:
212
                /* treat any other address family as AF_UNSPEC */
213
                return 0;
214
        }
215
}
216

217
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
2,168✔
218
                route_hash_ops,
219
                Route,
220
                route_hash_func,
221
                route_compare_func,
222
                route_detach);
223

224
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(
×
225
                route_hash_ops_unref,
226
                Route,
227
                route_hash_func,
228
                route_compare_func,
229
                route_unref);
230

231
DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
329✔
232
                route_section_hash_ops,
233
                ConfigSection,
234
                config_section_hash_func,
235
                config_section_compare_func,
236
                Route,
237
                route_detach);
238

239
int route_new(Route **ret) {
12,244✔
240
        _cleanup_(route_unrefp) Route *route = NULL;
12,244✔
241

242
        route = new(Route, 1);
12,244✔
243
        if (!route)
12,244✔
244
                return -ENOMEM;
245

246
        *route = (Route) {
12,244✔
247
                .n_ref = 1,
248
                .family = AF_UNSPEC,
249
                .scope = RT_SCOPE_UNIVERSE,
250
                .protocol = RTPROT_UNSPEC,
251
                .type = RTN_UNICAST,
252
                .table = RT_TABLE_MAIN,
253
                .lifetime_usec = USEC_INFINITY,
254
                .gateway_onlink = -1,
255
        };
256

257
        *ret = TAKE_PTR(route);
12,244✔
258

259
        return 0;
12,244✔
260
}
261

262
int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
591✔
263
        _cleanup_(config_section_freep) ConfigSection *n = NULL;
591✔
264
        _cleanup_(route_unrefp) Route *route = NULL;
591✔
265
        int r;
591✔
266

267
        assert(network);
591✔
268
        assert(ret);
591✔
269
        assert(filename);
591✔
270
        assert(section_line > 0);
591✔
271

272
        r = config_section_new(filename, section_line, &n);
591✔
273
        if (r < 0)
591✔
274
                return r;
275

276
        route = hashmap_get(network->routes_by_section, n);
591✔
277
        if (route) {
591✔
278
                *ret = TAKE_PTR(route);
262✔
279
                return 0;
262✔
280
        }
281

282
        if (hashmap_size(network->routes_by_section) >= routes_max())
329✔
283
                return -E2BIG;
284

285
        r = route_new(&route);
329✔
286
        if (r < 0)
329✔
287
                return r;
288

289
        route->protocol = RTPROT_STATIC;
329✔
290
        route->network = network;
329✔
291
        route->section = TAKE_PTR(n);
329✔
292
        route->source = NETWORK_CONFIG_SOURCE_STATIC;
329✔
293

294
        r = hashmap_ensure_put(&network->routes_by_section, &route_section_hash_ops, route->section, route);
329✔
295
        if (r < 0)
329✔
296
                return r;
297

298
        *ret = TAKE_PTR(route);
329✔
299
        return 0;
329✔
300
}
301

302
static int route_attach(Manager *manager, Route *route) {
6,678✔
303
        int r;
6,678✔
304

305
        assert(manager);
6,678✔
306
        assert(route);
6,678✔
307
        assert(!route->network);
6,678✔
308
        assert(!route->wireguard);
6,678✔
309

310
        r = set_ensure_put(&manager->routes, &route_hash_ops, route);
6,678✔
311
        if (r < 0)
6,678✔
312
                return r;
313
        if (r == 0)
6,678✔
314
                return -EEXIST;
315

316
        route->manager = manager;
6,678✔
317
        return 0;
6,678✔
318
}
319

320
int route_get(Manager *manager, const Route *route, Route **ret) {
16,127✔
321
        Route *existing;
16,127✔
322

323
        assert(manager);
16,127✔
324
        assert(route);
16,127✔
325

326
        existing = set_get(manager->routes, route);
16,127✔
327
        if (!existing)
16,127✔
328
                return -ENOENT;
329

330
        if (ret)
5,685✔
331
                *ret = existing;
5,611✔
332

333
        return 0;
334
}
335

336
static int route_get_link(Manager *manager, const Route *route, Link **ret) {
27,605✔
337
        int r;
27,605✔
338

339
        assert(manager);
27,605✔
340
        assert(route);
27,605✔
341

342
        if (route->nexthop_id != 0) {
27,605✔
343
                NextHop *nh;
1,485✔
344

345
                r = nexthop_get_by_id(manager, route->nexthop_id, &nh);
1,485✔
346
                if (r < 0)
1,485✔
347
                        return r;
1,485✔
348

349
                return link_get_by_index(manager, nh->ifindex, ret);
1,371✔
350
        }
351

352
        return route_nexthop_get_link(manager, &route->nexthop, ret);
26,120✔
353
}
354

355
bool route_is_bound_to_link(const Route *route, Link *link) {
936✔
356
        assert(route);
936✔
357
        assert(link);
936✔
358
        assert(link->manager);
936✔
359

360
        Link *route_link;
936✔
361
        if (route_get_link(link->manager, route, &route_link) < 0)
936✔
362
                return false;
936✔
363

364
        return route_link->ifindex == link->ifindex;
896✔
365
}
366

367
int route_get_request(Manager *manager, const Route *route, Request **ret) {
12,969✔
368
        Request *req;
12,969✔
369

370
        assert(manager);
12,969✔
371
        assert(route);
12,969✔
372

373
        req = ordered_set_get(manager->request_queue,
25,938✔
374
                              &(const Request) {
12,969✔
375
                                      .type = REQUEST_TYPE_ROUTE,
376
                                      .userdata = (void*) route,
377
                                      .hash_func = (hash_func_t) route_hash_func,
378
                                      .compare_func = (compare_func_t) route_compare_func,
379
                              });
380
        if (!req)
12,969✔
381
                return -ENOENT;
12,969✔
382

383
        if (ret)
646✔
384
                *ret = req;
646✔
385
        return 0;
386
}
387

388
int route_dup(const Route *src, const RouteNextHop *nh, Route **ret) {
2,075✔
389
        _cleanup_(route_unrefp) Route *dest = NULL;
2,075✔
390
        int r;
2,075✔
391

392
        assert(src);
2,075✔
393
        assert(ret);
2,075✔
394

395
        dest = newdup(Route, src, 1);
2,075✔
396
        if (!dest)
2,075✔
397
                return -ENOMEM;
398

399
        /* Unset number of reference and all pointers */
400
        dest->n_ref = 1;
2,075✔
401
        dest->manager = NULL;
2,075✔
402
        dest->network = NULL;
2,075✔
403
        dest->wireguard = NULL;
2,075✔
404
        dest->section = NULL;
2,075✔
405
        dest->nexthop = ROUTE_NEXTHOP_NULL;
2,075✔
406
        dest->nexthops = NULL;
2,075✔
407
        dest->metric = ROUTE_METRIC_NULL;
2,075✔
408
        dest->expire = NULL;
2,075✔
409

410
        r = route_nexthops_copy(src, nh, dest);
2,075✔
411
        if (r < 0)
2,075✔
412
                return r;
413

414
        r = route_metric_copy(&src->metric, &dest->metric);
2,075✔
415
        if (r < 0)
2,075✔
416
                return r;
417

418
        *ret = TAKE_PTR(dest);
2,075✔
419
        return 0;
2,075✔
420
}
421

422
void log_route_debug(const Route *route, const char *str, Manager *manager) {
14,828✔
423
        _cleanup_free_ char *state = NULL, *nexthop = NULL, *prefsrc = NULL,
×
424
                *table = NULL, *scope = NULL, *proto = NULL, *flags = NULL;
14,480✔
425
        const char *dst, *src;
14,828✔
426
        Link *link = NULL;
14,828✔
427

428
        assert(route);
14,828✔
429
        assert(str);
14,828✔
430
        assert(manager);
14,828✔
431

432
        if (!DEBUG_LOGGING)
14,828✔
433
                return;
348✔
434

435
        (void) route_get_link(manager, route, &link);
14,480✔
436

437
        (void) network_config_state_to_string_alloc(route->state, &state);
14,480✔
438

439
        dst = in_addr_is_set(route->family, &route->dst) || route->dst_prefixlen > 0 ?
15,637✔
440
                IN_ADDR_PREFIX_TO_STRING(route->family, &route->dst, route->dst_prefixlen) : NULL;
14,491✔
441
        src = in_addr_is_set(route->family, &route->src) || route->src_prefixlen > 0 ?
28,960✔
442
                IN_ADDR_PREFIX_TO_STRING(route->family, &route->src, route->src_prefixlen) : NULL;
14,480✔
443

444
        (void) route_nexthops_to_string(route, &nexthop);
14,480✔
445

446
        if (in_addr_is_set(route->family, &route->prefsrc))
14,480✔
447
                (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
6,298✔
448
        (void) route_scope_to_string_alloc(route->scope, &scope);
14,480✔
449
        (void) manager_get_route_table_to_string(manager, route->table, /* append_num = */ true, &table);
14,480✔
450
        (void) route_protocol_full_to_string_alloc(route->protocol, &proto);
14,480✔
451
        (void) route_flags_to_string_alloc(route->flags, &flags);
14,480✔
452

453
        log_link_debug(link,
58,697✔
454
                       "%s %s route (%s): dst: %s, src: %s, %s, prefsrc: %s, "
455
                       "table: %s, priority: %"PRIu32", "
456
                       "proto: %s, scope: %s, type: %s, flags: %s",
457
                       str, strna(network_config_source_to_string(route->source)), strna(state),
458
                       strna(dst), strna(src), strna(nexthop), strna(prefsrc),
459
                       strna(table), route->priority,
460
                       strna(proto), strna(scope), strna(route_type_to_string(route->type)), strna(flags));
461
}
462

463
static void route_forget(Manager *manager, Route *route, const char *msg) {
4,751✔
464
        assert(manager);
4,751✔
465
        assert(route);
4,751✔
466
        assert(msg);
4,751✔
467

468
        Request *req;
4,751✔
469
        if (route_get_request(manager, route, &req) >= 0)
4,751✔
470
                route_enter_removed(req->userdata);
2✔
471

472
        if (!route->manager && route_get(manager, route, &route) < 0)
4,751✔
473
                return;
154✔
474

475
        route_enter_removed(route);
4,597✔
476
        log_route_debug(route, msg, manager);
4,597✔
477
        route_detach(route);
4,597✔
478
}
479

480
static int route_set_netlink_message(const Route *route, sd_netlink_message *m) {
1,182✔
481
        int r;
1,182✔
482

483
        assert(route);
1,182✔
484
        assert(m);
1,182✔
485

486
        /* rtmsg header (and relevant attributes) */
487
        if (route->dst_prefixlen > 0) {
1,182✔
488
                r = netlink_message_append_in_addr_union(m, RTA_DST, route->family, &route->dst);
845✔
489
                if (r < 0)
845✔
490
                        return r;
491

492
                r = sd_rtnl_message_route_set_dst_prefixlen(m, route->dst_prefixlen);
845✔
493
                if (r < 0)
845✔
494
                        return r;
495
        }
496

497
        if (route->src_prefixlen > 0) {
1,182✔
498
                r = netlink_message_append_in_addr_union(m, RTA_SRC, route->family, &route->src);
×
499
                if (r < 0)
×
500
                        return r;
501

502
                r = sd_rtnl_message_route_set_src_prefixlen(m, route->src_prefixlen);
×
503
                if (r < 0)
×
504
                        return r;
505
        }
506

507
        r = sd_rtnl_message_route_set_tos(m, route->tos);
1,182✔
508
        if (r < 0)
1,182✔
509
                return r;
510

511
        r = sd_rtnl_message_route_set_scope(m, route->scope);
1,182✔
512
        if (r < 0)
1,182✔
513
                return r;
514

515
        r = sd_rtnl_message_route_set_type(m, route->type);
1,182✔
516
        if (r < 0)
1,182✔
517
                return r;
518

519
        r = sd_rtnl_message_route_set_flags(m, route->flags & ~RTNH_COMPARE_MASK);
1,182✔
520
        if (r < 0)
1,182✔
521
                return r;
522

523
        /* attributes */
524
        r = sd_netlink_message_append_u32(m, RTA_PRIORITY, route->priority);
1,182✔
525
        if (r < 0)
1,182✔
526
                return r;
527

528
        if (in_addr_is_set(route->family, &route->prefsrc)) {
1,182✔
529
                r = netlink_message_append_in_addr_union(m, RTA_PREFSRC, route->family, &route->prefsrc);
277✔
530
                if (r < 0)
277✔
531
                        return r;
532
        }
533

534
        if (route->table < 256) {
1,182✔
535
                r = sd_rtnl_message_route_set_table(m, route->table);
1,039✔
536
                if (r < 0)
1,039✔
537
                        return r;
538
        } else {
539
                r = sd_rtnl_message_route_set_table(m, RT_TABLE_UNSPEC);
143✔
540
                if (r < 0)
143✔
541
                        return r;
542

543
                /* Table attribute to allow more than 256. */
544
                r = sd_netlink_message_append_u32(m, RTA_TABLE, route->table);
143✔
545
                if (r < 0)
143✔
546
                        return r;
547
        }
548

549
        r = sd_netlink_message_append_u8(m, RTA_PREF, route->pref);
1,182✔
550
        if (r < 0)
1,182✔
551
                return r;
552

553
        /* nexthops */
554
        r = route_nexthops_set_netlink_message(route, m);
1,182✔
555
        if (r < 0)
1,182✔
556
                return r;
557

558
        /* metrics */
559
        r = route_metric_set_netlink_message(&route->metric, m);
1,182✔
560
        if (r < 0)
1,182✔
561
                return r;
×
562

563
        return 0;
564
}
565

566
static int route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, RemoveRequest *rreq) {
371✔
567
        int r;
371✔
568

569
        assert(m);
371✔
570
        assert(rreq);
371✔
571

572
        Manager *manager = ASSERT_PTR(rreq->manager);
371✔
573
        Route *route = ASSERT_PTR(rreq->userdata);
371✔
574

575
        r = sd_netlink_message_get_errno(m);
371✔
576
        if (r < 0) {
371✔
577
                log_message_full_errno(m,
162✔
578
                                       (r == -ESRCH || /* the route is already removed? */
579
                                        (r == -EINVAL && route->nexthop_id != 0) || /* The nexthop is already removed? */
580
                                        !route->manager) ? /* already detached? */
581
                                       LOG_DEBUG : LOG_WARNING,
582
                                       r, "Could not drop route, ignoring");
583

584
                /* If the route cannot be removed, then assume the route is already removed. */
585
                route_forget(manager, route, "Forgetting");
162✔
586
        }
587

588
        return 1;
371✔
589
}
590

591
int route_remove(Route *route, Manager *manager) {
371✔
592
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
371✔
593
        Link *link = NULL;
371✔
594
        int r;
371✔
595

596
        assert(route);
371✔
597
        assert(manager);
371✔
598

599
        if (manager->state == MANAGER_STOPPED)
371✔
600
                return 0; /* The remove request will not be queued anyway. Suppress logging below. */
601

602
        /* If the route is remembered, then use the remembered object. */
603
        (void) route_get(manager, route, &route);
371✔
604

605
        log_route_debug(route, "Removing", manager);
371✔
606

607
        /* For logging. */
608
        (void) route_get_link(manager, route, &link);
371✔
609

610
        r = sd_rtnl_message_new_route(manager->rtnl, &m, RTM_DELROUTE, route->family, route->protocol);
371✔
611
        if (r < 0)
371✔
612
                return log_link_warning_errno(link, r, "Could not create netlink message: %m");
×
613

614
        r = route_set_netlink_message(route, m);
371✔
615
        if (r < 0)
371✔
616
                return log_link_warning_errno(link, r, "Could not fill netlink message: %m");
×
617

618
        r = manager_remove_request_add(manager, route, route, manager->rtnl, m, route_remove_handler);
371✔
619
        if (r < 0)
371✔
620
                return log_link_warning_errno(link, r, "Could not queue rtnetlink message: %m");
×
621

622
        route_enter_removing(route);
371✔
623
        return 0;
624
}
625

626
int route_remove_and_cancel(Route *route, Manager *manager) {
200✔
627
        _cleanup_(request_unrefp) Request *req = NULL;
200✔
628
        bool waiting = false;
200✔
629

630
        assert(route);
200✔
631
        assert(manager);
200✔
632

633
        /* If the route is remembered by the manager, then use the remembered object. */
634
        (void) route_get(manager, route, &route);
200✔
635

636
        /* Cancel the request for the route. If the request is already called but we have not received the
637
         * notification about the request, then explicitly remove the route. */
638
        if (route_get_request(manager, route, &req) >= 0) {
200✔
639
                request_ref(req); /* avoid the request freed by request_detach() */
4✔
640
                waiting = req->waiting_reply;
4✔
641
                request_detach(req);
4✔
642
                route_cancel_requesting(route);
4✔
643
        }
644

645
        /* If we know that the route will come or already exists, remove it. */
646
        if (waiting || (route->manager && route_exists(route)))
200✔
647
                return route_remove(route, manager);
170✔
648

649
        return 0;
650
}
651

652
static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
1✔
653
        Route *route = ASSERT_PTR(userdata);
1✔
654
        int r;
1✔
655

656
        if (!route->manager)
1✔
657
                return 0; /* already detached. */
658

659
        r = route_remove(route, route->manager);
1✔
660
        if (r < 0) {
1✔
661
                Link *link = NULL;
×
662
                (void) route_get_link(route->manager, route, &link);
×
663
                log_link_warning_errno(link, r, "Could not remove route: %m");
×
664
                if (link)
×
665
                        link_enter_failed(link);
×
666
        }
667

668
        return 1;
669
}
670

671
static int route_setup_timer(Route *route, const struct rta_cacheinfo *cacheinfo) {
7,375✔
672
        int r;
7,375✔
673

674
        assert(route);
7,375✔
675

676
        if (cacheinfo && cacheinfo->rta_expires != 0)
7,375✔
677
                route->expiration_managed_by_kernel = true;
167✔
678

679
        if (route->lifetime_usec == USEC_INFINITY || /* We do not request expiration for the route. */
7,375✔
680
            route->expiration_managed_by_kernel) {   /* We have received nonzero expiration previously. The expiration is managed by the kernel. */
681
                route->expire = sd_event_source_disable_unref(route->expire);
7,371✔
682
                return 0;
7,371✔
683
        }
684

685
        Manager *manager = ASSERT_PTR(route->manager);
4✔
686
        r = event_reset_time(manager->event, &route->expire, CLOCK_BOOTTIME,
4✔
687
                             route->lifetime_usec, 0, route_expire_handler, route, 0, "route-expiration", true);
688
        if (r < 0) {
4✔
689
                Link *link = NULL;
×
690
                (void) route_get_link(manager, route, &link);
×
691
                return log_link_warning_errno(link, r, "Failed to configure expiration timer for route, ignoring: %m");
×
692
        }
693

694
        log_route_debug(route, "Configured expiration timer for", manager);
4✔
695
        return 1;
4✔
696
}
697

698
static int route_update_by_request(Route *route, Request *req) {
807✔
699
        assert(route);
807✔
700
        assert(req);
807✔
701

702
        Route *rt = ASSERT_PTR(req->userdata);
807✔
703

704
        route->provider = rt->provider;
807✔
705
        route->source = rt->source;
807✔
706
        route->lifetime_usec = rt->lifetime_usec;
807✔
707

708
        return 0;
807✔
709
}
710

711
static int route_update_on_existing_one(Request *req, Route *requested) {
171✔
712
        Manager *manager = ASSERT_PTR(ASSERT_PTR(req)->manager);
171✔
713
        Route *existing;
171✔
714
        int r;
171✔
715

716
        assert(requested);
171✔
717

718
        if (route_get(manager, requested, &existing) < 0)
171✔
719
                return 0;
171✔
720

721
        r = route_update_by_request(existing, req);
171✔
722
        if (r < 0)
171✔
723
                return r;
724

725
        r = route_setup_timer(existing, NULL);
171✔
726
        if (r < 0)
171✔
727
                return r;
728

729
        /* This may be a bug in the kernel, but the MTU of an IPv6 route can be updated only when the
730
         * route has an expiration timer managed by the kernel (not by us). See fib6_add_rt2node() in
731
         * net/ipv6/ip6_fib.c of the kernel. */
732
        if (existing->family == AF_INET6 &&
171✔
733
            existing->expiration_managed_by_kernel) {
734
                r = route_metric_set(&existing->metric, RTAX_MTU, route_metric_get(&requested->metric, RTAX_MTU));
74✔
735
                if (r < 0)
74✔
736
                        return r;
737
        }
738

739
        route_enter_configured(existing);
171✔
740
        return 0;
741
}
742

743
static int route_update_on_existing(Request *req) {
171✔
744
        Route *rt = ASSERT_PTR(ASSERT_PTR(req)->userdata);
171✔
745
        int r;
171✔
746

747
        if (!req->manager)
171✔
748
                /* Already detached? At least there are two possibilities then.
749
                 * 1) The interface is removed, and all queued requests for the interface are cancelled.
750
                 * 2) networkd is now stopping, hence all queued requests are cancelled.
751
                 * Anyway, we can ignore the request, and there is nothing we can do. */
752
                return 0;
171✔
753

754
        if (rt->family == AF_INET || ordered_set_isempty(rt->nexthops))
171✔
755
                return route_update_on_existing_one(req, rt);
171✔
756

757
        RouteNextHop *nh;
×
758
        ORDERED_SET_FOREACH(nh, rt->nexthops) {
×
759
                _cleanup_(route_unrefp) Route *dup = NULL;
×
760

761
                r = route_dup(rt, nh, &dup);
×
762
                if (r < 0)
×
763
                        return r;
764

765
                r = route_update_on_existing_one(req, dup);
×
766
                if (r < 0)
×
767
                        return r;
768
        }
769

770
        return 0;
×
771
}
772

773
int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Request *req, const char *error_msg) {
811✔
774
        int r;
811✔
775

776
        assert(m);
811✔
777
        assert(req);
811✔
778
        assert(error_msg);
811✔
779

780
        Link *link = ASSERT_PTR(req->link);
811✔
781

782
        r = sd_netlink_message_get_errno(m);
811✔
783
        if (r == -EEXIST) {
811✔
784
                /* When re-configuring an existing route, kernel does not send RTM_NEWROUTE notification, so
785
                 * here we need to update the state, provider, source, timer, and so on. */
786
                r = route_update_on_existing(req);
171✔
787
                if (r < 0) {
171✔
788
                        log_link_warning_errno(link, r, "Failed to update existing route: %m");
×
789
                        link_enter_failed(link);
×
790
                        return 0;
×
791
                }
792

793
                return 1;
794
        }
795
        if (r < 0) {
640✔
796
                log_link_message_warning_errno(link, m, r, error_msg);
×
797
                link_enter_failed(link);
×
798
                return 0;
×
799
        }
800

801
        return 1;
802
}
803

804
static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link, Request *req) {
811✔
805
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
811✔
806
        int r;
811✔
807

808
        assert(route);
811✔
809
        assert(link);
811✔
810
        assert(link->manager);
811✔
811
        assert(req);
811✔
812

813
        log_route_debug(route, "Configuring", link->manager);
811✔
814

815
        r = sd_rtnl_message_new_route(link->manager->rtnl, &m, RTM_NEWROUTE, route->family, route->protocol);
811✔
816
        if (r < 0)
811✔
817
                return r;
818

819
        r = route_set_netlink_message(route, m);
811✔
820
        if (r < 0)
811✔
821
                return r;
822

823
        if (lifetime_sec != UINT32_MAX) {
811✔
824
                r = sd_netlink_message_append_u32(m, RTA_EXPIRES, lifetime_sec);
215✔
825
                if (r < 0)
215✔
826
                        return r;
827
        }
828

829
        return request_call_netlink_async(link->manager->rtnl, m, req);
811✔
830
}
831

832
static int route_requeue_request(Request *req, Link *link, const Route *route) {
823✔
833
        _unused_ _cleanup_(request_unrefp) Request *req_unref = NULL;
823✔
834
        _cleanup_(route_unrefp) Route *tmp = NULL;
823✔
835
        int r;
823✔
836

837
        assert(req);
823✔
838
        assert(link);
823✔
839
        assert(link->manager);
823✔
840
        assert(route);
823✔
841

842
        /* It is not possible to adjust the Route object owned by Request, as it is used as a key to manage
843
         * Request objects in the queue. Hence, we need to re-request with the updated Route object. */
844

845
        if (!route_nexthops_needs_adjust(route))
823✔
846
                return 0; /* The Route object does not need the adjustment. Continue with it. */
847

848
        r = route_dup(route, NULL, &tmp);
155✔
849
        if (r < 0)
155✔
850
                return r;
851

852
        r = route_adjust_nexthops(tmp, link);
155✔
853
        if (r <= 0)
155✔
854
                return r;
855

856
        if (route_compare_func(route, tmp) == 0 && route->type == tmp->type)
20✔
857
                return 0; /* No effective change?? That's OK. */
858

859
        /* Avoid the request to be freed by request_detach(). */
860
        req_unref = request_ref(req);
12✔
861

862
        /* Detach the request from the queue, to make not the new request is deduped.
863
         * Why this is necessary? IPv6 routes with different type may be handled as the same,
864
         * As commented in route_adjust_nexthops(), we need to configure the adjusted type,
865
         * otherwise we cannot remove the route on reconfigure or so. If we request the new Route object
866
         * without detaching the current request, the new request is deduped, and the route is configured
867
         * with unmodified type. */
868
        request_detach(req);
12✔
869

870
        /* Request the route with the adjusted Route object combined with the same other parameters. */
871
        r = link_requeue_request(link, req, tmp, NULL);
12✔
872
        if (r < 0)
12✔
873
                return r;
874
        if (r == 0)
12✔
875
                return 1; /* Already queued?? That's OK. Maybe, [Route] section is effectively duplicated. */
876

877
        TAKE_PTR(tmp);
12✔
878
        return 1; /* New request is queued. Finish to process this request. */
12✔
879
}
880

881
static int route_is_ready_to_configure(const Route *route, Link *link) {
20,085✔
882
        assert(route);
20,085✔
883
        assert(link);
20,085✔
884

885
        if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false))
20,085✔
886
                return false;
887

888
        if (in_addr_is_set(route->family, &route->prefsrc) > 0) {
5,051✔
889
                Address *a;
1,493✔
890

891
                if (manager_get_address(link->manager, route->family, &route->prefsrc, &a) < 0)
1,493✔
892
                        return false;
1,016✔
893

894
                if (!address_is_ready(a))
487✔
895
                        return false;
896
        }
897

898
        return route_nexthops_is_ready_to_configure(route, link->manager);
4,035✔
899
}
900

901
static int route_process_request(Request *req, Link *link, Route *route) {
20,085✔
902
        Route *existing;
20,085✔
903
        int r;
20,085✔
904

905
        assert(req);
20,085✔
906
        assert(link);
20,085✔
907
        assert(link->manager);
20,085✔
908
        assert(route);
20,085✔
909

910
        r = route_is_ready_to_configure(route, link);
20,085✔
911
        if (r < 0)
20,085✔
912
                return log_link_warning_errno(link, r, "Failed to check if route is ready to configure: %m");
×
913
        if (r == 0)
20,085✔
914
                return 0;
915

916
        usec_t now_usec;
823✔
917
        assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
823✔
918
        uint32_t sec = usec_to_sec(route->lifetime_usec, now_usec);
823✔
919
        if (sec == 0) {
823✔
920
                log_link_debug(link, "Refuse to configure %s route with zero lifetime.",
×
921
                               network_config_source_to_string(route->source));
922

923
                route_cancel_requesting(route);
×
924
                if (route_get(link->manager, route, &existing) >= 0)
×
925
                        route_cancel_requesting(existing);
×
926
                return 1;
×
927
        }
928

929
        r = route_requeue_request(req, link, route);
823✔
930
        if (r != 0)
823✔
931
                return r;
932

933
        r = route_configure(route, sec, link, req);
811✔
934
        if (r < 0)
811✔
935
                return log_link_warning_errno(link, r, "Failed to configure route: %m");
×
936

937
        route_enter_configuring(route);
811✔
938
        if (route_get(link->manager, route, &existing) >= 0)
811✔
939
                route_enter_configuring(existing);
171✔
940
        return 1;
941
}
942

943
static int link_request_route_one(
1,066✔
944
                Link *link,
945
                const Route *route,
946
                const RouteNextHop *nh,
947
                unsigned *message_counter,
948
                route_netlink_handler_t netlink_handler) {
949

950
        _cleanup_(route_unrefp) Route *tmp = NULL;
1,066✔
951
        Route *existing = NULL;
1,066✔
952
        int r;
1,066✔
953

954
        assert(link);
1,066✔
955
        assert(link->manager);
1,066✔
956
        assert(route);
1,066✔
957

958
        r = route_dup(route, nh, &tmp);
1,066✔
959
        if (r < 0)
1,066✔
960
                return r;
961

962
        r = route_adjust_nexthops(tmp, link);
1,066✔
963
        if (r < 0)
1,066✔
964
                return r;
965

966
        if (route_get(link->manager, tmp, &existing) >= 0)
1,066✔
967
                /* Copy state for logging below. */
968
                tmp->state = existing->state;
180✔
969

970
        log_route_debug(tmp, "Requesting", link->manager);
1,066✔
971
        r = link_queue_request_safe(link, REQUEST_TYPE_ROUTE,
1,066✔
972
                                    tmp,
973
                                    route_unref,
974
                                    route_hash_func,
975
                                    route_compare_func,
976
                                    route_process_request,
977
                                    message_counter,
978
                                    netlink_handler,
979
                                    NULL);
980
        if (r <= 0)
1,066✔
981
                return r;
982

983
        route_enter_requesting(tmp);
831✔
984
        if (existing)
831✔
985
                route_enter_requesting(existing);
176✔
986

987
        TAKE_PTR(tmp);
831✔
988
        return 1;
831✔
989
}
990

991
int link_request_route(
1,048✔
992
                Link *link,
993
                const Route *route,
994
                unsigned *message_counter,
995
                route_netlink_handler_t netlink_handler) {
996

997
        int r;
1,048✔
998

999
        assert(link);
1,048✔
1000
        assert(link->manager);
1,048✔
1001
        assert(route);
1,048✔
1002
        assert(route->source != NETWORK_CONFIG_SOURCE_FOREIGN);
1,048✔
1003

1004
        if (route->family == AF_INET || route_is_reject(route) || ordered_set_isempty(route->nexthops))
1,048✔
1005
                return link_request_route_one(link, route, NULL, message_counter, netlink_handler);
1,042✔
1006

1007
        RouteNextHop *nh;
6✔
1008
        ORDERED_SET_FOREACH(nh, route->nexthops) {
30✔
1009
                r = link_request_route_one(link, route, nh, message_counter, netlink_handler);
24✔
1010
                if (r < 0)
24✔
1011
                        return r;
×
1012
        }
1013

1014
        return 0;
6✔
1015
}
1016

1017
static int static_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Route *route) {
362✔
1018
        int r;
362✔
1019

1020
        assert(link);
362✔
1021

1022
        r = route_configure_handler_internal(rtnl, m, req, "Could not set static route");
362✔
1023
        if (r <= 0)
362✔
1024
                return r;
1025

1026
        if (link->static_route_messages == 0) {
362✔
1027
                log_link_debug(link, "Routes set");
100✔
1028
                link->static_routes_configured = true;
100✔
1029
                link_check_ready(link);
100✔
1030
        }
1031

1032
        return 1;
1033
}
1034

1035
static int link_request_wireguard_routes(Link *link, bool only_ipv4) {
1,403✔
1036
        Route *route;
1,403✔
1037
        int r;
1,403✔
1038

1039
        assert(link);
1,403✔
1040

1041
        if (!link->netdev || link->netdev->kind != NETDEV_KIND_WIREGUARD)
1,403✔
1042
                return 0;
1,403✔
1043

1044
        Wireguard *w = WIREGUARD(link->netdev);
9✔
1045

1046
        SET_FOREACH(route, w->routes) {
153✔
1047
                if (only_ipv4 && route->family != AF_INET)
144✔
1048
                        continue;
×
1049

1050
                r = link_request_route(link, route, &link->static_route_messages, static_route_handler);
144✔
1051
                if (r < 0)
144✔
1052
                        return r;
×
1053
        }
1054

1055
        return 0;
9✔
1056
}
1057

1058
int link_request_static_routes(Link *link, bool only_ipv4) {
1,403✔
1059
        Route *route;
1,403✔
1060
        int r;
1,403✔
1061

1062
        assert(link);
1,403✔
1063
        assert(link->network);
1,403✔
1064

1065
        link->static_routes_configured = false;
1,403✔
1066

1067
        HASHMAP_FOREACH(route, link->network->routes_by_section) {
1,828✔
1068
                if (route->source != NETWORK_CONFIG_SOURCE_STATIC)
425✔
1069
                        continue;
20✔
1070

1071
                if (only_ipv4 && route->family != AF_INET)
405✔
1072
                        continue;
×
1073

1074
                r = link_request_route(link, route, &link->static_route_messages, static_route_handler);
405✔
1075
                if (r < 0)
405✔
1076
                        return r;
×
1077
        }
1078

1079
        r = link_request_wireguard_routes(link, only_ipv4);
1,403✔
1080
        if (r < 0)
1,403✔
1081
                return r;
1082

1083
        if (link->static_route_messages == 0) {
1,403✔
1084
                link->static_routes_configured = true;
1,231✔
1085
                link_check_ready(link);
1,231✔
1086
        } else {
1087
                log_link_debug(link, "Requesting routes");
172✔
1088
                link_set_state(link, LINK_STATE_CONFIGURING);
172✔
1089
        }
1090

1091
        return 0;
1092
}
1093

1094
static int process_route_one(
11,335✔
1095
                Manager *manager,
1096
                uint16_t type,
1097
                Route *tmp,
1098
                const struct rta_cacheinfo *cacheinfo) {
1099

1100
        Route *route = NULL;
11,335✔
1101
        Link *link = NULL;
11,335✔
1102
        bool is_new = false, update_dhcp4;
11,335✔
1103
        int r;
11,335✔
1104

1105
        assert(manager);
11,335✔
1106
        assert(tmp);
11,335✔
1107
        assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE));
11,335✔
1108

1109
        (void) route_get(manager, tmp, &route);
11,335✔
1110
        (void) route_get_link(manager, tmp, &link);
11,335✔
1111

1112
        update_dhcp4 = link && tmp->family == AF_INET6 && tmp->dst_prefixlen == 0;
11,335✔
1113

1114
        switch (type) {
11,335✔
1115
        case RTM_NEWROUTE: {
7,321✔
1116
                Request *req = NULL;
7,321✔
1117
                (void) route_get_request(manager, tmp, &req);
7,321✔
1118

1119
                if (!route) {
7,321✔
1120
                        if (!manager->manage_foreign_routes && !(req && req->waiting_reply)) {
6,795✔
1121
                                route_enter_configured(tmp);
117✔
1122
                                log_route_debug(tmp, "Ignoring received", manager);
117✔
1123
                                return 0;
117✔
1124
                        }
1125

1126
                        /* If we do not know the route, then save it. */
1127
                        r = route_attach(manager, tmp);
6,678✔
1128
                        if (r < 0) {
6,678✔
1129
                                log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m");
×
1130
                                return 0;
×
1131
                        }
1132

1133
                        route = route_ref(tmp);
6,678✔
1134
                        is_new = true;
6,678✔
1135

1136
                } else {
1137
                        /* Update remembered route with the received notification. */
1138

1139
                        /* Here, update weight only when a non-zero weight is received. As the kernel does
1140
                         * not provide the weight of a single-path route. In such case, tmp->nexthop.weight
1141
                         * is zero, hence we should not overwrite the known weight of the route. */
1142
                        if (tmp->nexthop.weight != 0)
526✔
1143
                                route->nexthop.weight = tmp->nexthop.weight;
22✔
1144
                }
1145

1146
                /* Also update information that cannot be obtained through netlink notification. */
1147
                if (req && req->waiting_reply) {
7,204✔
1148
                        r = route_update_by_request(route, req);
636✔
1149
                        if (r < 0) {
636✔
1150
                                log_link_warning_errno(link, r, "Failed to update route by request: %m");
×
1151
                                link_enter_failed(link);
×
1152
                                return 0;
×
1153
                        }
1154

1155
                        /* We configure IPv6 multipath route separately. When the first path is configured,
1156
                         * the kernel does not provide the weight of the path. So, we need to adjust it here.
1157
                         * Hopefully, the weight is assigned correctly. */
1158
                        if (route->nexthop.weight == 0) {
636✔
1159
                                Route *rt = ASSERT_PTR(req->userdata);
626✔
1160
                                route->nexthop.weight = rt->nexthop.weight;
626✔
1161
                        }
1162
                }
1163

1164
                route_attach_to_nexthop(route);
7,204✔
1165

1166
                route_enter_configured(route);
7,204✔
1167
                log_route_debug(route, is_new ? "Received new" : "Received remembered", manager);
7,730✔
1168

1169
                (void) route_setup_timer(route, cacheinfo);
7,204✔
1170

1171
                break;
7,204✔
1172
        }
1173
        case RTM_DELROUTE:
4,014✔
1174
                if (route)
4,014✔
1175
                        route_forget(manager, route, "Forgetting removed");
3,426✔
1176
                else
1177
                        log_route_debug(tmp,
588✔
1178
                                        manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received",
588✔
1179
                                        manager);
1180
                break;
1181

1182
        default:
×
1183
                assert_not_reached();
×
1184
        }
1185

1186
        if (update_dhcp4) {
11,218✔
1187
                r = dhcp4_update_ipv6_connectivity(link);
231✔
1188
                if (r < 0) {
231✔
1189
                        log_link_warning_errno(link, r, "Failed to notify IPv6 connectivity to DHCPv4 client: %m");
×
1190
                        link_enter_failed(link);
×
1191
                }
1192
        }
1193

1194
        return 1;
1195
}
1196

1197
int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
11,313✔
1198
        _cleanup_(route_unrefp) Route *tmp = NULL;
11,313✔
1199
        int r;
11,313✔
1200

1201
        assert(rtnl);
11,313✔
1202
        assert(message);
11,313✔
1203
        assert(m);
11,313✔
1204

1205
        if (sd_netlink_message_is_error(message)) {
11,313✔
1206
                r = sd_netlink_message_get_errno(message);
×
1207
                if (r < 0)
×
1208
                        log_message_warning_errno(message, r, "rtnl: failed to receive route message, ignoring");
×
1209

1210
                return 0;
×
1211
        }
1212

1213
        uint16_t type;
11,313✔
1214
        r = sd_netlink_message_get_type(message, &type);
11,313✔
1215
        if (r < 0) {
11,313✔
1216
                log_warning_errno(r, "rtnl: could not get message type, ignoring: %m");
×
1217
                return 0;
×
1218
        } else if (!IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)) {
11,313✔
1219
                log_warning("rtnl: received unexpected message type %u when processing route, ignoring.", type);
×
1220
                return 0;
×
1221
        }
1222

1223
        r = route_new(&tmp);
11,313✔
1224
        if (r < 0)
11,313✔
1225
                return log_oom();
×
1226

1227
        /* rtmsg header */
1228
        r = sd_rtnl_message_route_get_family(message, &tmp->family);
11,313✔
1229
        if (r < 0) {
11,313✔
1230
                log_warning_errno(r, "rtnl: received route message without family, ignoring: %m");
×
1231
                return 0;
×
1232
        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
11,313✔
1233
                log_debug("rtnl: received route message with invalid family '%i', ignoring.", tmp->family);
×
1234
                return 0;
×
1235
        }
1236

1237
        r = sd_rtnl_message_route_get_dst_prefixlen(message, &tmp->dst_prefixlen);
11,313✔
1238
        if (r < 0) {
11,313✔
1239
                log_warning_errno(r, "rtnl: received route message with invalid destination prefixlen, ignoring: %m");
×
1240
                return 0;
×
1241
        }
1242

1243
        r = sd_rtnl_message_route_get_src_prefixlen(message, &tmp->src_prefixlen);
11,313✔
1244
        if (r < 0) {
11,313✔
1245
                log_warning_errno(r, "rtnl: received route message with invalid source prefixlen, ignoring: %m");
×
1246
                return 0;
×
1247
        }
1248

1249
        r = sd_rtnl_message_route_get_tos(message, &tmp->tos);
11,313✔
1250
        if (r < 0) {
11,313✔
1251
                log_warning_errno(r, "rtnl: received route message with invalid tos, ignoring: %m");
×
1252
                return 0;
×
1253
        }
1254

1255
        r = sd_rtnl_message_route_get_protocol(message, &tmp->protocol);
11,313✔
1256
        if (r < 0) {
11,313✔
1257
                log_warning_errno(r, "rtnl: received route message without route protocol, ignoring: %m");
×
1258
                return 0;
×
1259
        }
1260

1261
        r = sd_rtnl_message_route_get_scope(message, &tmp->scope);
11,313✔
1262
        if (r < 0) {
11,313✔
1263
                log_warning_errno(r, "rtnl: received route message with invalid scope, ignoring: %m");
×
1264
                return 0;
×
1265
        }
1266

1267
        r = sd_rtnl_message_route_get_type(message, &tmp->type);
11,313✔
1268
        if (r < 0) {
11,313✔
1269
                log_warning_errno(r, "rtnl: received route message with invalid type, ignoring: %m");
×
1270
                return 0;
×
1271
        }
1272

1273
        r = sd_rtnl_message_route_get_flags(message, &tmp->flags);
11,313✔
1274
        if (r < 0) {
11,313✔
1275
                log_warning_errno(r, "rtnl: received route message without route flags, ignoring: %m");
×
1276
                return 0;
×
1277
        }
1278

1279
        /* attributes */
1280
        r = netlink_message_read_in_addr_union(message, RTA_DST, tmp->family, &tmp->dst);
11,313✔
1281
        if (r < 0 && r != -ENODATA) {
11,313✔
1282
                log_warning_errno(r, "rtnl: received route message without valid destination, ignoring: %m");
×
1283
                return 0;
×
1284
        }
1285

1286
        r = netlink_message_read_in_addr_union(message, RTA_SRC, tmp->family, &tmp->src);
11,313✔
1287
        if (r < 0 && r != -ENODATA) {
11,313✔
1288
                log_warning_errno(r, "rtnl: received route message without valid source, ignoring: %m");
×
1289
                return 0;
×
1290
        }
1291

1292
        r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &tmp->priority);
11,313✔
1293
        if (r < 0 && r != -ENODATA) {
11,313✔
1294
                log_warning_errno(r, "rtnl: received route message with invalid priority, ignoring: %m");
×
1295
                return 0;
×
1296
        }
1297

1298
        r = netlink_message_read_in_addr_union(message, RTA_PREFSRC, tmp->family, &tmp->prefsrc);
11,313✔
1299
        if (r < 0 && r != -ENODATA) {
11,313✔
1300
                log_warning_errno(r, "rtnl: received route message without valid preferred source, ignoring: %m");
×
1301
                return 0;
×
1302
        }
1303

1304
        r = sd_netlink_message_read_u32(message, RTA_TABLE, &tmp->table);
11,313✔
1305
        if (r == -ENODATA) {
11,313✔
1306
                unsigned char table;
×
1307

1308
                r = sd_rtnl_message_route_get_table(message, &table);
×
1309
                if (r >= 0)
×
1310
                        tmp->table = table;
×
1311
        }
1312
        if (r < 0) {
11,313✔
1313
                log_warning_errno(r, "rtnl: received route message with invalid table, ignoring: %m");
×
1314
                return 0;
×
1315
        }
1316

1317
        r = sd_netlink_message_read_u8(message, RTA_PREF, &tmp->pref);
11,313✔
1318
        if (r < 0 && r != -ENODATA) {
11,313✔
1319
                log_warning_errno(r, "rtnl: received route message with invalid preference, ignoring: %m");
×
1320
                return 0;
×
1321
        }
1322

1323
        /* nexthops */
1324
        if (route_nexthops_read_netlink_message(tmp, message) < 0)
11,313✔
1325
                return 0;
1326

1327
        /* metrics */
1328
        if (route_metric_read_netlink_message(&tmp->metric, message) < 0)
11,313✔
1329
                return 0;
1330

1331
        bool has_cacheinfo;
11,313✔
1332
        struct rta_cacheinfo cacheinfo;
11,313✔
1333
        r = sd_netlink_message_read(message, RTA_CACHEINFO, sizeof(cacheinfo), &cacheinfo);
11,313✔
1334
        if (r < 0 && r != -ENODATA) {
11,313✔
1335
                log_warning_errno(r, "rtnl: failed to read RTA_CACHEINFO attribute, ignoring: %m");
×
1336
                return 0;
×
1337
        }
1338
        has_cacheinfo = r >= 0;
11,313✔
1339

1340
        if (tmp->family == AF_INET || ordered_set_isempty(tmp->nexthops))
11,313✔
1341
                return process_route_one(m, type, tmp, has_cacheinfo ? &cacheinfo : NULL);
16,419✔
1342

1343
        RouteNextHop *nh;
10✔
1344
        ORDERED_SET_FOREACH(nh, tmp->nexthops) {
42✔
1345
                _cleanup_(route_unrefp) Route *dup = NULL;
32✔
1346

1347
                r = route_dup(tmp, nh, &dup);
32✔
1348
                if (r < 0)
32✔
1349
                        return log_oom();
×
1350

1351
                r = process_route_one(m, type, dup, has_cacheinfo ? &cacheinfo : NULL);
32✔
1352
                if (r < 0)
32✔
1353
                        return r;
1354
        }
1355

1356
        return 1;
10✔
1357
}
1358

1359
void manager_mark_routes(Manager *manager, Link *link, NetworkConfigSource source) {
96✔
1360
        Route *route;
96✔
1361

1362
        assert(manager);
96✔
1363

1364
        SET_FOREACH(route, manager->routes) {
2,184✔
1365
                if (route->source != source)
1,992✔
1366
                        continue;
1,948✔
1367

1368
                if (link) {
44✔
1369
                        Link *route_link;
44✔
1370

1371
                        if (route_get_link(manager, route, &route_link) < 0)
44✔
1372
                                continue;
9✔
1373
                        if (route_link != link)
44✔
1374
                                continue;
9✔
1375
                }
1376

1377
                route_mark(route);
2,123✔
1378
        }
1379
}
96✔
1380

1381
static bool route_by_kernel(const Route *route) {
24,402✔
1382
        assert(route);
24,402✔
1383

1384
        if (route->protocol == RTPROT_KERNEL)
24,402✔
1385
                return true;
1386

1387
        /* The kernels older than a826b04303a40d52439aa141035fca5654ccaccd (v5.11) create the IPv6
1388
         * multicast with RTPROT_BOOT. Do not touch it. */
1389
        if (route->protocol == RTPROT_BOOT &&
1,417✔
1390
            route->family == AF_INET6 &&
4✔
1391
            route->dst_prefixlen == 8 &&
3✔
1392
            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 }}}))
×
1393
                return true;
×
1394

1395
        return false;
1,417✔
1396
}
1397

1398
bool route_can_update(const Route *existing, const Route *requesting) {
487✔
1399
        assert(existing);
487✔
1400
        assert(requesting);
487✔
1401

1402
        if (route_compare_func(existing, requesting) != 0)
487✔
1403
                return false;
1404

1405
        switch (existing->family) {
477✔
1406
        case AF_INET:
130✔
1407
                if (existing->nexthop.weight != requesting->nexthop.weight)
130✔
1408
                        return false;
×
1409
                return true;
1410

1411
        case AF_INET6:
347✔
1412
                if (existing->protocol != requesting->protocol)
347✔
1413
                        return false;
1414
                if (existing->type != requesting->type)
346✔
1415
                        return false;
1416
                if (existing->flags != requesting->flags)
344✔
1417
                        return false;
1418
                if (!in6_addr_equal(&existing->prefsrc.in6, &requesting->prefsrc.in6))
344✔
1419
                        return false;
1420
                if (existing->pref != requesting->pref)
344✔
1421
                        return false;
1422
                if (existing->expiration_managed_by_kernel && requesting->lifetime_usec == USEC_INFINITY)
344✔
1423
                        return false; /* We cannot disable expiration timer in the kernel. */
1424
                if (!route_metric_can_update(&existing->metric, &requesting->metric, existing->expiration_managed_by_kernel))
344✔
1425
                        return false;
1426
                if (existing->nexthop.weight != requesting->nexthop.weight)
344✔
1427
                        return false;
×
1428
                return true;
1429

1430
        default:
×
1431
                assert_not_reached();
×
1432
        }
1433
}
1434

1435
static int link_unmark_route(Link *link, const Route *route, const RouteNextHop *nh) {
805✔
1436
        _cleanup_(route_unrefp) Route *tmp = NULL;
×
1437
        Route *existing;
805✔
1438
        int r;
805✔
1439

1440
        assert(link);
805✔
1441
        assert(route);
805✔
1442

1443
        r = route_dup(route, nh, &tmp);
805✔
1444
        if (r < 0)
805✔
1445
                return r;
1446

1447
        r = route_adjust_nexthops(tmp, link);
805✔
1448
        if (r < 0)
805✔
1449
                return r;
1450

1451
        if (route_get(link->manager, tmp, &existing) < 0)
805✔
1452
                return 0;
1453

1454
        if (!route_can_update(existing, tmp))
402✔
1455
                return 0;
1456

1457
        route_unmark(existing);
805✔
1458
        return 1;
1459
}
1460

1461
int link_drop_routes(Link *link, bool only_static) {
3,150✔
1462
        Route *route;
3,150✔
1463
        Link *other;
3,150✔
1464
        int r = 0;
3,150✔
1465

1466
        assert(link);
3,150✔
1467
        assert(link->manager);
3,150✔
1468

1469
        /* First, mark all routes. */
1470
        SET_FOREACH(route, link->manager->routes) {
30,702✔
1471
                /* Do not touch routes managed by the kernel. */
1472
                if (route_by_kernel(route))
24,402✔
1473
                        continue;
22,985✔
1474

1475
                /* Ignore routes not assigned yet or already removed. */
1476
                if (!route_exists(route))
1,417✔
1477
                        continue;
171✔
1478

1479
                if (only_static) {
1,246✔
1480
                        if (route->source != NETWORK_CONFIG_SOURCE_STATIC)
583✔
1481
                                continue;
413✔
1482
                } else {
1483
                        /* Ignore dynamically assigned routes. */
1484
                        if (!IN_SET(route->source, NETWORK_CONFIG_SOURCE_FOREIGN, NETWORK_CONFIG_SOURCE_STATIC))
663✔
1485
                                continue;
222✔
1486

1487
                        if (route->source == NETWORK_CONFIG_SOURCE_FOREIGN && link->network) {
441✔
1488
                                if (route->protocol == RTPROT_STATIC &&
13✔
1489
                                    FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
7✔
1490
                                        continue;
×
1491

1492
                                if (IN_SET(route->protocol, RTPROT_DHCP, RTPROT_RA, RTPROT_REDIRECT) &&
13✔
1493
                                    FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DYNAMIC))
6✔
1494
                                        continue;
2✔
1495
                        }
1496
                }
1497

1498
                /* When we also mark foreign routes, do not mark routes assigned to other interfaces.
1499
                 * Otherwise, routes assigned to unmanaged interfaces will be dropped.
1500
                 * Note, route_get_link() does not provide assigned link for routes with an unreachable type
1501
                 * or IPv4 multipath routes. So, the current implementation does not support managing such
1502
                 * routes by other daemon or so, unless ManageForeignRoutes=no. */
1503
                if (!only_static) {
609✔
1504
                        Link *route_link;
439✔
1505

1506
                        if (route_get_link(link->manager, route, &route_link) >= 0 && route_link != link)
439✔
1507
                                continue;
280✔
1508
                }
1509

1510
                route_mark(route);
27,881✔
1511
        }
1512

1513
        /* Then, unmark all routes requested by active links. */
1514
        HASHMAP_FOREACH(other, link->manager->links_by_index) {
22,951✔
1515
                if (only_static && other == link)
19,801✔
1516
                        continue;
2,395✔
1517

1518
                if (!IN_SET(other->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
17,406✔
1519
                        continue;
14,998✔
1520

1521
                HASHMAP_FOREACH(route, other->network->routes_by_section) {
2,928✔
1522
                        if (route->source != NETWORK_CONFIG_SOURCE_STATIC)
520✔
1523
                                continue;
21✔
1524

1525
                        if (route->family == AF_INET || ordered_set_isempty(route->nexthops)) {
499✔
1526
                                r = link_unmark_route(other, route, NULL);
493✔
1527
                                if (r < 0)
493✔
1528
                                        return r;
×
1529

1530
                        } else {
1531
                                RouteNextHop *nh;
6✔
1532
                                ORDERED_SET_FOREACH(nh, route->nexthops) {
30✔
1533
                                        r = link_unmark_route(other, route, nh);
24✔
1534
                                        if (r < 0)
24✔
1535
                                                return r;
×
1536
                                }
1537
                        }
1538
                }
1539

1540
                /* Also unmark routes requested in .netdev file. */
1541
                if (other->netdev && other->netdev->kind == NETDEV_KIND_WIREGUARD) {
2,408✔
1542
                        Wireguard *w = WIREGUARD(other->netdev);
18✔
1543

1544
                        SET_FOREACH(route, w->routes) {
306✔
1545
                                r = link_unmark_route(other, route, NULL);
288✔
1546
                                if (r < 0)
288✔
1547
                                        return r;
×
1548
                        }
1549
                }
1550
        }
1551

1552
        /* Finally, remove all marked routes. */
1553
        SET_FOREACH(route, link->manager->routes) {
27,552✔
1554
                if (!route_is_marked(route))
24,402✔
1555
                        continue;
24,202✔
1556

1557
                RET_GATHER(r, route_remove(route, link->manager));
200✔
1558
        }
1559

1560
        return r;
3,150✔
1561
}
1562

1563
void link_forget_routes(Link *link) {
652✔
1564
        assert(link);
652✔
1565
        assert(link->ifindex > 0);
652✔
1566
        assert(!FLAGS_SET(link->flags, IFF_UP));
652✔
1567

1568
        /* When an interface went down, IPv4 non-local routes bound to the interface are silently removed by
1569
         * the kernel, without any notifications. Let's forget them in that case. Otherwise, when the link
1570
         * goes up later, the configuration order of routes may be confused by the nonexistent routes.
1571
         * See issue #35047. */
1572

1573
        Route *route;
652✔
1574
        SET_FOREACH(route, link->manager->routes) {
9,370✔
1575
                // TODO: handle multipath routes
1576
                if (route->nexthop.ifindex != link->ifindex)
8,718✔
1577
                        continue;
5,267✔
1578
                if (route->family != AF_INET)
3,451✔
1579
                        continue;
1,798✔
1580
                // TODO: check RTN_NAT and RTN_XRESOLVE
1581
                if (!IN_SET(route->type, RTN_UNICAST, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
1,653✔
1582
                        continue;
490✔
1583

1584
                route_forget(link->manager, route, "Forgetting silently removed");
1,163✔
1585
        }
1586
}
652✔
1587

1588
int network_add_ipv4ll_route(Network *network) {
6,236✔
1589
        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
6,236✔
1590
        unsigned section_line;
6,236✔
1591
        int r;
6,236✔
1592

1593
        assert(network);
6,236✔
1594

1595
        if (!network->ipv4ll_route)
6,236✔
1596
                return 0;
1597

1598
        r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
6✔
1599
        if (r < 0)
6✔
1600
                return r;
1601

1602
        /* IPv4LLRoute= is in [Network] section. */
1603
        r = route_new_static(network, network->filename, section_line, &route);
6✔
1604
        if (r < 0)
6✔
1605
                return r;
1606

1607
        r = in_addr_from_string(AF_INET, "169.254.0.0", &route->dst);
6✔
1608
        if (r < 0)
6✔
1609
                return r;
1610

1611
        route->family = AF_INET;
6✔
1612
        route->dst_prefixlen = 16;
6✔
1613
        route->scope = RT_SCOPE_LINK;
6✔
1614
        route->scope_set = true;
6✔
1615
        route->table_set = true;
6✔
1616
        route->priority = IPV4LL_ROUTE_METRIC;
6✔
1617
        route->protocol = RTPROT_STATIC;
6✔
1618

1619
        TAKE_PTR(route);
6✔
1620
        return 0;
6✔
1621
}
1622

1623
int network_add_default_route_on_device(Network *network) {
6,236✔
1624
        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
6,236✔
1625
        unsigned section_line;
6,236✔
1626
        int r;
6,236✔
1627

1628
        assert(network);
6,236✔
1629

1630
        if (!network->default_route_on_device)
6,236✔
1631
                return 0;
1632

1633
        r = hashmap_by_section_find_unused_line(network->routes_by_section, network->filename, &section_line);
6✔
1634
        if (r < 0)
6✔
1635
                return r;
1636

1637
        /* DefaultRouteOnDevice= is in [Network] section. */
1638
        r = route_new_static(network, network->filename, section_line, &route);
6✔
1639
        if (r < 0)
6✔
1640
                return r;
1641

1642
        route->family = AF_INET;
6✔
1643
        route->scope = RT_SCOPE_LINK;
6✔
1644
        route->scope_set = true;
6✔
1645
        route->protocol = RTPROT_STATIC;
6✔
1646

1647
        TAKE_PTR(route);
6✔
1648
        return 0;
6✔
1649
}
1650

1651
static int config_parse_preferred_src(
3✔
1652
                const char *unit,
1653
                const char *filename,
1654
                unsigned line,
1655
                const char *section,
1656
                unsigned section_line,
1657
                const char *lvalue,
1658
                int ltype,
1659
                const char *rvalue,
1660
                void *data,
1661
                void *userdata) {
1662

1663
        Route *route = ASSERT_PTR(userdata);
3✔
1664
        int r;
3✔
1665

1666
        if (isempty(rvalue)) {
3✔
1667
                route->prefsrc_set = false;
×
1668
                route->prefsrc = IN_ADDR_NULL;
×
1669
                return 1;
×
1670
        }
1671

1672
        r = parse_boolean(rvalue);
3✔
1673
        if (r == 0) {
3✔
1674
                /* Accepts only no. That prohibits prefsrc set by DHCP lease. */
1675
                route->prefsrc_set = true;
×
1676
                route->prefsrc = IN_ADDR_NULL;
×
1677
                return 1;
×
1678
        }
1679

1680
        if (route->family == AF_UNSPEC)
3✔
1681
                r = in_addr_from_string_auto(rvalue, &route->family, &route->prefsrc);
×
1682
        else
1683
                r = in_addr_from_string(route->family, rvalue, &route->prefsrc);
3✔
1684
        if (r < 0)
3✔
1685
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1686

1687
        route->prefsrc_set = true;
3✔
1688
        return 1;
3✔
1689
}
1690

1691
static int config_parse_route_destination(
228✔
1692
                const char *unit,
1693
                const char *filename,
1694
                unsigned line,
1695
                const char *section,
1696
                unsigned section_line,
1697
                const char *lvalue,
1698
                int ltype,
1699
                const char *rvalue,
1700
                void *data,
1701
                void *userdata) {
1702

1703
        Route *route = ASSERT_PTR(userdata);
228✔
1704
        union in_addr_union *buffer;
228✔
1705
        unsigned char *prefixlen;
228✔
1706
        int r;
228✔
1707

1708
        assert(lvalue);
228✔
1709
        assert(rvalue);
228✔
1710

1711
        if (streq(lvalue, "Destination")) {
228✔
1712
                buffer = &route->dst;
228✔
1713
                prefixlen = &route->dst_prefixlen;
228✔
1714
        } else if (streq(lvalue, "Source")) {
×
1715
                buffer = &route->src;
×
1716
                prefixlen = &route->src_prefixlen;
×
1717
        } else
1718
                assert_not_reached();
×
1719

1720
        if (route->family == AF_UNSPEC)
228✔
1721
                r = in_addr_prefix_from_string_auto(rvalue, &route->family, buffer, prefixlen);
228✔
1722
        else
1723
                r = in_addr_prefix_from_string(rvalue, route->family, buffer, prefixlen);
×
1724
        if (r < 0)
228✔
1725
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1726

1727
        (void) in_addr_mask(route->family, buffer, *prefixlen);
228✔
1728
        return 1;
228✔
1729
}
1730

1731
static int config_parse_route_priority(
4✔
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
                void *userdata) {
1742

1743
        Route *route = ASSERT_PTR(userdata);
4✔
1744
        int r;
4✔
1745

1746
        assert(rvalue);
4✔
1747

1748
        r = safe_atou32(rvalue, &route->priority);
4✔
1749
        if (r < 0)
4✔
1750
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1751

1752
        route->priority_set = true;
4✔
1753
        return 1;
4✔
1754
}
1755

1756
static int config_parse_route_scope(
2✔
1757
                const char *unit,
1758
                const char *filename,
1759
                unsigned line,
1760
                const char *section,
1761
                unsigned section_line,
1762
                const char *lvalue,
1763
                int ltype,
1764
                const char *rvalue,
1765
                void *data,
1766
                void *userdata) {
1767

1768
        Route *route = ASSERT_PTR(userdata);
2✔
1769
        int r;
2✔
1770

1771
        assert(rvalue);
2✔
1772

1773
        r = route_scope_from_string(rvalue);
2✔
1774
        if (r < 0)
2✔
1775
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1776

1777
        route->scope = r;
2✔
1778
        route->scope_set = true;
2✔
1779
        return 1;
2✔
1780
}
1781

1782
static int config_parse_route_table(
2✔
1783
                const char *unit,
1784
                const char *filename,
1785
                unsigned line,
1786
                const char *section,
1787
                unsigned section_line,
1788
                const char *lvalue,
1789
                int ltype,
1790
                const char *rvalue,
1791
                void *data,
1792
                void *userdata) {
1793

1794
        Route *route = ASSERT_PTR(userdata);
2✔
1795
        Manager *manager = ASSERT_PTR(ASSERT_PTR(route->network)->manager);
2✔
1796
        int r;
2✔
1797

1798
        assert(rvalue);
2✔
1799

1800
        r = manager_get_route_table_from_string(manager, rvalue, &route->table);
2✔
1801
        if (r < 0)
2✔
1802
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1803

1804
        route->table_set = true;
2✔
1805
        return 1;
2✔
1806
}
1807

1808
static int config_parse_route_preference(
×
1809
                const char *unit,
1810
                const char *filename,
1811
                unsigned line,
1812
                const char *section,
1813
                unsigned section_line,
1814
                const char *lvalue,
1815
                int ltype,
1816
                const char *rvalue,
1817
                void *data,
1818
                void *userdata) {
1819

1820
        Route *route = ASSERT_PTR(userdata);
×
1821

1822
        assert(rvalue);
×
1823

1824
        if (streq(rvalue, "low"))
×
1825
                route->pref = SD_NDISC_PREFERENCE_LOW;
×
1826
        else if (streq(rvalue, "medium"))
×
1827
                route->pref = SD_NDISC_PREFERENCE_MEDIUM;
×
1828
        else if (streq(rvalue, "high"))
×
1829
                route->pref = SD_NDISC_PREFERENCE_HIGH;
×
1830
        else
1831
                return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
×
1832

1833
        route->pref_set = true;
×
1834
        return 1;
×
1835
}
1836

1837
static int config_parse_route_protocol(
×
1838
                const char *unit,
1839
                const char *filename,
1840
                unsigned line,
1841
                const char *section,
1842
                unsigned section_line,
1843
                const char *lvalue,
1844
                int ltype,
1845
                const char *rvalue,
1846
                void *data,
1847
                void *userdata) {
1848

1849
        unsigned char *p = ASSERT_PTR(data);
×
1850
        int r;
×
1851

1852
        assert(rvalue);
×
1853

1854
        r = route_protocol_from_string(rvalue);
×
1855
        if (r < 0)
×
1856
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1857

1858
        *p = (unsigned char) r;
×
1859
        return 1;
×
1860
}
1861

1862
static int config_parse_route_type(
60✔
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
                void *userdata) {
1873

1874
        unsigned char *p = ASSERT_PTR(data);
60✔
1875
        int r;
60✔
1876

1877
        assert(rvalue);
60✔
1878

1879
        r = route_type_from_string(rvalue);
60✔
1880
        if (r < 0)
60✔
1881
                return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
×
1882

1883
        *p = (unsigned char) r;
60✔
1884
        return 1;
60✔
1885
}
1886

1887
int config_parse_route_section(
579✔
1888
                const char *unit,
1889
                const char *filename,
1890
                unsigned line,
1891
                const char *section,
1892
                unsigned section_line,
1893
                const char *lvalue,
1894
                int ltype,
1895
                const char *rvalue,
1896
                void *data,
1897
                void *userdata) {
1898

1899
        static const ConfigSectionParser table[_ROUTE_CONF_PARSER_MAX] = {
579✔
1900
                [ROUTE_DESTINATION]               = { .parser = config_parse_route_destination,      .ltype = 0,                       .offset = 0,                                                   },
1901
                [ROUTE_PREFERRED_SOURCE]          = { .parser = config_parse_preferred_src,          .ltype = 0,                       .offset = 0,                                                   },
1902
                [ROUTE_PRIORITY]                  = { .parser = config_parse_route_priority,         .ltype = 0,                       .offset = 0,                                                   },
1903
                [ROUTE_SCOPE]                     = { .parser = config_parse_route_scope,            .ltype = 0,                       .offset = 0,                                                   },
1904
                [ROUTE_TABLE]                     = { .parser = config_parse_route_table,            .ltype = 0,                       .offset = 0,                                                   },
1905
                [ROUTE_PREFERENCE]                = { .parser = config_parse_route_preference,       .ltype = 0,                       .offset = 0,                                                   },
1906
                [ROUTE_PROTOCOL]                  = { .parser = config_parse_route_protocol,         .ltype = 0,                       .offset = offsetof(Route, protocol),                           },
1907
                [ROUTE_TYPE]                      = { .parser = config_parse_route_type,             .ltype = 0,                       .offset = offsetof(Route, type),                               },
1908
                [ROUTE_GATEWAY_NETWORK]           = { .parser = config_parse_gateway,                .ltype = 0,                       .offset = 0,                                                   },
1909
                [ROUTE_GATEWAY]                   = { .parser = config_parse_gateway,                .ltype = 1,                       .offset = 0,                                                   },
1910
                [ROUTE_GATEWAY_ONLINK]            = { .parser = config_parse_tristate,               .ltype = 0,                       .offset = offsetof(Route, gateway_onlink),                     },
1911
                [ROUTE_MULTIPATH]                 = { .parser = config_parse_multipath_route,        .ltype = 0,                       .offset = offsetof(Route, nexthops),                           },
1912
                [ROUTE_NEXTHOP]                   = { .parser = config_parse_route_nexthop,          .ltype = 0,                       .offset = offsetof(Route, nexthop_id),                         },
1913
                [ROUTE_METRIC_MTU]                = { .parser = config_parse_route_metric,           .ltype = RTAX_MTU,                .offset = 0,                                                   },
1914
                [ROUTE_METRIC_ADVMSS]             = { .parser = config_parse_route_metric,           .ltype = RTAX_ADVMSS,             .offset = 0,                                                   },
1915
                [ROUTE_METRIC_HOPLIMIT]           = { .parser = config_parse_route_metric,           .ltype = RTAX_HOPLIMIT,           .offset = 0,                                                   },
1916
                [ROUTE_METRIC_INITCWND]           = { .parser = config_parse_route_metric,           .ltype = RTAX_INITCWND,           .offset = 0,                                                   },
1917
                [ROUTE_METRIC_RTO_MIN]            = { .parser = config_parse_route_metric,           .ltype = RTAX_RTO_MIN,            .offset = 0,                                                   },
1918
                [ROUTE_METRIC_INITRWND]           = { .parser = config_parse_route_metric,           .ltype = RTAX_INITRWND,           .offset = 0,                                                   },
1919
                [ROUTE_METRIC_QUICKACK]           = { .parser = config_parse_route_metric,           .ltype = RTAX_QUICKACK,           .offset = 0,                                                   },
1920
                [ROUTE_METRIC_CC_ALGO]            = { .parser = config_parse_string,                 .ltype = 0,                       .offset = offsetof(Route, metric.tcp_congestion_control_algo), },
1921
                [ROUTE_METRIC_FASTOPEN_NO_COOKIE] = { .parser = config_parse_route_metric,           .ltype = RTAX_FASTOPEN_NO_COOKIE, .offset = 0,                                                   },
1922
        };
1923

1924
        _cleanup_(route_unref_or_set_invalidp) Route *route = NULL;
579✔
1925
        Network *network = ASSERT_PTR(userdata);
579✔
1926
        int r;
579✔
1927

1928
        assert(filename);
579✔
1929

1930
        if (streq(section, "Network")) {
579✔
1931
                assert(streq_ptr(lvalue, "Gateway"));
61✔
1932

1933
                /* we are not in an Route section, so use line number instead */
1934
                r = route_new_static(network, filename, line, &route);
61✔
1935
        } else
1936
                r = route_new_static(network, filename, section_line, &route);
518✔
1937
        if (r == -ENOMEM)
579✔
1938
                return log_oom();
×
1939
        if (r < 0) {
579✔
1940
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
1941
                           "Failed to allocate route, ignoring assignment: %m");
1942
                return 0;
×
1943
        }
1944

1945
        r = config_section_parse(table, ELEMENTSOF(table),
579✔
1946
                                 unit, filename, line, section, section_line, lvalue, ltype, rvalue, route);
1947
        if (r <= 0)
579✔
1948
                return r;
1949

1950
        TAKE_PTR(route);
579✔
1951
        return 0;
579✔
1952
}
1953

1954
int route_section_verify(Route *route) {
424✔
1955
        int r;
424✔
1956

1957
        assert(route);
424✔
1958
        assert(route->section);
424✔
1959

1960
        if (section_is_invalid(route->section))
424✔
1961
                return -EINVAL;
1962

1963
        /* Currently, we do not support static route with finite lifetime. */
1964
        assert(route->lifetime_usec == USEC_INFINITY);
424✔
1965

1966
        r = route_section_verify_nexthops(route);
424✔
1967
        if (r < 0)
424✔
1968
                return r;
1969

1970
        /* table */
1971
        if (!route->table_set && route->network && route->network->vrf) {
424✔
1972
                route->table = VRF(route->network->vrf)->table;
1✔
1973
                route->table_set = true;
1✔
1974
        }
1975

1976
        if (!route->table_set && IN_SET(route->type, RTN_LOCAL, RTN_BROADCAST, RTN_ANYCAST, RTN_NAT))
424✔
1977
                route->table = RT_TABLE_LOCAL;
18✔
1978

1979
        /* scope */
1980
        if (!route->scope_set && route->family == AF_INET) {
424✔
1981
                if (IN_SET(route->type, RTN_LOCAL, RTN_NAT))
224✔
1982
                        route->scope = RT_SCOPE_HOST;
6✔
1983
                else if (IN_SET(route->type, RTN_BROADCAST, RTN_ANYCAST, RTN_MULTICAST))
218✔
1984
                        route->scope = RT_SCOPE_LINK;
18✔
1985
                else if (IN_SET(route->type, RTN_UNICAST, RTN_UNSPEC) &&
200✔
1986
                         !route->gateway_from_dhcp_or_ra &&
182✔
1987
                         !in_addr_is_set(route->nexthop.family, &route->nexthop.gw) &&
178✔
1988
                         ordered_set_isempty(route->nexthops) &&
96✔
1989
                         route->nexthop_id == 0)
84✔
1990
                        route->scope = RT_SCOPE_LINK;
42✔
1991
        }
1992

1993
        /* IPv6 route */
1994
        if (route->family == AF_INET6) {
424✔
1995
                if (route->scope != RT_SCOPE_UNIVERSE) {
188✔
1996
                        log_section_warning(route->section, "Scope= is specified for IPv6 route. It will be ignored.");
2✔
1997
                        route->scope = RT_SCOPE_UNIVERSE;
2✔
1998
                }
1999

2000
                if (route->priority == 0)
188✔
2001
                        route->priority = IP6_RT_PRIO_USER;
90✔
2002
        }
2003

2004
        return 0;
2005
}
2006

2007
void network_drop_invalid_routes(Network *network) {
5,303✔
2008
        Route *route;
5,303✔
2009

2010
        assert(network);
5,303✔
2011

2012
        HASHMAP_FOREACH(route, network->routes_by_section)
10,934✔
2013
                if (route_section_verify(route) < 0)
328✔
2014
                        route_detach(route);
×
2015
}
5,303✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc