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