]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-ndisc.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / network / networkd-ndisc.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright (C) 2014 Intel Corporation. All rights reserved.
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <netinet/icmp6.h>
22 #include <arpa/inet.h>
23
24 #include "sd-ndisc.h"
25
26 #include "networkd-ndisc.h"
27 #include "networkd-route.h"
28
29 #define NDISC_DNSSL_MAX 64U
30 #define NDISC_RDNSS_MAX 64U
31 #define NDISC_PREFIX_LFT_MIN 7200U
32
33 static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
34 _cleanup_link_unref_ Link *link = userdata;
35 int r;
36
37 assert(link);
38 assert(link->ndisc_messages > 0);
39
40 link->ndisc_messages--;
41
42 r = sd_netlink_message_get_errno(m);
43 if (r < 0 && r != -EEXIST) {
44 log_link_error_errno(link, r, "Could not set NDisc route or address: %m");
45 link_enter_failed(link);
46 }
47
48 if (link->ndisc_messages == 0) {
49 link->ndisc_configured = true;
50 link_check_ready(link);
51 }
52
53 return 1;
54 }
55
56 static void ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
57 _cleanup_route_free_ Route *route = NULL;
58 struct in6_addr gateway;
59 uint16_t lifetime;
60 unsigned preference;
61 uint32_t mtu;
62 usec_t time_now;
63 int r;
64 Address *address;
65 Iterator i;
66
67 assert(link);
68 assert(rt);
69
70 r = sd_ndisc_router_get_lifetime(rt, &lifetime);
71 if (r < 0) {
72 log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
73 return;
74 }
75 if (lifetime == 0) /* not a default router */
76 return;
77
78 r = sd_ndisc_router_get_address(rt, &gateway);
79 if (r < 0) {
80 log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
81 return;
82 }
83
84 SET_FOREACH(address, link->addresses, i) {
85 if (!memcmp(&gateway, &address->in_addr.in6,
86 sizeof(address->in_addr.in6))) {
87 char buffer[INET6_ADDRSTRLEN];
88
89 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
90 inet_ntop(AF_INET6,
91 &address->in_addr.in6,
92 buffer, sizeof(buffer)));
93 return;
94 }
95 }
96
97 SET_FOREACH(address, link->addresses_foreign, i) {
98 if (!memcmp(&gateway, &address->in_addr.in6,
99 sizeof(address->in_addr.in6))) {
100 char buffer[INET6_ADDRSTRLEN];
101
102 log_link_debug(link, "No NDisc route added, gateway %s matches local address",
103 inet_ntop(AF_INET6,
104 &address->in_addr.in6,
105 buffer, sizeof(buffer)));
106 return;
107 }
108 }
109
110 r = sd_ndisc_router_get_preference(rt, &preference);
111 if (r < 0) {
112 log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
113 return;
114 }
115
116 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
117 if (r < 0) {
118 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
119 return;
120 }
121
122 r = sd_ndisc_router_get_mtu(rt, &mtu);
123 if (r == -ENODATA)
124 mtu = 0;
125 else if (r < 0) {
126 log_link_warning_errno(link, r, "Failed to get default router MTU from RA: %m");
127 return;
128 }
129
130 r = route_new(&route);
131 if (r < 0) {
132 log_link_error_errno(link, r, "Could not allocate route: %m");
133 return;
134 }
135
136 route->family = AF_INET6;
137 route->table = link->network->ipv6_accept_ra_route_table;
138 route->priority = link->network->dhcp_route_metric;
139 route->protocol = RTPROT_RA;
140 route->pref = preference;
141 route->gw.in6 = gateway;
142 route->lifetime = time_now + lifetime * USEC_PER_SEC;
143 route->mtu = mtu;
144
145 r = route_configure(route, link, ndisc_netlink_handler);
146 if (r < 0) {
147 log_link_warning_errno(link, r, "Could not set default route: %m");
148 link_enter_failed(link);
149 return;
150 }
151
152 link->ndisc_messages++;
153 }
154
155 static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
156 _cleanup_address_free_ Address *address = NULL;
157 Address *existing_address;
158 uint32_t lifetime_valid, lifetime_preferred, lifetime_remaining;
159 usec_t time_now;
160 unsigned prefixlen;
161 int r;
162
163 assert(link);
164 assert(rt);
165
166 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
167 if (r < 0) {
168 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
169 return;
170 }
171
172 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
173 if (r < 0) {
174 log_link_error_errno(link, r, "Failed to get prefix length: %m");
175 return;
176 }
177
178 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime_valid);
179 if (r < 0) {
180 log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
181 return;
182 }
183
184 r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred);
185 if (r < 0) {
186 log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
187 return;
188 }
189
190 r = address_new(&address);
191 if (r < 0) {
192 log_link_error_errno(link, r, "Could not allocate address: %m");
193 return;
194 }
195
196 address->family = AF_INET6;
197 r = sd_ndisc_router_prefix_get_address(rt, &address->in_addr.in6);
198 if (r < 0) {
199 log_link_error_errno(link, r, "Failed to get prefix address: %m");
200 return;
201 }
202
203 if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0)
204 memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
205 else {
206 /* see RFC4291 section 2.5.1 */
207 address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0];
208 address->in_addr.in6.s6_addr[8] ^= 1 << 1;
209 address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1];
210 address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
211 address->in_addr.in6.s6_addr[11] = 0xff;
212 address->in_addr.in6.s6_addr[12] = 0xfe;
213 address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
214 address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
215 address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
216 }
217 address->prefixlen = prefixlen;
218 address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
219 address->cinfo.ifa_prefered = lifetime_preferred;
220
221 /* see RFC4862 section 5.5.3.e */
222 r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address);
223 if (r > 0) {
224 lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
225 if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
226 address->cinfo.ifa_valid = lifetime_valid;
227 else if (lifetime_remaining <= NDISC_PREFIX_LFT_MIN)
228 address->cinfo.ifa_valid = lifetime_remaining;
229 else
230 address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN;
231 } else if (lifetime_valid > 0)
232 address->cinfo.ifa_valid = lifetime_valid;
233 else
234 return; /* see RFC4862 section 5.5.3.d */
235
236 if (address->cinfo.ifa_valid == 0)
237 return;
238
239 r = address_configure(address, link, ndisc_netlink_handler, true);
240 if (r < 0) {
241 log_link_warning_errno(link, r, "Could not set SLAAC address: %m");
242 link_enter_failed(link);
243 return;
244 }
245
246 link->ndisc_messages++;
247 }
248
249 static void ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
250 _cleanup_route_free_ Route *route = NULL;
251 usec_t time_now;
252 uint32_t lifetime;
253 unsigned prefixlen;
254 int r;
255
256 assert(link);
257 assert(rt);
258
259 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
260 if (r < 0) {
261 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
262 return;
263 }
264
265 r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
266 if (r < 0) {
267 log_link_error_errno(link, r, "Failed to get prefix length: %m");
268 return;
269 }
270
271 r = sd_ndisc_router_prefix_get_valid_lifetime(rt, &lifetime);
272 if (r < 0) {
273 log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
274 return;
275 }
276
277 r = route_new(&route);
278 if (r < 0) {
279 log_link_error_errno(link, r, "Could not allocate route: %m");
280 return;
281 }
282
283 route->family = AF_INET6;
284 route->table = link->network->ipv6_accept_ra_route_table;
285 route->priority = link->network->dhcp_route_metric;
286 route->protocol = RTPROT_RA;
287 route->flags = RTM_F_PREFIX;
288 route->dst_prefixlen = prefixlen;
289 route->lifetime = time_now + lifetime * USEC_PER_SEC;
290
291 r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
292 if (r < 0) {
293 log_link_error_errno(link, r, "Failed to get prefix address: %m");
294 return;
295 }
296
297 r = route_configure(route, link, ndisc_netlink_handler);
298 if (r < 0) {
299 log_link_warning_errno(link, r, "Could not set prefix route: %m");
300 link_enter_failed(link);
301 return;
302 }
303
304 link->ndisc_messages++;
305 }
306
307 static void ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
308 _cleanup_route_free_ Route *route = NULL;
309 struct in6_addr gateway;
310 uint32_t lifetime;
311 unsigned preference, prefixlen;
312 usec_t time_now;
313 int r;
314
315 assert(link);
316
317 r = sd_ndisc_router_route_get_lifetime(rt, &lifetime);
318 if (r < 0) {
319 log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
320 return;
321 }
322 if (lifetime == 0)
323 return;
324
325 r = sd_ndisc_router_get_address(rt, &gateway);
326 if (r < 0) {
327 log_link_warning_errno(link, r, "Failed to get gateway address from RA: %m");
328 return;
329 }
330
331 r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen);
332 if (r < 0) {
333 log_link_warning_errno(link, r, "Failed to get route prefix length: %m");
334 return;
335 }
336
337 r = sd_ndisc_router_route_get_preference(rt, &preference);
338 if (r < 0) {
339 log_link_warning_errno(link, r, "Failed to get default router preference from RA: %m");
340 return;
341 }
342
343 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
344 if (r < 0) {
345 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
346 return;
347 }
348
349 r = route_new(&route);
350 if (r < 0) {
351 log_link_error_errno(link, r, "Could not allocate route: %m");
352 return;
353 }
354
355 route->family = AF_INET6;
356 route->table = link->network->ipv6_accept_ra_route_table;
357 route->protocol = RTPROT_RA;
358 route->pref = preference;
359 route->gw.in6 = gateway;
360 route->dst_prefixlen = prefixlen;
361 route->lifetime = time_now + lifetime * USEC_PER_SEC;
362
363 r = sd_ndisc_router_route_get_address(rt, &route->dst.in6);
364 if (r < 0) {
365 log_link_error_errno(link, r, "Failed to get route address: %m");
366 return;
367 }
368
369 r = route_configure(route, link, ndisc_netlink_handler);
370 if (r < 0) {
371 log_link_warning_errno(link, r, "Could not set additional route: %m");
372 link_enter_failed(link);
373 return;
374 }
375
376 link->ndisc_messages++;
377 }
378
379 static void ndisc_rdnss_hash_func(const void *p, struct siphash *state) {
380 const NDiscRDNSS *x = p;
381
382 siphash24_compress(&x->address, sizeof(x->address), state);
383 }
384
385 static int ndisc_rdnss_compare_func(const void *_a, const void *_b) {
386 const NDiscRDNSS *a = _a, *b = _b;
387
388 return memcmp(&a->address, &b->address, sizeof(a->address));
389 }
390
391 static const struct hash_ops ndisc_rdnss_hash_ops = {
392 .hash = ndisc_rdnss_hash_func,
393 .compare = ndisc_rdnss_compare_func
394 };
395
396 static void ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
397 uint32_t lifetime;
398 const struct in6_addr *a;
399 usec_t time_now;
400 int i, n, r;
401
402 assert(link);
403 assert(rt);
404
405 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
406 if (r < 0) {
407 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
408 return;
409 }
410
411 r = sd_ndisc_router_rdnss_get_lifetime(rt, &lifetime);
412 if (r < 0) {
413 log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
414 return;
415 }
416
417 n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
418 if (n < 0) {
419 log_link_warning_errno(link, n, "Failed to get RDNSS addresses: %m");
420 return;
421 }
422
423 for (i = 0; i < n; i++) {
424 NDiscRDNSS d = {
425 .address = a[i]
426 }, *x;
427
428 if (lifetime == 0) {
429 (void) set_remove(link->ndisc_rdnss, &d);
430 link_dirty(link);
431 continue;
432 }
433
434 x = set_get(link->ndisc_rdnss, &d);
435 if (x) {
436 x->valid_until = time_now + lifetime * USEC_PER_SEC;
437 continue;
438 }
439
440 ndisc_vacuum(link);
441
442 if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
443 log_link_warning(link, "Too many RDNSS records per link, ignoring.");
444 continue;
445 }
446
447 r = set_ensure_allocated(&link->ndisc_rdnss, &ndisc_rdnss_hash_ops);
448 if (r < 0) {
449 log_oom();
450 return;
451 }
452
453 x = new0(NDiscRDNSS, 1);
454 if (!x) {
455 log_oom();
456 return;
457 }
458
459 x->address = a[i];
460 x->valid_until = time_now + lifetime * USEC_PER_SEC;
461
462 r = set_put(link->ndisc_rdnss, x);
463 if (r < 0) {
464 free(x);
465 log_oom();
466 return;
467 }
468
469 assert(r > 0);
470 link_dirty(link);
471 }
472 }
473
474 static void ndisc_dnssl_hash_func(const void *p, struct siphash *state) {
475 const NDiscDNSSL *x = p;
476
477 siphash24_compress(NDISC_DNSSL_DOMAIN(x), strlen(NDISC_DNSSL_DOMAIN(x)), state);
478 }
479
480 static int ndisc_dnssl_compare_func(const void *_a, const void *_b) {
481 const NDiscDNSSL *a = _a, *b = _b;
482
483 return strcmp(NDISC_DNSSL_DOMAIN(a), NDISC_DNSSL_DOMAIN(b));
484 }
485
486 static const struct hash_ops ndisc_dnssl_hash_ops = {
487 .hash = ndisc_dnssl_hash_func,
488 .compare = ndisc_dnssl_compare_func
489 };
490
491 static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
492 _cleanup_strv_free_ char **l = NULL;
493 uint32_t lifetime;
494 usec_t time_now;
495 char **i;
496 int r;
497
498 assert(link);
499 assert(rt);
500
501 r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
502 if (r < 0) {
503 log_link_warning_errno(link, r, "Failed to get RA timestamp: %m");
504 return;
505 }
506
507 r = sd_ndisc_router_dnssl_get_lifetime(rt, &lifetime);
508 if (r < 0) {
509 log_link_warning_errno(link, r, "Failed to get RDNSS lifetime: %m");
510 return;
511 }
512
513 r = sd_ndisc_router_dnssl_get_domains(rt, &l);
514 if (r < 0) {
515 log_link_warning_errno(link, r, "Failed to get RDNSS addresses: %m");
516 return;
517 }
518
519 STRV_FOREACH(i, l) {
520 _cleanup_free_ NDiscDNSSL *s;
521 NDiscDNSSL *x;
522
523 s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*i) + 1);
524 if (!s) {
525 log_oom();
526 return;
527 }
528
529 strcpy(NDISC_DNSSL_DOMAIN(s), *i);
530
531 if (lifetime == 0) {
532 (void) set_remove(link->ndisc_dnssl, s);
533 link_dirty(link);
534 continue;
535 }
536
537 x = set_get(link->ndisc_dnssl, s);
538 if (x) {
539 x->valid_until = time_now + lifetime * USEC_PER_SEC;
540 continue;
541 }
542
543 ndisc_vacuum(link);
544
545 if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
546 log_link_warning(link, "Too many DNSSL records per link, ignoring.");
547 continue;
548 }
549
550 r = set_ensure_allocated(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops);
551 if (r < 0) {
552 log_oom();
553 return;
554 }
555
556 s->valid_until = time_now + lifetime * USEC_PER_SEC;
557
558 r = set_put(link->ndisc_dnssl, s);
559 if (r < 0) {
560 log_oom();
561 return;
562 }
563
564 s = NULL;
565 assert(r > 0);
566 link_dirty(link);
567 }
568 }
569
570 static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
571 int r;
572
573 assert(link);
574 assert(rt);
575
576 r = sd_ndisc_router_option_rewind(rt);
577 for (;;) {
578 uint8_t type;
579
580 if (r < 0) {
581 log_link_warning_errno(link, r, "Failed to iterate through options: %m");
582 return;
583 }
584 if (r == 0) /* EOF */
585 break;
586
587 r = sd_ndisc_router_option_get_type(rt, &type);
588 if (r < 0) {
589 log_link_warning_errno(link, r, "Failed to get RA option type: %m");
590 return;
591 }
592
593 switch (type) {
594
595 case SD_NDISC_OPTION_PREFIX_INFORMATION: {
596 uint8_t flags;
597
598 r = sd_ndisc_router_prefix_get_flags(rt, &flags);
599 if (r < 0) {
600 log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
601 return;
602 }
603
604 if (flags & ND_OPT_PI_FLAG_ONLINK)
605 ndisc_router_process_onlink_prefix(link, rt);
606 if (flags & ND_OPT_PI_FLAG_AUTO)
607 ndisc_router_process_autonomous_prefix(link, rt);
608
609 break;
610 }
611
612 case SD_NDISC_OPTION_ROUTE_INFORMATION:
613 ndisc_router_process_route(link, rt);
614 break;
615
616 case SD_NDISC_OPTION_RDNSS:
617 if (link->network->ipv6_accept_ra_use_dns)
618 ndisc_router_process_rdnss(link, rt);
619 break;
620
621 case SD_NDISC_OPTION_DNSSL:
622 if (link->network->ipv6_accept_ra_use_dns)
623 ndisc_router_process_dnssl(link, rt);
624 break;
625 }
626
627 r = sd_ndisc_router_option_next(rt);
628 }
629 }
630
631 static void ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
632 uint64_t flags;
633 int r;
634
635 assert(link);
636 assert(link->network);
637 assert(link->manager);
638 assert(rt);
639
640 r = sd_ndisc_router_get_flags(rt, &flags);
641 if (r < 0) {
642 log_link_warning_errno(link, r, "Failed to get RA flags: %m");
643 return;
644 }
645
646 if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) {
647 /* (re)start DHCPv6 client in stateful or stateless mode according to RA flags */
648 r = dhcp6_request_address(link, !(flags & ND_RA_FLAG_MANAGED));
649 if (r < 0 && r != -EBUSY)
650 log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease on NDisc request: %m");
651 else
652 log_link_debug(link, "Acquiring DHCPv6 lease on NDisc request");
653 }
654
655 ndisc_router_process_default(link, rt);
656 ndisc_router_process_options(link, rt);
657 }
658
659 static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) {
660 Link *link = userdata;
661
662 assert(link);
663
664 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
665 return;
666
667 switch (event) {
668
669 case SD_NDISC_EVENT_ROUTER:
670 ndisc_router_handler(link, rt);
671 break;
672
673 case SD_NDISC_EVENT_TIMEOUT:
674 link->ndisc_configured = true;
675 link_check_ready(link);
676
677 break;
678 default:
679 log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event);
680 }
681 }
682
683 int ndisc_configure(Link *link) {
684 int r;
685
686 assert(link);
687
688 r = sd_ndisc_new(&link->ndisc);
689 if (r < 0)
690 return r;
691
692 r = sd_ndisc_attach_event(link->ndisc, NULL, 0);
693 if (r < 0)
694 return r;
695
696 r = sd_ndisc_set_mac(link->ndisc, &link->mac);
697 if (r < 0)
698 return r;
699
700 r = sd_ndisc_set_ifindex(link->ndisc, link->ifindex);
701 if (r < 0)
702 return r;
703
704 r = sd_ndisc_set_callback(link->ndisc, ndisc_handler, link);
705 if (r < 0)
706 return r;
707
708 return 0;
709 }
710
711 void ndisc_vacuum(Link *link) {
712 NDiscRDNSS *r;
713 NDiscDNSSL *d;
714 Iterator i;
715 usec_t time_now;
716
717 assert(link);
718
719 /* Removes all RDNSS and DNSSL entries whose validity time has passed */
720
721 time_now = now(clock_boottime_or_monotonic());
722
723 SET_FOREACH(r, link->ndisc_rdnss, i)
724 if (r->valid_until < time_now) {
725 free(set_remove(link->ndisc_rdnss, r));
726 link_dirty(link);
727 }
728
729 SET_FOREACH(d, link->ndisc_dnssl, i)
730 if (d->valid_until < time_now) {
731 free(set_remove(link->ndisc_dnssl, d));
732 link_dirty(link);
733 }
734 }
735
736 void ndisc_flush(Link *link) {
737 assert(link);
738
739 /* Removes all RDNSS and DNSSL entries, without exception */
740
741 link->ndisc_rdnss = set_free_free(link->ndisc_rdnss);
742 link->ndisc_dnssl = set_free_free(link->ndisc_dnssl);
743 }