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