]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-routing-policy-rule.c
test-network: suppress logs in status command
[thirdparty/systemd.git] / src / network / networkd-routing-policy-rule.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
bce67bbe
SS
2
3#include <net/if.h>
4#include <linux/fib_rules.h>
5
43e08c78 6#include "af-list.h"
bce67bbe
SS
7#include "alloc-util.h"
8#include "conf-parser.h"
9#include "fileio.h"
da96ad5a 10#include "ip-protocol-list.h"
bce67bbe
SS
11#include "networkd-routing-policy-rule.h"
12#include "netlink-util.h"
13#include "networkd-manager.h"
f6c6ff97 14#include "networkd-util.h"
bce67bbe
SS
15#include "parse-util.h"
16#include "socket-util.h"
17#include "string-util.h"
51517f9e 18#include "strv.h"
bce67bbe
SS
19
20int routing_policy_rule_new(RoutingPolicyRule **ret) {
21 RoutingPolicyRule *rule;
22
9d66b48c 23 rule = new(RoutingPolicyRule, 1);
bce67bbe
SS
24 if (!rule)
25 return -ENOMEM;
26
9d66b48c 27 *rule = (RoutingPolicyRule) {
9d66b48c
YW
28 .table = RT_TABLE_MAIN,
29 };
bce67bbe
SS
30
31 *ret = rule;
32 return 0;
33}
34
35void routing_policy_rule_free(RoutingPolicyRule *rule) {
36
37 if (!rule)
38 return;
39
40 if (rule->network) {
41 LIST_REMOVE(rules, rule->network->rules, rule);
42 assert(rule->network->n_rules > 0);
43 rule->network->n_rules--;
44
0f7f2769 45 if (rule->section)
bce67bbe 46 hashmap_remove(rule->network->rules_by_section, rule->section);
36e6e28b
SS
47 }
48
6964cf45 49 if (rule->manager) {
9ee92e7e
YW
50 if (set_get(rule->manager->rules, rule) == rule)
51 set_remove(rule->manager->rules, rule);
52 if (set_get(rule->manager->rules_foreign, rule) == rule)
53 set_remove(rule->manager->rules_foreign, rule);
bce67bbe
SS
54 }
55
0f7f2769 56 network_config_section_free(rule->section);
762e2659
SS
57 free(rule->iif);
58 free(rule->oif);
bce67bbe
SS
59 free(rule);
60}
61
01fc8e4f
YW
62static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) {
63 _cleanup_free_ char *iif = NULL, *oif = NULL;
64
65 assert(dest);
66 assert(src);
67
68 if (src->iif) {
69 iif = strdup(src->iif);
70 if (!iif)
71 return -ENOMEM;
72 }
73
74 if (src->oif) {
75 oif = strdup(src->oif);
76 if (!oif)
77 return -ENOMEM;
78 }
79
80 dest->family = src->family;
81 dest->from = src->from;
82 dest->from_prefixlen = src->from_prefixlen;
83 dest->to = src->to;
84 dest->to_prefixlen = src->to_prefixlen;
85 dest->invert_rule = src->invert_rule;
86 dest->tos = src->tos;
87 dest->fwmark = src->fwmark;
88 dest->fwmask = src->fwmask;
89 dest->priority = src->priority;
90 dest->table = src->table;
91 dest->iif = TAKE_PTR(iif);
92 dest->oif = TAKE_PTR(oif);
93 dest->protocol = src->protocol;
94 dest->sport = src->sport;
95 dest->dport = src->dport;
96
97 return 0;
98}
99
7a08d314 100static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash *state) {
bce67bbe
SS
101 assert(rule);
102
103 siphash24_compress(&rule->family, sizeof(rule->family), state);
104
105 switch (rule->family) {
106 case AF_INET:
107 case AF_INET6:
bce67bbe
SS
108 siphash24_compress(&rule->from, FAMILY_ADDRESS_SIZE(rule->family), state);
109 siphash24_compress(&rule->from_prefixlen, sizeof(rule->from_prefixlen), state);
110
111 siphash24_compress(&rule->to, FAMILY_ADDRESS_SIZE(rule->family), state);
112 siphash24_compress(&rule->to_prefixlen, sizeof(rule->to_prefixlen), state);
113
b80a511b
YW
114 siphash24_compress_boolean(rule->invert_rule, state);
115
bce67bbe
SS
116 siphash24_compress(&rule->tos, sizeof(rule->tos), state);
117 siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state);
b80a511b
YW
118 siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state);
119 siphash24_compress(&rule->priority, sizeof(rule->priority), state);
bce67bbe
SS
120 siphash24_compress(&rule->table, sizeof(rule->table), state);
121
926062f0
SS
122 siphash24_compress(&rule->protocol, sizeof(rule->protocol), state);
123 siphash24_compress(&rule->sport, sizeof(rule->sport), state);
124 siphash24_compress(&rule->dport, sizeof(rule->dport), state);
125
762e2659 126 if (rule->iif)
0d7febd0 127 siphash24_compress(rule->iif, strlen(rule->iif), state);
762e2659
SS
128
129 if (rule->oif)
0d7febd0 130 siphash24_compress(rule->oif, strlen(rule->oif), state);
762e2659 131
bce67bbe
SS
132 break;
133 default:
134 /* treat any other address family as AF_UNSPEC */
135 break;
136 }
137}
138
7a08d314 139static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const RoutingPolicyRule *b) {
bce67bbe
SS
140 int r;
141
a0edd02e
FB
142 r = CMP(a->family, b->family);
143 if (r != 0)
144 return r;
bce67bbe
SS
145
146 switch (a->family) {
147 case AF_INET:
148 case AF_INET6:
a0edd02e
FB
149 r = CMP(a->from_prefixlen, b->from_prefixlen);
150 if (r != 0)
151 return r;
152
67e05dd8
ZJS
153 r = memcmp(&a->from, &b->from, FAMILY_ADDRESS_SIZE(a->family));
154 if (r != 0)
155 return r;
156
a0edd02e
FB
157 r = CMP(a->to_prefixlen, b->to_prefixlen);
158 if (r != 0)
159 return r;
160
67e05dd8
ZJS
161 r = memcmp(&a->to, &b->to, FAMILY_ADDRESS_SIZE(a->family));
162 if (r != 0)
163 return r;
164
b80a511b
YW
165 r = CMP(a->invert_rule, b->invert_rule);
166 if (r != 0)
167 return r;
168
a0edd02e
FB
169 r = CMP(a->tos, b->tos);
170 if (r != 0)
171 return r;
172
b80a511b
YW
173 r = CMP(a->fwmark, b->fwmark);
174 if (r != 0)
175 return r;
176
a0edd02e
FB
177 r = CMP(a->fwmask, b->fwmask);
178 if (r != 0)
179 return r;
180
b80a511b
YW
181 r = CMP(a->priority, b->priority);
182 if (r != 0)
183 return r;
184
a0edd02e
FB
185 r = CMP(a->table, b->table);
186 if (r != 0)
187 return r;
bce67bbe 188
926062f0
SS
189 r = CMP(a->protocol, b->protocol);
190 if (r != 0)
191 return r;
192
193 r = memcmp(&a->sport, &b->sport, sizeof(a->sport));
194 if (r != 0)
195 return r;
196
197 r = memcmp(&a->dport, &b->dport, sizeof(a->dport));
198 if (r != 0)
199 return r;
200
67e05dd8 201 r = strcmp_ptr(a->iif, b->iif);
314ed4f9 202 if (r != 0)
bce67bbe
SS
203 return r;
204
67e05dd8 205 r = strcmp_ptr(a->oif, b->oif);
314ed4f9 206 if (r != 0)
67e05dd8 207 return r;
bce67bbe 208
67e05dd8 209 return 0;
bce67bbe
SS
210 default:
211 /* treat any other address family as AF_UNSPEC */
212 return 0;
213 }
214}
215
7a08d314 216DEFINE_PRIVATE_HASH_OPS(routing_policy_rule_hash_ops, RoutingPolicyRule, routing_policy_rule_hash_func, routing_policy_rule_compare_func);
bce67bbe 217
b80a511b 218int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
bce67bbe 219
b80a511b 220 RoutingPolicyRule *existing;
bce67bbe 221
b80a511b 222 assert(m);
bce67bbe 223
b80a511b 224 existing = set_get(m->rules, rule);
b87dadcd
ZJS
225 if (existing) {
226 if (ret)
227 *ret = existing;
228 return 1;
bce67bbe
SS
229 }
230
b80a511b 231 existing = set_get(m->rules_foreign, rule);
b87dadcd
ZJS
232 if (existing) {
233 if (ret)
234 *ret = existing;
e6b65ab7 235 return 0;
bce67bbe
SS
236 }
237
238 return -ENOENT;
239}
240
241int routing_policy_rule_make_local(Manager *m, RoutingPolicyRule *rule) {
242 int r;
243
244 assert(m);
245
246 if (set_contains(m->rules_foreign, rule)) {
247 set_remove(m->rules_foreign, rule);
248
249 r = set_ensure_allocated(&m->rules, &routing_policy_rule_hash_ops);
250 if (r < 0)
251 return r;
252
75a302b5
YW
253 r = set_put(m->rules, rule);
254 if (r < 0)
255 return r;
256 if (r == 0)
257 routing_policy_rule_free(rule);
bce67bbe
SS
258 }
259
260 return -ENOENT;
261}
262
b80a511b 263static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, RoutingPolicyRule **ret) {
8e766630 264 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
bce67bbe
SS
265 int r;
266
b80a511b
YW
267 assert(m);
268 assert(rules);
269 assert(in);
bce67bbe
SS
270
271 r = routing_policy_rule_new(&rule);
272 if (r < 0)
273 return r;
274
6964cf45 275 rule->manager = m;
01fc8e4f
YW
276
277 r = routing_policy_rule_copy(rule, in);
278 if (r < 0)
279 return r;
bce67bbe
SS
280
281 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
282 if (r < 0)
283 return r;
284
285 r = set_put(*rules, rule);
286 if (r < 0)
287 return r;
75a302b5
YW
288 if (r == 0)
289 return -EEXIST;
bce67bbe
SS
290
291 if (ret)
292 *ret = rule;
293
d26267dd 294 TAKE_PTR(rule);
bce67bbe
SS
295 return 0;
296}
297
b80a511b
YW
298static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
299 return routing_policy_rule_add_internal(m, &m->rules, rule, ret);
bce67bbe
SS
300}
301
b80a511b
YW
302int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) {
303 return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, ret);
bce67bbe
SS
304}
305
302a796f 306static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
bce67bbe
SS
307 int r;
308
309 assert(m);
310 assert(link);
311 assert(link->ifname);
312
7715629e 313 link->routing_policy_rule_remove_messages--;
bce67bbe
SS
314
315 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
316 return 1;
317
318 r = sd_netlink_message_get_errno(m);
319 if (r < 0)
5ecb131d 320 log_link_message_warning_errno(link, m, r, "Could not drop routing policy rule");
bce67bbe
SS
321
322 return 1;
323}
324
302a796f 325int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback) {
bce67bbe
SS
326 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
327 int r;
328
329 assert(routing_policy_rule);
330 assert(link);
331 assert(link->manager);
332 assert(link->manager->rtnl);
333 assert(link->ifindex > 0);
334 assert(IN_SET(routing_policy_rule->family, AF_INET, AF_INET6));
335
336 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, routing_policy_rule->family);
337 if (r < 0)
338 return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
339
d40b01e4 340 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
43409486 341 r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
bce67bbe
SS
342 if (r < 0)
343 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
344
345 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, routing_policy_rule->from_prefixlen);
346 if (r < 0)
347 return log_error_errno(r, "Could not set source prefix length: %m");
348 }
349
d40b01e4 350 if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
43409486 351 r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
bce67bbe
SS
352 if (r < 0)
353 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
354
355 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, routing_policy_rule->to_prefixlen);
356 if (r < 0)
357 return log_error_errno(r, "Could not set destination prefix length: %m");
358 }
359
302a796f
YW
360 r = netlink_call_async(link->manager->rtnl, NULL, m,
361 callback ?: routing_policy_rule_remove_handler,
362 link_netlink_destroy_callback, link);
bce67bbe
SS
363 if (r < 0)
364 return log_error_errno(r, "Could not send rtnetlink message: %m");
365
366 link_ref(link);
367
368 return 0;
369}
370
371static int routing_policy_rule_new_static(Network *network, const char *filename, unsigned section_line, RoutingPolicyRule **ret) {
8e766630
LP
372 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
373 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
bce67bbe
SS
374 int r;
375
376 assert(network);
377 assert(ret);
378 assert(!!filename == (section_line > 0));
379
0f7f2769
YW
380 if (filename) {
381 r = network_config_section_new(filename, section_line, &n);
382 if (r < 0)
383 return r;
bce67bbe 384
0f7f2769
YW
385 rule = hashmap_get(network->rules_by_section, n);
386 if (rule) {
387 *ret = TAKE_PTR(rule);
bce67bbe 388
0f7f2769
YW
389 return 0;
390 }
bce67bbe
SS
391 }
392
393 r = routing_policy_rule_new(&rule);
394 if (r < 0)
395 return r;
396
bce67bbe 397 rule->network = network;
bce67bbe
SS
398 LIST_APPEND(rules, network->rules, rule);
399 network->n_rules++;
400
0f7f2769
YW
401 if (filename) {
402 rule->section = TAKE_PTR(n);
403
3e570042
YW
404 r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops);
405 if (r < 0)
406 return r;
407
0f7f2769
YW
408 r = hashmap_put(network->rules_by_section, rule->section, rule);
409 if (r < 0)
410 return r;
411 }
412
1cc6c93a 413 *ret = TAKE_PTR(rule);
bce67bbe
SS
414
415 return 0;
416}
417
302a796f 418static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
bce67bbe
SS
419 int r;
420
421 assert(rtnl);
422 assert(m);
423 assert(link);
424 assert(link->ifname);
7715629e 425 assert(link->routing_policy_rule_messages > 0);
bce67bbe 426
7715629e 427 link->routing_policy_rule_messages--;
bce67bbe
SS
428
429 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
430 return 1;
431
432 r = sd_netlink_message_get_errno(m);
4ff296b0 433 if (r < 0 && r != -EEXIST) {
5ecb131d 434 log_link_message_warning_errno(link, m, r, "Could not add routing policy rule");
4ff296b0
YW
435 link_enter_failed(link);
436 return 1;
437 }
bce67bbe 438
7715629e 439 if (link->routing_policy_rule_messages == 0) {
bce67bbe 440 log_link_debug(link, "Routing policy rule configured");
7715629e
ST
441 link->routing_policy_rules_configured = true;
442 link_check_ready(link);
443 }
bce67bbe
SS
444
445 return 1;
446}
447
9f08a578 448int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netlink_message_handler_t callback) {
bce67bbe
SS
449 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
450 int r;
451
452 assert(rule);
453 assert(link);
454 assert(link->ifindex > 0);
455 assert(link->manager);
456 assert(link->manager->rtnl);
457
15201512
YW
458 if (DEBUG_LOGGING) {
459 _cleanup_free_ char *from = NULL, *to = NULL;
460
461 (void) in_addr_to_string(rule->family, &rule->from, &from);
462 (void) in_addr_to_string(rule->family, &rule->to, &to);
463
464 log_debug("Configuring routing policy rule: %s/%u -> %s/%u, iif: %s, oif: %s, table: %u",
465 from, rule->from_prefixlen, to, rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table);
466 }
467
bce67bbe
SS
468 r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, rule->family);
469 if (r < 0)
470 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
471
d40b01e4 472 if (in_addr_is_null(rule->family, &rule->from) == 0) {
43409486 473 r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
bce67bbe
SS
474 if (r < 0)
475 return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
476
477 r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen);
478 if (r < 0)
479 return log_error_errno(r, "Could not set source prefix length: %m");
480 }
481
d40b01e4 482 if (in_addr_is_null(rule->family, &rule->to) == 0) {
43409486 483 r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
bce67bbe
SS
484 if (r < 0)
485 return log_error_errno(r, "Could not append FRA_DST attribute: %m");
486
487 r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen);
488 if (r < 0)
489 return log_error_errno(r, "Could not set destination prefix length: %m");
490 }
491
492 r = sd_netlink_message_append_u32(m, FRA_PRIORITY, rule->priority);
493 if (r < 0)
494 return log_error_errno(r, "Could not append FRA_PRIORITY attribute: %m");
495
496 if (rule->tos > 0) {
497 r = sd_rtnl_message_routing_policy_rule_set_tos(m, rule->tos);
498 if (r < 0)
499 return log_error_errno(r, "Could not set ip rule tos: %m");
500 }
501
502 if (rule->table < 256) {
503 r = sd_rtnl_message_routing_policy_rule_set_table(m, rule->table);
504 if (r < 0)
505 return log_error_errno(r, "Could not set ip rule table: %m");
506 } else {
507 r = sd_rtnl_message_routing_policy_rule_set_table(m, RT_TABLE_UNSPEC);
508 if (r < 0)
509 return log_error_errno(r, "Could not set ip rule table: %m");
510
511 r = sd_netlink_message_append_u32(m, FRA_TABLE, rule->table);
512 if (r < 0)
513 return log_error_errno(r, "Could not append FRA_TABLE attribute: %m");
514 }
515
516 if (rule->fwmark > 0) {
517 r = sd_netlink_message_append_u32(m, FRA_FWMARK, rule->fwmark);
518 if (r < 0)
519 return log_error_errno(r, "Could not append FRA_FWMARK attribute: %m");
520 }
521
522 if (rule->fwmask > 0) {
523 r = sd_netlink_message_append_u32(m, FRA_FWMASK, rule->fwmask);
524 if (r < 0)
525 return log_error_errno(r, "Could not append FRA_FWMASK attribute: %m");
526 }
527
762e2659
SS
528 if (rule->iif) {
529 r = sd_netlink_message_append_string(m, FRA_IFNAME, rule->iif);
530 if (r < 0)
531 return log_error_errno(r, "Could not append FRA_IFNAME attribute: %m");
532 }
533
534 if (rule->oif) {
535 r = sd_netlink_message_append_string(m, FRA_OIFNAME, rule->oif);
536 if (r < 0)
537 return log_error_errno(r, "Could not append FRA_OIFNAME attribute: %m");
538 }
539
926062f0
SS
540 r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol);
541 if (r < 0)
542 return log_error_errno(r, "Could not append FRA_IP_PROTO attribute: %m");
543
544 if (rule->sport.start != 0 || rule->sport.end != 0) {
545 r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport));
546 if (r < 0)
547 return log_error_errno(r, "Could not append FRA_SPORT_RANGE attribute: %m");
548 }
549
550 if (rule->dport.start != 0 || rule->dport.end != 0) {
551 r = sd_netlink_message_append_data(m, FRA_DPORT_RANGE, &rule->dport, sizeof(rule->dport));
552 if (r < 0)
553 return log_error_errno(r, "Could not append FRA_DPORT_RANGE attribute: %m");
554 }
555
8b220643
SS
556 if (rule->invert_rule) {
557 r = sd_rtnl_message_routing_policy_rule_set_flags(m, FIB_RULE_INVERT);
558 if (r < 0)
559 return log_error_errno(r, "Could not append FIB_RULE_INVERT attribute: %m");
560 }
561
bce67bbe
SS
562 rule->link = link;
563
302a796f
YW
564 r = netlink_call_async(link->manager->rtnl, NULL, m,
565 callback ?: routing_policy_rule_handler,
566 link_netlink_destroy_callback, link);
bce67bbe
SS
567 if (r < 0)
568 return log_error_errno(r, "Could not send rtnetlink message: %m");
569
570 link_ref(link);
571
b80a511b 572 r = routing_policy_rule_add(link->manager, rule, NULL);
bce67bbe 573 if (r < 0)
cb700a11 574 return log_error_errno(r, "Could not add rule: %m");
bce67bbe 575
7ef7e550 576 return 1;
bce67bbe
SS
577}
578
0aabccc8 579int routing_policy_rule_section_verify(RoutingPolicyRule *rule) {
f6c6ff97
YW
580 int r;
581
0aabccc8
YW
582 if (section_is_invalid(rule->section))
583 return -EINVAL;
584
f6c6ff97
YW
585 if ((rule->family == AF_INET && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6)) ||
586 (rule->family == AF_INET6 && FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4)))
587 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
588 "%s: address family specified by Family= conflicts with the address "
589 "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.",
590 rule->section->filename, rule->section->line);
591
592 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6)) {
593 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule6 = NULL;
594
595 assert(rule->family == AF_UNSPEC);
596
597 /* When Family=both, we need to copy the section, AF_INET and AF_INET6. */
598
599 r = routing_policy_rule_new_static(rule->network, NULL, 0, &rule6);
600 if (r < 0)
601 return r;
602
603 r = routing_policy_rule_copy(rule6, rule);
604 if (r < 0)
605 return r;
606
0aabccc8 607 rule->family = AF_INET;
f6c6ff97
YW
608 rule6->family = AF_INET6;
609
610 TAKE_PTR(rule6);
611 }
612
613 if (rule->family == AF_UNSPEC) {
614 if (FLAGS_SET(rule->address_family, ADDRESS_FAMILY_IPV6))
615 rule->family = AF_INET6;
616 else
617 rule->family = AF_INET;
618 }
0aabccc8
YW
619
620 return 0;
621}
622
bce67bbe
SS
623static int parse_fwmark_fwmask(const char *s, uint32_t *fwmark, uint32_t *fwmask) {
624 _cleanup_free_ char *f = NULL;
625 char *p;
626 int r;
627
628 assert(s);
629
630 f = strdup(s);
631 if (!f)
632 return -ENOMEM;
633
634 p = strchr(f, '/');
635 if (p)
636 *p++ = '\0';
637
638 r = safe_atou32(f, fwmark);
639 if (r < 0)
640 return log_error_errno(r, "Failed to parse RPDB rule firewall mark, ignoring: %s", f);
641
642 if (p) {
643 r = safe_atou32(p, fwmask);
644 if (r < 0)
645 return log_error_errno(r, "Failed to parse RPDB rule mask, ignoring: %s", f);
646 }
647
648 return 0;
649}
650
651int config_parse_routing_policy_rule_tos(
652 const char *unit,
653 const char *filename,
654 unsigned line,
655 const char *section,
656 unsigned section_line,
657 const char *lvalue,
658 int ltype,
659 const char *rvalue,
660 void *data,
661 void *userdata) {
662
fcbf4cb7 663 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe
SS
664 Network *network = userdata;
665 int r;
666
667 assert(filename);
668 assert(section);
669 assert(lvalue);
670 assert(rvalue);
671 assert(data);
672
673 r = routing_policy_rule_new_static(network, filename, section_line, &n);
674 if (r < 0)
675 return r;
676
677 r = safe_atou8(rvalue, &n->tos);
678 if (r < 0) {
679 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule tos, ignoring: %s", rvalue);
680 return 0;
681 }
682
683 n = NULL;
684
685 return 0;
686}
687
688int config_parse_routing_policy_rule_priority(
689 const char *unit,
690 const char *filename,
691 unsigned line,
692 const char *section,
693 unsigned section_line,
694 const char *lvalue,
695 int ltype,
696 const char *rvalue,
697 void *data,
698 void *userdata) {
699
fcbf4cb7 700 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe
SS
701 Network *network = userdata;
702 int r;
703
704 assert(filename);
705 assert(section);
706 assert(lvalue);
707 assert(rvalue);
708 assert(data);
709
710 r = routing_policy_rule_new_static(network, filename, section_line, &n);
711 if (r < 0)
712 return r;
713
714 r = safe_atou32(rvalue, &n->priority);
715 if (r < 0) {
716 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule priority, ignoring: %s", rvalue);
717 return 0;
718 }
719
720 n = NULL;
721
722 return 0;
723}
724
725int config_parse_routing_policy_rule_table(
726 const char *unit,
727 const char *filename,
728 unsigned line,
729 const char *section,
730 unsigned section_line,
731 const char *lvalue,
732 int ltype,
733 const char *rvalue,
734 void *data,
735 void *userdata) {
736
fcbf4cb7 737 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe
SS
738 Network *network = userdata;
739 int r;
740
741 assert(filename);
742 assert(section);
743 assert(lvalue);
744 assert(rvalue);
745 assert(data);
746
747 r = routing_policy_rule_new_static(network, filename, section_line, &n);
748 if (r < 0)
749 return r;
750
751 r = safe_atou32(rvalue, &n->table);
752 if (r < 0) {
753 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue);
754 return 0;
755 }
756
757 n = NULL;
758
759 return 0;
760}
761
762int config_parse_routing_policy_rule_fwmark_mask(
763 const char *unit,
764 const char *filename,
765 unsigned line,
766 const char *section,
767 unsigned section_line,
768 const char *lvalue,
769 int ltype,
770 const char *rvalue,
771 void *data,
772 void *userdata) {
773
fcbf4cb7 774 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe
SS
775 Network *network = userdata;
776 int r;
777
778 assert(filename);
779 assert(section);
780 assert(lvalue);
781 assert(rvalue);
782 assert(data);
783
784 r = routing_policy_rule_new_static(network, filename, section_line, &n);
785 if (r < 0)
786 return r;
787
788 r = parse_fwmark_fwmask(rvalue, &n->fwmark, &n->fwmask);
789 if (r < 0) {
790 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", rvalue);
791 return 0;
792 }
793
794 n = NULL;
795
796 return 0;
797}
798
799int config_parse_routing_policy_rule_prefix(
800 const char *unit,
801 const char *filename,
802 unsigned line,
803 const char *section,
804 unsigned section_line,
805 const char *lvalue,
806 int ltype,
807 const char *rvalue,
808 void *data,
809 void *userdata) {
810
fcbf4cb7 811 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
bce67bbe 812 Network *network = userdata;
7934dede
YW
813 union in_addr_union *buffer;
814 uint8_t *prefixlen;
bce67bbe
SS
815 int r;
816
817 assert(filename);
818 assert(section);
819 assert(lvalue);
820 assert(rvalue);
821 assert(data);
822
823 r = routing_policy_rule_new_static(network, filename, section_line, &n);
824 if (r < 0)
825 return r;
826
bce67bbe 827 if (streq(lvalue, "To")) {
7934dede
YW
828 buffer = &n->to;
829 prefixlen = &n->to_prefixlen;
bce67bbe 830 } else {
7934dede
YW
831 buffer = &n->from;
832 prefixlen = &n->from_prefixlen;
833 }
834
0aabccc8
YW
835 if (n->family == AF_UNSPEC)
836 r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
837 else
838 r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
7934dede
YW
839 if (r < 0) {
840 log_syntax(unit, LOG_ERR, filename, line, r, "RPDB rule prefix is invalid, ignoring assignment: %s", rvalue);
841 return 0;
bce67bbe
SS
842 }
843
844 n = NULL;
845
846 return 0;
847}
848
762e2659
SS
849int config_parse_routing_policy_rule_device(
850 const char *unit,
851 const char *filename,
852 unsigned line,
853 const char *section,
854 unsigned section_line,
855 const char *lvalue,
856 int ltype,
857 const char *rvalue,
858 void *data,
859 void *userdata) {
860
fcbf4cb7 861 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
762e2659
SS
862 Network *network = userdata;
863 int r;
864
865 assert(filename);
866 assert(section);
867 assert(lvalue);
868 assert(rvalue);
869 assert(data);
870
871 r = routing_policy_rule_new_static(network, filename, section_line, &n);
872 if (r < 0)
873 return r;
874
875 if (!ifname_valid(rvalue)) {
876 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse '%s' interface name, ignoring: %s", lvalue, rvalue);
877 return 0;
878 }
879
880 if (streq(lvalue, "IncomingInterface")) {
881 r = free_and_strdup(&n->iif, rvalue);
882 if (r < 0)
883 return log_oom();
884 } else {
885 r = free_and_strdup(&n->oif, rvalue);
886 if (r < 0)
887 return log_oom();
888 }
889
890 n = NULL;
891
892 return 0;
893}
894
926062f0
SS
895int config_parse_routing_policy_rule_port_range(
896 const char *unit,
897 const char *filename,
898 unsigned line,
899 const char *section,
900 unsigned section_line,
901 const char *lvalue,
902 int ltype,
903 const char *rvalue,
904 void *data,
905 void *userdata) {
fcbf4cb7 906 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
926062f0
SS
907 Network *network = userdata;
908 uint16_t low, high;
909 int r;
910
911 assert(filename);
912 assert(section);
913 assert(lvalue);
914 assert(rvalue);
915 assert(data);
916
917 r = routing_policy_rule_new_static(network, filename, section_line, &n);
918 if (r < 0)
919 return r;
920
921 r = parse_ip_port_range(rvalue, &low, &high);
922 if (r < 0) {
923 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse routing policy rule port range '%s'", rvalue);
924 return 0;
925 }
926
927 if (streq(lvalue, "SourcePort")) {
928 n->sport.start = low;
929 n->sport.end = high;
930 } else {
931 n->dport.start = low;
932 n->dport.end = high;
933 }
934
935 n = NULL;
936
937 return 0;
938}
939
97f9df9e 940int config_parse_routing_policy_rule_ip_protocol(
926062f0
SS
941 const char *unit,
942 const char *filename,
943 unsigned line,
944 const char *section,
945 unsigned section_line,
946 const char *lvalue,
947 int ltype,
948 const char *rvalue,
949 void *data,
950 void *userdata) {
951
fcbf4cb7 952 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
926062f0
SS
953 Network *network = userdata;
954 int r;
955
956 assert(filename);
957 assert(section);
958 assert(lvalue);
959 assert(rvalue);
960 assert(data);
961
962 r = routing_policy_rule_new_static(network, filename, section_line, &n);
963 if (r < 0)
964 return r;
965
3a269dcf 966 r = parse_ip_protocol(rvalue);
926062f0 967 if (r < 0) {
3a269dcf 968 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IP protocol '%s' for routing policy rule, ignoring: %m", rvalue);
926062f0
SS
969 return 0;
970 }
971
972 n->protocol = r;
973
974 n = NULL;
975
976 return 0;
977}
978
8b220643
SS
979int config_parse_routing_policy_rule_invert(
980 const char *unit,
981 const char *filename,
982 unsigned line,
983 const char *section,
984 unsigned section_line,
985 const char *lvalue,
986 int ltype,
987 const char *rvalue,
988 void *data,
989 void *userdata) {
990
fcbf4cb7 991 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
8b220643
SS
992 Network *network = userdata;
993 int r;
994
995 assert(filename);
996 assert(section);
997 assert(lvalue);
998 assert(rvalue);
999 assert(data);
1000
1001 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1002 if (r < 0)
1003 return r;
1004
1005 r = parse_boolean(rvalue);
1006 if (r < 0) {
1007 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse RPDB rule invert, ignoring: %s", rvalue);
1008 return 0;
1009 }
1010
1011 n->invert_rule = r;
1012
1013 n = NULL;
1014
1015 return 0;
1016}
1017
f6c6ff97
YW
1018int config_parse_routing_policy_rule_family(
1019 const char *unit,
1020 const char *filename,
1021 unsigned line,
1022 const char *section,
1023 unsigned section_line,
1024 const char *lvalue,
1025 int ltype,
1026 const char *rvalue,
1027 void *data,
1028 void *userdata) {
1029
1030 _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
1031 Network *network = userdata;
1032 AddressFamily a;
1033 int r;
1034
1035 assert(filename);
1036 assert(section);
1037 assert(lvalue);
1038 assert(rvalue);
1039 assert(data);
1040
1041 r = routing_policy_rule_new_static(network, filename, section_line, &n);
1042 if (r < 0)
1043 return r;
1044
1045 a = routing_policy_rule_address_family_from_string(rvalue);
1046 if (a < 0) {
1047 log_syntax(unit, LOG_ERR, filename, line, 0,
1048 "Invalid address family '%s', ignoring.", rvalue);
1049 return 0;
1050 }
1051
1052 n->address_family = a;
1053 n = NULL;
1054
1055 return 0;
1056}
1057
458d8ae3 1058static int routing_policy_rule_read_full_file(const char *state_file, char **ret) {
ac097c84 1059 _cleanup_free_ char *s = NULL;
bce67bbe
SS
1060 size_t size;
1061 int r;
1062
1063 assert(state_file);
1064
1065 r = read_full_file(state_file, &s, &size);
1066 if (r == -ENOENT)
1067 return -ENODATA;
1068 if (r < 0)
1069 return r;
1070 if (size <= 0)
1071 return -ENODATA;
1072
ae2a15bc 1073 *ret = TAKE_PTR(s);
bce67bbe
SS
1074
1075 return size;
1076}
1077
458d8ae3
ZJS
1078int routing_policy_serialize_rules(Set *rules, FILE *f) {
1079 RoutingPolicyRule *rule = NULL;
1080 Iterator i;
1081 int r;
1082
1083 assert(f);
1084
1085 SET_FOREACH(rule, rules, i) {
1086 _cleanup_free_ char *from_str = NULL, *to_str = NULL;
1087 bool space = false;
43e08c78 1088 const char *family_str;
458d8ae3
ZJS
1089
1090 fputs("RULE=", f);
1091
1092 if (!in_addr_is_null(rule->family, &rule->from)) {
1093 r = in_addr_to_string(rule->family, &rule->from, &from_str);
1094 if (r < 0)
1095 return r;
1096
1097 fprintf(f, "from=%s/%hhu",
1098 from_str, rule->from_prefixlen);
1099 space = true;
1100 }
1101
1102 if (!in_addr_is_null(rule->family, &rule->to)) {
1103 r = in_addr_to_string(rule->family, &rule->to, &to_str);
1104 if (r < 0)
1105 return r;
1106
1107 fprintf(f, "%sto=%s/%hhu",
1108 space ? " " : "",
1109 to_str, rule->to_prefixlen);
1110 space = true;
1111 }
1112
43e08c78
YW
1113 family_str = af_to_name(rule->family);
1114 if (family_str)
1115 fprintf(f, "%sfamily=%s",
1116 space ? " " : "",
1117 family_str);
1118
458d8ae3
ZJS
1119 if (rule->tos != 0) {
1120 fprintf(f, "%stos=%hhu",
1121 space ? " " : "",
1122 rule->tos);
1123 space = true;
1124 }
1125
ec863cdc
YW
1126 fprintf(f, "%spriority=%"PRIu32,
1127 space ? " " : "",
1128 rule->priority);
1129
458d8ae3
ZJS
1130 if (rule->fwmark != 0) {
1131 fprintf(f, "%sfwmark=%"PRIu32"/%"PRIu32,
1132 space ? " " : "",
1133 rule->fwmark, rule->fwmask);
1134 space = true;
1135 }
1136
9491f55f
ZJS
1137 if (rule->iif) {
1138 fprintf(f, "%siif=%s",
1139 space ? " " : "",
1140 rule->iif);
1141 space = true;
1142 }
1143
1144 if (rule->oif) {
1145 fprintf(f, "%soif=%s",
1146 space ? " " : "",
1147 rule->oif);
1148 space = true;
1149 }
1150
926062f0
SS
1151 if (rule->protocol != 0) {
1152 fprintf(f, "%sprotocol=%hhu",
1153 space ? " " : "",
1154 rule->protocol);
1155 space = true;
1156 }
1157
1158 if (rule->sport.start != 0 || rule->sport.end != 0) {
58a02e4c 1159 fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16,
926062f0
SS
1160 space ? " " : "",
1161 rule->sport.start, rule->sport.end);
1162 space = true;
1163 }
1164
1165 if (rule->dport.start != 0 || rule->dport.end != 0) {
58a02e4c 1166 fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16,
926062f0
SS
1167 space ? " " : "",
1168 rule->dport.start, rule->dport.end);
1169 space = true;
1170 }
1171
458d8ae3
ZJS
1172 fprintf(f, "%stable=%"PRIu32 "\n",
1173 space ? " " : "",
1174 rule->table);
1175 }
1176
1177 return 0;
1178}
1179
1180int routing_policy_load_rules(const char *state_file, Set **rules) {
bce67bbe
SS
1181 _cleanup_strv_free_ char **l = NULL;
1182 _cleanup_free_ char *data = NULL;
926062f0 1183 uint16_t low = 0, high = 0;
bce67bbe
SS
1184 const char *p;
1185 char **i;
1186 int r;
1187
458d8ae3
ZJS
1188 assert(state_file);
1189 assert(rules);
bce67bbe 1190
458d8ae3 1191 r = routing_policy_rule_read_full_file(state_file, &data);
bce67bbe
SS
1192 if (r <= 0)
1193 return r;
1194
1195 l = strv_split_newlines(data);
1196 if (!l)
1197 return -ENOMEM;
1198
458d8ae3 1199 r = set_ensure_allocated(rules, &routing_policy_rule_hash_ops);
bce67bbe
SS
1200 if (r < 0)
1201 return r;
1202
1203 STRV_FOREACH(i, l) {
8e766630 1204 _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL;
bce67bbe
SS
1205
1206 p = startswith(*i, "RULE=");
1207 if (!p)
1208 continue;
1209
bce67bbe
SS
1210 r = routing_policy_rule_new(&rule);
1211 if (r < 0)
1212 return r;
1213
1214 for (;;) {
1215 _cleanup_free_ char *word = NULL, *a = NULL, *b = NULL;
bce67bbe
SS
1216
1217 r = extract_first_word(&p, &word, NULL, 0);
1218 if (r < 0)
1219 return r;
1220 if (r == 0)
1221 break;
1222
1223 r = split_pair(word, "=", &a, &b);
1224 if (r < 0)
1225 continue;
1226
1227 if (STR_IN_SET(a, "from", "to")) {
7934dede
YW
1228 union in_addr_union *buffer;
1229 uint8_t *prefixlen;
bce67bbe
SS
1230
1231 if (streq(a, "to")) {
7934dede
YW
1232 buffer = &rule->to;
1233 prefixlen = &rule->to_prefixlen;
bce67bbe 1234 } else {
7934dede
YW
1235 buffer = &rule->from;
1236 prefixlen = &rule->from_prefixlen;
1237 }
1238
1239 r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen);
1240 if (r < 0) {
1241 log_error_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b);
1242 continue;
bce67bbe 1243 }
7934dede 1244
43e08c78
YW
1245 } else if (streq(a, "family")) {
1246 r = af_from_name(b);
1247 if (r < 0) {
1248 log_error_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b);
1249 continue;
1250 }
1251 rule->family = r;
bce67bbe
SS
1252 } else if (streq(a, "tos")) {
1253 r = safe_atou8(b, &rule->tos);
1254 if (r < 0) {
1255 log_error_errno(r, "Failed to parse RPDB rule tos, ignoring: %s", b);
1256 continue;
1257 }
1258 } else if (streq(a, "table")) {
1259 r = safe_atou32(b, &rule->table);
1260 if (r < 0) {
1261 log_error_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b);
1262 continue;
1263 }
ec863cdc
YW
1264 } else if (streq(a, "priority")) {
1265 r = safe_atou32(b, &rule->priority);
1266 if (r < 0) {
1267 log_error_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b);
1268 continue;
1269 }
bce67bbe
SS
1270 } else if (streq(a, "fwmark")) {
1271
e4aca57d 1272 r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask);
bce67bbe
SS
1273 if (r < 0) {
1274 log_error_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a);
1275 continue;
1276 }
9491f55f 1277 } else if (streq(a, "iif")) {
762e2659 1278
93f9da6e 1279 if (free_and_strdup(&rule->iif, b) < 0)
762e2659 1280 return log_oom();
93f9da6e 1281
9491f55f 1282 } else if (streq(a, "oif")) {
762e2659 1283
93f9da6e 1284 if (free_and_strdup(&rule->oif, b) < 0)
762e2659 1285 return log_oom();
926062f0
SS
1286 } else if (streq(a, "protocol")) {
1287 r = safe_atou8(b, &rule->protocol);
1288 if (r < 0) {
1289 log_error_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b);
1290 continue;
1291 }
1292 } else if (streq(a, "sourceport")) {
1293
1294 r = parse_ip_port_range(b, &low, &high);
1295 if (r < 0) {
1296 log_error_errno(r, "Invalid routing policy rule source port range, ignoring assignment:'%s'", b);
1297 continue;
1298 }
1299
1300 rule->sport.start = low;
1301 rule->sport.end = high;
1302
1303 } else if (streq(a, "destinationport")) {
1304
1305 r = parse_ip_port_range(b, &low, &high);
1306 if (r < 0) {
1307 log_error_errno(r, "Invalid routing policy rule destination port range, ignoring assignment:'%s'", b);
1308 continue;
1309 }
1310
1311 rule->dport.start = low;
1312 rule->dport.end = high;
bce67bbe
SS
1313 }
1314 }
1315
458d8ae3 1316 r = set_put(*rules, rule);
bce67bbe
SS
1317 if (r < 0) {
1318 log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", p);
1319 continue;
1320 }
75a302b5
YW
1321 if (r > 0)
1322 rule = NULL;
bce67bbe
SS
1323 }
1324
1325 return 0;
1326}
1327
031fb59a
YW
1328static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
1329 RoutingPolicyRule *link_rule;
1330 Iterator i;
1331 Link *link;
1332
1333 assert(m);
1334 assert(rule);
1335
1336 HASHMAP_FOREACH(link, m->links, i) {
1337 if (!link->network)
1338 continue;
1339
1340 LIST_FOREACH(rules, link_rule, link->network->rules)
1341 if (routing_policy_rule_compare_func(link_rule, rule) == 0)
1342 return true;
1343 }
1344
1345 return false;
1346}
1347
bce67bbe
SS
1348void routing_policy_rule_purge(Manager *m, Link *link) {
1349 RoutingPolicyRule *rule, *existing;
1350 Iterator i;
1351 int r;
1352
1353 assert(m);
1354 assert(link);
1355
1356 SET_FOREACH(rule, m->rules_saved, i) {
1357 existing = set_get(m->rules_foreign, rule);
92cd00b9
YW
1358 if (!existing)
1359 continue; /* Saved rule does not exist anymore. */
bce67bbe 1360
031fb59a
YW
1361 if (manager_links_have_routing_policy_rule(m, existing))
1362 continue; /* Existing links have the saved rule. */
1363
1364 /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
1365 * later when it is requested. */
1366
92cd00b9
YW
1367 r = routing_policy_rule_remove(existing, link, NULL);
1368 if (r < 0) {
1369 log_warning_errno(r, "Could not remove routing policy rules: %m");
1370 continue;
bce67bbe 1371 }
92cd00b9
YW
1372
1373 link->routing_policy_rule_remove_messages++;
1374
1375 assert_se(set_remove(m->rules_foreign, existing) == existing);
1376 routing_policy_rule_free(existing);
bce67bbe
SS
1377 }
1378}