]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-link.c
resolved: cache stringified transaction key once per transaction
[thirdparty/systemd.git] / src / resolve / resolved-link.c
CommitLineData
74b2466e
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <net/if.h>
23
24#include "sd-network.h"
07630cea 25
b5efdb8a 26#include "alloc-util.h"
ec2c5e43 27#include "missing.h"
6bedfcbb 28#include "parse-util.h"
74b2466e 29#include "resolved-link.h"
07630cea
LP
30#include "string-util.h"
31#include "strv.h"
74b2466e
LP
32
33int link_new(Manager *m, Link **ret, int ifindex) {
34 _cleanup_(link_freep) Link *l = NULL;
35 int r;
36
37 assert(m);
38 assert(ifindex > 0);
39
d5099efc 40 r = hashmap_ensure_allocated(&m->links, NULL);
74b2466e
LP
41 if (r < 0)
42 return r;
43
44 l = new0(Link, 1);
45 if (!l)
46 return -ENOMEM;
47
48 l->ifindex = ifindex;
19b50b5b 49 l->llmnr_support = SUPPORT_YES;
74b2466e
LP
50
51 r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
52 if (r < 0)
53 return r;
54
55 l->manager = m;
56
57 if (ret)
58 *ret = l;
59 l = NULL;
60
61 return 0;
62}
63
64Link *link_free(Link *l) {
74b2466e
LP
65 if (!l)
66 return NULL;
67
4b95f179 68 dns_server_unlink_marked(l->dns_servers);
a51c1048 69 dns_search_domain_unlink_all(l->search_domains);
0eac4623 70
74b2466e
LP
71 while (l->addresses)
72 link_address_free(l->addresses);
73
74 if (l->manager)
75 hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex));
76
77 dns_scope_free(l->unicast_scope);
1716f6dc
LP
78 dns_scope_free(l->llmnr_ipv4_scope);
79 dns_scope_free(l->llmnr_ipv6_scope);
b4f1862d
DM
80 dns_scope_free(l->mdns_ipv4_scope);
81 dns_scope_free(l->mdns_ipv6_scope);
74b2466e 82
74b2466e
LP
83 free(l);
84 return NULL;
1716f6dc
LP
85}
86
87static void link_allocate_scopes(Link *l) {
88 int r;
89
90 assert(l);
91
6073b6f2 92 if (l->dns_servers) {
1716f6dc
LP
93 if (!l->unicast_scope) {
94 r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC);
95 if (r < 0)
da927ba9 96 log_warning_errno(r, "Failed to allocate DNS scope: %m");
1716f6dc
LP
97 }
98 } else
99 l->unicast_scope = dns_scope_free(l->unicast_scope);
100
90ab5042
LP
101 if (link_relevant(l, AF_INET) &&
102 l->llmnr_support != SUPPORT_NO &&
db97a66a 103 l->manager->llmnr_support != SUPPORT_NO) {
1716f6dc
LP
104 if (!l->llmnr_ipv4_scope) {
105 r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET);
106 if (r < 0)
da927ba9 107 log_warning_errno(r, "Failed to allocate LLMNR IPv4 scope: %m");
1716f6dc
LP
108 }
109 } else
110 l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope);
111
90ab5042
LP
112 if (link_relevant(l, AF_INET6) &&
113 l->llmnr_support != SUPPORT_NO &&
114 l->manager->llmnr_support != SUPPORT_NO &&
db97a66a 115 socket_ipv6_is_supported()) {
1716f6dc
LP
116 if (!l->llmnr_ipv6_scope) {
117 r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6);
118 if (r < 0)
da927ba9 119 log_warning_errno(r, "Failed to allocate LLMNR IPv6 scope: %m");
1716f6dc
LP
120 }
121 } else
122 l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope);
b4f1862d
DM
123
124 if (link_relevant(l, AF_INET) &&
125 l->mdns_support != SUPPORT_NO &&
126 l->manager->mdns_support != SUPPORT_NO) {
127 if (!l->mdns_ipv4_scope) {
128 r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET);
129 if (r < 0)
130 log_warning_errno(r, "Failed to allocate mDNS IPv4 scope: %m");
131 }
132 } else
133 l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope);
134
135 if (link_relevant(l, AF_INET6) &&
136 l->mdns_support != SUPPORT_NO &&
137 l->manager->mdns_support != SUPPORT_NO) {
138 if (!l->mdns_ipv6_scope) {
139 r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6);
140 if (r < 0)
141 log_warning_errno(r, "Failed to allocate mDNS IPv6 scope: %m");
142 }
143 } else
144 l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope);
1716f6dc 145}
74b2466e 146
ec2c5e43 147void link_add_rrs(Link *l, bool force_remove) {
623a4c97
LP
148 LinkAddress *a;
149
150 LIST_FOREACH(addresses, a, l->addresses)
ec2c5e43 151 link_address_add_rrs(a, force_remove);
623a4c97
LP
152}
153
1c4baffc 154int link_update_rtnl(Link *l, sd_netlink_message *m) {
1716f6dc 155 const char *n = NULL;
74b2466e
LP
156 int r;
157
158 assert(l);
159 assert(m);
160
161 r = sd_rtnl_message_link_get_flags(m, &l->flags);
162 if (r < 0)
163 return r;
164
1c4baffc 165 sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu);
1716f6dc 166
1c4baffc 167 if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
cc7844e7 168 strncpy(l->name, n, sizeof(l->name)-1);
1716f6dc
LP
169 char_array_0(l->name);
170 }
171
172 link_allocate_scopes(l);
ec2c5e43 173 link_add_rrs(l, false);
623a4c97 174
74b2466e
LP
175 return 0;
176}
177
6073b6f2 178static int link_update_dns_servers(Link *l) {
6f4dedb2
TG
179 _cleanup_strv_free_ char **nameservers = NULL;
180 char **nameserver;
6f4dedb2 181 int r;
74b2466e
LP
182
183 assert(l);
184
d6731e4c 185 r = sd_network_link_get_dns(l->ifindex, &nameservers);
1ade96e9
LP
186 if (r == -ENODATA) {
187 r = 0;
188 goto clear;
189 }
6f4dedb2 190 if (r < 0)
74b2466e 191 goto clear;
74b2466e 192
4b95f179 193 dns_server_mark_all(l->dns_servers);
5cb36f41 194
6f4dedb2
TG
195 STRV_FOREACH(nameserver, nameservers) {
196 union in_addr_union a;
0eac4623 197 DnsServer *s;
6f4dedb2 198 int family;
74b2466e 199
6f4dedb2
TG
200 r = in_addr_from_string_auto(*nameserver, &family, &a);
201 if (r < 0)
202 goto clear;
74b2466e 203
4b95f179 204 s = dns_server_find(l->dns_servers, family, &a);
74b2466e 205 if (s)
0b58db65 206 dns_server_move_back_and_unmark(s);
74b2466e 207 else {
4e945a6f 208 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a);
74b2466e
LP
209 if (r < 0)
210 goto clear;
211 }
212 }
213
4b95f179 214 dns_server_unlink_marked(l->dns_servers);
74b2466e
LP
215 return 0;
216
217clear:
4b95f179 218 dns_server_unlink_all(l->dns_servers);
74b2466e
LP
219 return r;
220}
221
19b50b5b
LP
222static int link_update_llmnr_support(Link *l) {
223 _cleanup_free_ char *b = NULL;
224 int r;
225
226 assert(l);
227
d6731e4c 228 r = sd_network_link_get_llmnr(l->ifindex, &b);
1ade96e9
LP
229 if (r == -ENODATA) {
230 r = 0;
231 goto clear;
232 }
19b50b5b
LP
233 if (r < 0)
234 goto clear;
235
236 r = parse_boolean(b);
237 if (r < 0) {
238 if (streq(b, "resolve"))
239 l->llmnr_support = SUPPORT_RESOLVE;
240 else
241 goto clear;
242
243 } else if (r > 0)
244 l->llmnr_support = SUPPORT_YES;
245 else
246 l->llmnr_support = SUPPORT_NO;
247
248 return 0;
249
250clear:
251 l->llmnr_support = SUPPORT_YES;
252 return r;
253}
254
a51c1048
LP
255static int link_update_search_domains(Link *l) {
256 _cleanup_strv_free_ char **domains = NULL;
257 char **i;
bda2c408
TG
258 int r;
259
a51c1048 260 assert(l);
bda2c408 261
a51c1048 262 r = sd_network_link_get_domains(l->ifindex, &domains);
1ade96e9
LP
263 if (r == -ENODATA) {
264 /* networkd knows nothing about this interface, and that's fine. */
265 r = 0;
266 goto clear;
267 }
bda2c408 268 if (r < 0)
a51c1048
LP
269 goto clear;
270
271 dns_search_domain_mark_all(l->search_domains);
272
273 STRV_FOREACH(i, domains) {
274 DnsSearchDomain *d;
bda2c408 275
a51c1048
LP
276 r = dns_search_domain_find(l->search_domains, *i, &d);
277 if (r < 0)
278 goto clear;
279
280 if (r > 0)
281 dns_search_domain_move_back_and_unmark(d);
282 else {
283 r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i);
284 if (r < 0)
285 goto clear;
286 }
287 }
288
289 dns_search_domain_unlink_marked(l->search_domains);
bda2c408 290 return 0;
a51c1048
LP
291
292clear:
293 dns_search_domain_unlink_all(l->search_domains);
294 return r;
bda2c408
TG
295}
296
74b2466e 297int link_update_monitor(Link *l) {
a51c1048
LP
298 int r;
299
74b2466e
LP
300 assert(l);
301
6073b6f2 302 link_update_dns_servers(l);
19b50b5b 303 link_update_llmnr_support(l);
1716f6dc 304 link_allocate_scopes(l);
a51c1048
LP
305
306 r = link_update_search_domains(l);
307 if (r < 0)
308 log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
309
ec2c5e43 310 link_add_rrs(l, false);
74b2466e
LP
311
312 return 0;
313}
314
0dd25fb9 315bool link_relevant(Link *l, int family) {
1716f6dc 316 _cleanup_free_ char *state = NULL;
74b2466e
LP
317 LinkAddress *a;
318
319 assert(l);
320
ec2c5e43
LP
321 /* A link is relevant if it isn't a loopback or pointopoint
322 * device, has a link beat, can do multicast and has at least
323 * one relevant IP address */
324
325 if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT))
326 return false;
74b2466e 327
ec2c5e43 328 if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST))
74b2466e
LP
329 return false;
330
d6731e4c 331 sd_network_link_get_operational_state(l->ifindex, &state);
1716f6dc 332 if (state && !STR_IN_SET(state, "unknown", "degraded", "routable"))
74b2466e
LP
333 return false;
334
335 LIST_FOREACH(addresses, a, l->addresses)
1716f6dc 336 if (a->family == family && link_address_relevant(a))
74b2466e
LP
337 return true;
338
339 return false;
340}
341
623a4c97 342LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *in_addr) {
74b2466e
LP
343 LinkAddress *a;
344
345 assert(l);
346
1716f6dc
LP
347 LIST_FOREACH(addresses, a, l->addresses)
348 if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr))
74b2466e 349 return a;
74b2466e
LP
350
351 return NULL;
352}
353
2c27fbca 354DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
4e945a6f
LP
355 assert(l);
356
357 if (l->current_dns_server == s)
358 return s;
359
360 if (s) {
361 _cleanup_free_ char *ip = NULL;
362
363 in_addr_to_string(s->family, &s->address, &ip);
364 log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name);
2c27fbca 365 }
4e945a6f 366
0eac4623
LP
367 dns_server_unref(l->current_dns_server);
368 l->current_dns_server = dns_server_ref(s);
2c27fbca
LP
369
370 if (l->unicast_scope)
371 dns_cache_flush(&l->unicast_scope->cache);
372
4e945a6f
LP
373 return s;
374}
375
74b2466e
LP
376DnsServer *link_get_dns_server(Link *l) {
377 assert(l);
378
379 if (!l->current_dns_server)
4e945a6f 380 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
381
382 return l->current_dns_server;
383}
384
385void link_next_dns_server(Link *l) {
386 assert(l);
387
74b2466e
LP
388 if (!l->current_dns_server)
389 return;
390
0eac4623
LP
391 /* Change to the next one, but make sure to follow the linked
392 * list only if this server is actually still linked. */
393 if (l->current_dns_server->linked && l->current_dns_server->servers_next) {
4e945a6f 394 link_set_dns_server(l, l->current_dns_server->servers_next);
74b2466e
LP
395 return;
396 }
397
4e945a6f 398 link_set_dns_server(l, l->dns_servers);
74b2466e
LP
399}
400
623a4c97 401int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) {
74b2466e
LP
402 LinkAddress *a;
403
404 assert(l);
405 assert(in_addr);
406
407 a = new0(LinkAddress, 1);
408 if (!a)
409 return -ENOMEM;
410
411 a->family = family;
412 a->in_addr = *in_addr;
413
414 a->link = l;
415 LIST_PREPEND(addresses, l->addresses, a);
416
417 if (ret)
418 *ret = a;
419
420 return 0;
421}
422
423LinkAddress *link_address_free(LinkAddress *a) {
424 if (!a)
425 return NULL;
426
623a4c97 427 if (a->link) {
74b2466e
LP
428 LIST_REMOVE(addresses, a->link->addresses, a);
429
623a4c97 430 if (a->llmnr_address_rr) {
623a4c97
LP
431 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
432 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
433 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
434 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
623a4c97
LP
435 }
436
437 if (a->llmnr_ptr_rr) {
438 if (a->family == AF_INET && a->link->llmnr_ipv4_scope)
439 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
440 else if (a->family == AF_INET6 && a->link->llmnr_ipv6_scope)
441 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
623a4c97
LP
442 }
443 }
444
ec2c5e43
LP
445 dns_resource_record_unref(a->llmnr_address_rr);
446 dns_resource_record_unref(a->llmnr_ptr_rr);
447
74b2466e
LP
448 free(a);
449 return NULL;
450}
451
ec2c5e43 452void link_address_add_rrs(LinkAddress *a, bool force_remove) {
623a4c97
LP
453 int r;
454
455 assert(a);
456
ec2c5e43 457 if (a->family == AF_INET) {
623a4c97 458
4e945a6f
LP
459 if (!force_remove &&
460 link_address_relevant(a) &&
461 a->link->llmnr_ipv4_scope &&
19b50b5b 462 a->link->llmnr_support == SUPPORT_YES &&
4e945a6f
LP
463 a->link->manager->llmnr_support == SUPPORT_YES) {
464
78c6a153
LP
465 if (!a->link->manager->llmnr_host_ipv4_key) {
466 a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname);
467 if (!a->link->manager->llmnr_host_ipv4_key) {
ec2c5e43
LP
468 r = -ENOMEM;
469 goto fail;
470 }
623a4c97 471 }
623a4c97 472
623a4c97 473 if (!a->llmnr_address_rr) {
78c6a153 474 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv4_key);
ec2c5e43
LP
475 if (!a->llmnr_address_rr) {
476 r = -ENOMEM;
477 goto fail;
478 }
479
480 a->llmnr_address_rr->a.in_addr = a->in_addr.in;
481 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
482 }
483
ec2c5e43 484 if (!a->llmnr_ptr_rr) {
78c6a153 485 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
486 if (r < 0)
487 goto fail;
623a4c97 488
ec2c5e43
LP
489 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
490 }
623a4c97 491
ec2c5e43 492 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_address_rr, true);
623a4c97 493 if (r < 0)
da927ba9 494 log_warning_errno(r, "Failed to add A record to LLMNR zone: %m");
623a4c97 495
ec2c5e43 496 r = dns_zone_put(&a->link->llmnr_ipv4_scope->zone, a->link->llmnr_ipv4_scope, a->llmnr_ptr_rr, false);
623a4c97 497 if (r < 0)
da927ba9 498 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 499 } else {
ec2c5e43
LP
500 if (a->llmnr_address_rr) {
501 if (a->link->llmnr_ipv4_scope)
502 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_address_rr);
503 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
504 }
505
506 if (a->llmnr_ptr_rr) {
507 if (a->link->llmnr_ipv4_scope)
508 dns_zone_remove_rr(&a->link->llmnr_ipv4_scope->zone, a->llmnr_ptr_rr);
509 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
510 }
623a4c97
LP
511 }
512 }
513
ec2c5e43 514 if (a->family == AF_INET6) {
623a4c97 515
4e945a6f
LP
516 if (!force_remove &&
517 link_address_relevant(a) &&
518 a->link->llmnr_ipv6_scope &&
19b50b5b 519 a->link->llmnr_support == SUPPORT_YES &&
4e945a6f
LP
520 a->link->manager->llmnr_support == SUPPORT_YES) {
521
78c6a153
LP
522 if (!a->link->manager->llmnr_host_ipv6_key) {
523 a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname);
524 if (!a->link->manager->llmnr_host_ipv6_key) {
ec2c5e43
LP
525 r = -ENOMEM;
526 goto fail;
527 }
623a4c97 528 }
623a4c97 529
623a4c97 530 if (!a->llmnr_address_rr) {
78c6a153 531 a->llmnr_address_rr = dns_resource_record_new(a->link->manager->llmnr_host_ipv6_key);
ec2c5e43
LP
532 if (!a->llmnr_address_rr) {
533 r = -ENOMEM;
534 goto fail;
535 }
536
537 a->llmnr_address_rr->aaaa.in6_addr = a->in_addr.in6;
538 a->llmnr_address_rr->ttl = LLMNR_DEFAULT_TTL;
623a4c97
LP
539 }
540
ec2c5e43 541 if (!a->llmnr_ptr_rr) {
78c6a153 542 r = dns_resource_record_new_reverse(&a->llmnr_ptr_rr, a->family, &a->in_addr, a->link->manager->llmnr_hostname);
ec2c5e43
LP
543 if (r < 0)
544 goto fail;
623a4c97 545
ec2c5e43
LP
546 a->llmnr_ptr_rr->ttl = LLMNR_DEFAULT_TTL;
547 }
623a4c97 548
ec2c5e43 549 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_address_rr, true);
623a4c97 550 if (r < 0)
da927ba9 551 log_warning_errno(r, "Failed to add AAAA record to LLMNR zone: %m");
623a4c97 552
ec2c5e43 553 r = dns_zone_put(&a->link->llmnr_ipv6_scope->zone, a->link->llmnr_ipv6_scope, a->llmnr_ptr_rr, false);
623a4c97 554 if (r < 0)
da927ba9 555 log_warning_errno(r, "Failed to add IPv6 PTR record to LLMNR zone: %m");
623a4c97 556 } else {
ec2c5e43
LP
557 if (a->llmnr_address_rr) {
558 if (a->link->llmnr_ipv6_scope)
559 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_address_rr);
560 a->llmnr_address_rr = dns_resource_record_unref(a->llmnr_address_rr);
561 }
562
563 if (a->llmnr_ptr_rr) {
564 if (a->link->llmnr_ipv6_scope)
565 dns_zone_remove_rr(&a->link->llmnr_ipv6_scope->zone, a->llmnr_ptr_rr);
566 a->llmnr_ptr_rr = dns_resource_record_unref(a->llmnr_ptr_rr);
567 }
623a4c97
LP
568 }
569 }
570
571 return;
572
573fail:
da927ba9 574 log_debug_errno(r, "Failed to update address RRs: %m");
623a4c97
LP
575}
576
1c4baffc 577int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) {
74b2466e
LP
578 int r;
579 assert(a);
580 assert(m);
581
582 r = sd_rtnl_message_addr_get_flags(m, &a->flags);
583 if (r < 0)
584 return r;
585
1716f6dc 586 sd_rtnl_message_addr_get_scope(m, &a->scope);
74b2466e 587
1716f6dc 588 link_allocate_scopes(a->link);
ec2c5e43 589 link_add_rrs(a->link, false);
623a4c97 590
74b2466e
LP
591 return 0;
592}
593
594bool link_address_relevant(LinkAddress *a) {
595 assert(a);
596
7b85d72f 597 if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))
74b2466e
LP
598 return false;
599
600 if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE))
601 return false;
602
603 return true;
604}