]> git.proxmox.com Git - mirror_frr.git/blob - zebra/rtadv.c
Merge pull request #1346 from donaldsharp/apply_routemap
[mirror_frr.git] / zebra / rtadv.c
1 /* Router advertisement
2 * Copyright (C) 2016 Cumulus Networks
3 * Copyright (C) 2005 6WIND <jean-mickael.guerin@6wind.com>
4 * Copyright (C) 1999 Kunihiro Ishiguro
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * GNU Zebra 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 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <zebra.h>
24
25 #include "memory.h"
26 #include "zebra_memory.h"
27 #include "sockopt.h"
28 #include "thread.h"
29 #include "if.h"
30 #include "stream.h"
31 #include "log.h"
32 #include "prefix.h"
33 #include "linklist.h"
34 #include "command.h"
35 #include "privs.h"
36 #include "vrf.h"
37
38 #include "zebra/interface.h"
39 #include "zebra/rtadv.h"
40 #include "zebra/debug.h"
41 #include "zebra/rib.h"
42 #include "zebra/zserv.h"
43 #include "zebra/zebra_ns.h"
44 #include "zebra/zebra_vrf.h"
45
46 extern struct zebra_privs_t zserv_privs;
47
48 #if defined(HAVE_RTADV)
49
50 #ifdef OPEN_BSD
51 #include <netinet/icmp6.h>
52 #endif
53
54 /* If RFC2133 definition is used. */
55 #ifndef IPV6_JOIN_GROUP
56 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
57 #endif
58 #ifndef IPV6_LEAVE_GROUP
59 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
60 #endif
61
62 #define ALLNODE "ff02::1"
63 #define ALLROUTER "ff02::2"
64
65 /* Order is intentional. Matches RFC4191. This array is also used for
66 command matching, so only modify with care. */
67 const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0};
68
69 enum rtadv_event {
70 RTADV_START,
71 RTADV_STOP,
72 RTADV_TIMER,
73 RTADV_TIMER_MSEC,
74 RTADV_READ
75 };
76
77 static void rtadv_event(struct zebra_ns *, enum rtadv_event, int);
78
79 static int if_join_all_router(int, struct interface *);
80 static int if_leave_all_router(int, struct interface *);
81
82 static int rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex)
83 {
84 int ret = -1;
85 struct interface *iface;
86 struct zebra_if *zif;
87
88 iface = if_lookup_by_index_per_ns(zns, *ifindex);
89 if (iface && iface->info) {
90 zif = iface->info;
91 zif->ra_rcvd++;
92 ret = 0;
93 }
94 return ret;
95 }
96
97 static int rtadv_recv_packet(struct zebra_ns *zns, int sock, u_char *buf,
98 int buflen, struct sockaddr_in6 *from,
99 ifindex_t *ifindex, int *hoplimit)
100 {
101 int ret;
102 struct msghdr msg;
103 struct iovec iov;
104 struct cmsghdr *cmsgptr;
105 struct in6_addr dst;
106
107 char adata[1024];
108
109 /* Fill in message and iovec. */
110 memset(&msg, 0, sizeof(msg));
111 msg.msg_name = (void *)from;
112 msg.msg_namelen = sizeof(struct sockaddr_in6);
113 msg.msg_iov = &iov;
114 msg.msg_iovlen = 1;
115 msg.msg_control = (void *)adata;
116 msg.msg_controllen = sizeof adata;
117 iov.iov_base = buf;
118 iov.iov_len = buflen;
119
120 /* If recvmsg fail return minus value. */
121 ret = recvmsg(sock, &msg, 0);
122 if (ret < 0)
123 return ret;
124
125 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
126 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
127 /* I want interface index which this packet comes from. */
128 if (cmsgptr->cmsg_level == IPPROTO_IPV6
129 && cmsgptr->cmsg_type == IPV6_PKTINFO) {
130 struct in6_pktinfo *ptr;
131
132 ptr = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
133 *ifindex = ptr->ipi6_ifindex;
134 memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
135 }
136
137 /* Incoming packet's hop limit. */
138 if (cmsgptr->cmsg_level == IPPROTO_IPV6
139 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) {
140 int *hoptr = (int *)CMSG_DATA(cmsgptr);
141 *hoplimit = *hoptr;
142 }
143 }
144
145 rtadv_increment_received(zns, ifindex);
146 return ret;
147 }
148
149 #define RTADV_MSG_SIZE 4096
150
151 /* Send router advertisement packet. */
152 static void rtadv_send_packet(int sock, struct interface *ifp)
153 {
154 struct msghdr msg;
155 struct iovec iov;
156 struct cmsghdr *cmsgptr;
157 struct in6_pktinfo *pkt;
158 struct sockaddr_in6 addr;
159 static void *adata = NULL;
160 unsigned char buf[RTADV_MSG_SIZE];
161 struct nd_router_advert *rtadv;
162 int ret;
163 int len = 0;
164 struct zebra_if *zif;
165 struct rtadv_prefix *rprefix;
166 u_char all_nodes_addr[] = {0xff, 0x02, 0, 0, 0, 0, 0, 0,
167 0, 0, 0, 0, 0, 0, 0, 1};
168 struct listnode *node;
169 u_int16_t pkt_RouterLifetime;
170
171 /*
172 * Allocate control message bufffer. This is dynamic because
173 * CMSG_SPACE is not guaranteed not to call a function. Note that
174 * the size will be different on different architectures due to
175 * differing alignment rules.
176 */
177 if (adata == NULL) {
178 /* XXX Free on shutdown. */
179 adata = calloc(1, CMSG_SPACE(sizeof(struct in6_pktinfo)));
180
181 if (adata == NULL) {
182 zlog_err(
183 "rtadv_send_packet: can't malloc control data");
184 exit(-1);
185 }
186 }
187
188 /* Logging of packet. */
189 if (IS_ZEBRA_DEBUG_PACKET)
190 zlog_debug("%s(%u): Tx RA, socket %u", ifp->name, ifp->ifindex,
191 sock);
192
193 /* Fill in sockaddr_in6. */
194 memset(&addr, 0, sizeof(struct sockaddr_in6));
195 addr.sin6_family = AF_INET6;
196 #ifdef SIN6_LEN
197 addr.sin6_len = sizeof(struct sockaddr_in6);
198 #endif /* SIN6_LEN */
199 addr.sin6_port = htons(IPPROTO_ICMPV6);
200 IPV6_ADDR_COPY(&addr.sin6_addr, all_nodes_addr);
201
202 /* Fetch interface information. */
203 zif = ifp->info;
204
205 /* Make router advertisement message. */
206 rtadv = (struct nd_router_advert *)buf;
207
208 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
209 rtadv->nd_ra_code = 0;
210 rtadv->nd_ra_cksum = 0;
211
212 rtadv->nd_ra_curhoplimit = 64;
213
214 /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
215 rtadv->nd_ra_flags_reserved = zif->rtadv.AdvDefaultLifetime == 0
216 ? 0
217 : zif->rtadv.DefaultPreference;
218 rtadv->nd_ra_flags_reserved <<= 3;
219
220 if (zif->rtadv.AdvManagedFlag)
221 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
222 if (zif->rtadv.AdvOtherConfigFlag)
223 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
224 if (zif->rtadv.AdvHomeAgentFlag)
225 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
226 /* Note that according to Neighbor Discovery (RFC 4861 [18]),
227 * AdvDefaultLifetime is by default based on the value of
228 * MaxRtrAdvInterval. AdvDefaultLifetime is used in the Router Lifetime
229 * field of Router Advertisements. Given that this field is expressed
230 * in seconds, a small MaxRtrAdvInterval value can result in a zero
231 * value for this field. To prevent this, routers SHOULD keep
232 * AdvDefaultLifetime in at least one second, even if the use of
233 * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */
234 pkt_RouterLifetime =
235 zif->rtadv.AdvDefaultLifetime != -1
236 ? zif->rtadv.AdvDefaultLifetime
237 : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
238 rtadv->nd_ra_router_lifetime = htons(pkt_RouterLifetime);
239 rtadv->nd_ra_reachable = htonl(zif->rtadv.AdvReachableTime);
240 rtadv->nd_ra_retransmit = htonl(0);
241
242 len = sizeof(struct nd_router_advert);
243
244 /* If both the Home Agent Preference and Home Agent Lifetime are set to
245 * their default values specified above, this option SHOULD NOT be
246 * included in the Router Advertisement messages sent by this home
247 * agent. -- RFC6275, 7.4 */
248 if (zif->rtadv.AdvHomeAgentFlag
249 && (zif->rtadv.HomeAgentPreference
250 || zif->rtadv.HomeAgentLifetime != -1)) {
251 struct nd_opt_homeagent_info *ndopt_hai =
252 (struct nd_opt_homeagent_info *)(buf + len);
253 ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
254 ndopt_hai->nd_opt_hai_len = 1;
255 ndopt_hai->nd_opt_hai_reserved = 0;
256 ndopt_hai->nd_opt_hai_preference =
257 htons(zif->rtadv.HomeAgentPreference);
258 /* 16-bit unsigned integer. The lifetime associated with the
259 * home
260 * agent in units of seconds. The default value is the same as
261 * the
262 * Router Lifetime, as specified in the main body of the Router
263 * Advertisement. The maximum value corresponds to 18.2 hours.
264 * A
265 * value of 0 MUST NOT be used. -- RFC6275, 7.5 */
266 ndopt_hai->nd_opt_hai_lifetime =
267 htons(zif->rtadv.HomeAgentLifetime != -1
268 ? zif->rtadv.HomeAgentLifetime
269 : MAX(1, pkt_RouterLifetime) /* 0 is OK
270 for RL,
271 but not
272 for HAL*/
273 );
274 len += sizeof(struct nd_opt_homeagent_info);
275 }
276
277 if (zif->rtadv.AdvIntervalOption) {
278 struct nd_opt_adv_interval *ndopt_adv =
279 (struct nd_opt_adv_interval *)(buf + len);
280 ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL;
281 ndopt_adv->nd_opt_ai_len = 1;
282 ndopt_adv->nd_opt_ai_reserved = 0;
283 ndopt_adv->nd_opt_ai_interval =
284 htonl(zif->rtadv.MaxRtrAdvInterval);
285 len += sizeof(struct nd_opt_adv_interval);
286 }
287
288 /* Fill in prefix. */
289 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvPrefixList, node, rprefix)) {
290 struct nd_opt_prefix_info *pinfo;
291
292 pinfo = (struct nd_opt_prefix_info *)(buf + len);
293
294 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
295 pinfo->nd_opt_pi_len = 4;
296 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
297
298 pinfo->nd_opt_pi_flags_reserved = 0;
299 if (rprefix->AdvOnLinkFlag)
300 pinfo->nd_opt_pi_flags_reserved |=
301 ND_OPT_PI_FLAG_ONLINK;
302 if (rprefix->AdvAutonomousFlag)
303 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
304 if (rprefix->AdvRouterAddressFlag)
305 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
306
307 pinfo->nd_opt_pi_valid_time = htonl(rprefix->AdvValidLifetime);
308 pinfo->nd_opt_pi_preferred_time =
309 htonl(rprefix->AdvPreferredLifetime);
310 pinfo->nd_opt_pi_reserved2 = 0;
311
312 IPV6_ADDR_COPY(&pinfo->nd_opt_pi_prefix,
313 &rprefix->prefix.prefix);
314
315 #ifdef DEBUG
316 {
317 u_char buf[INET6_ADDRSTRLEN];
318
319 zlog_debug("DEBUG %s",
320 inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
321 buf, INET6_ADDRSTRLEN));
322 }
323 #endif /* DEBUG */
324
325 len += sizeof(struct nd_opt_prefix_info);
326 }
327
328 /* Hardware address. */
329 if (ifp->hw_addr_len != 0) {
330 buf[len++] = ND_OPT_SOURCE_LINKADDR;
331
332 /* Option length should be rounded up to next octet if
333 the link address does not end on an octet boundary. */
334 buf[len++] = (ifp->hw_addr_len + 9) >> 3;
335
336 memcpy(buf + len, ifp->hw_addr, ifp->hw_addr_len);
337 len += ifp->hw_addr_len;
338
339 /* Pad option to end on an octet boundary. */
340 memset(buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7);
341 len += -(ifp->hw_addr_len + 2) & 0x7;
342 }
343
344 /* MTU */
345 if (zif->rtadv.AdvLinkMTU) {
346 struct nd_opt_mtu *opt = (struct nd_opt_mtu *)(buf + len);
347 opt->nd_opt_mtu_type = ND_OPT_MTU;
348 opt->nd_opt_mtu_len = 1;
349 opt->nd_opt_mtu_reserved = 0;
350 opt->nd_opt_mtu_mtu = htonl(zif->rtadv.AdvLinkMTU);
351 len += sizeof(struct nd_opt_mtu);
352 }
353
354 msg.msg_name = (void *)&addr;
355 msg.msg_namelen = sizeof(struct sockaddr_in6);
356 msg.msg_iov = &iov;
357 msg.msg_iovlen = 1;
358 msg.msg_control = (void *)adata;
359 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
360 msg.msg_flags = 0;
361 iov.iov_base = buf;
362 iov.iov_len = len;
363
364 cmsgptr = ZCMSG_FIRSTHDR(&msg);
365 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
366 cmsgptr->cmsg_level = IPPROTO_IPV6;
367 cmsgptr->cmsg_type = IPV6_PKTINFO;
368
369 pkt = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
370 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
371 pkt->ipi6_ifindex = ifp->ifindex;
372
373 ret = sendmsg(sock, &msg, 0);
374 if (ret < 0) {
375 zlog_err("%s(%u): Tx RA failed, socket %u error %d (%s)",
376 ifp->name, ifp->ifindex, sock, errno,
377 safe_strerror(errno));
378 } else
379 zif->ra_sent++;
380 }
381
382 static int rtadv_timer(struct thread *thread)
383 {
384 struct zebra_ns *zns = THREAD_ARG(thread);
385 struct vrf *vrf;
386 struct interface *ifp;
387 struct zebra_if *zif;
388 int period;
389
390 zns->rtadv.ra_timer = NULL;
391 if (zns->rtadv.adv_msec_if_count == 0) {
392 period = 1000; /* 1 s */
393 rtadv_event(zns, RTADV_TIMER, 1 /* 1 s */);
394 } else {
395 period = 10; /* 10 ms */
396 rtadv_event(zns, RTADV_TIMER_MSEC, 10 /* 10 ms */);
397 }
398
399 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
400 FOR_ALL_INTERFACES (vrf, ifp) {
401 if (if_is_loopback(ifp)
402 || CHECK_FLAG(ifp->status,
403 ZEBRA_INTERFACE_VRF_LOOPBACK)
404 || !if_is_operative(ifp))
405 continue;
406
407 zif = ifp->info;
408
409 if (zif->rtadv.AdvSendAdvertisements) {
410 if (zif->rtadv.inFastRexmit) {
411 /* We assume we fast rexmit every sec so
412 * no
413 * additional vars */
414 if (--zif->rtadv.NumFastReXmitsRemain
415 <= 0)
416 zif->rtadv.inFastRexmit = 0;
417
418 if (IS_ZEBRA_DEBUG_SEND)
419 zlog_debug(
420 "Fast RA Rexmit on interface %s",
421 ifp->name);
422
423 rtadv_send_packet(zns->rtadv.sock, ifp);
424 } else {
425 zif->rtadv.AdvIntervalTimer -= period;
426 if (zif->rtadv.AdvIntervalTimer <= 0) {
427 /* FIXME: using
428 MaxRtrAdvInterval each
429 time isn't what section
430 6.2.4 of RFC4861 tells to do.
431 */
432 zif->rtadv.AdvIntervalTimer =
433 zif->rtadv
434 .MaxRtrAdvInterval;
435 rtadv_send_packet(
436 zns->rtadv.sock, ifp);
437 }
438 }
439 }
440 }
441
442 return 0;
443 }
444
445 static void rtadv_process_solicit(struct interface *ifp)
446 {
447 struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
448 struct zebra_ns *zns = zvrf->zns;
449
450 assert(zns);
451 rtadv_send_packet(zns->rtadv.sock, ifp);
452 }
453
454 static void rtadv_process_advert(u_char *msg, unsigned int len,
455 struct interface *ifp,
456 struct sockaddr_in6 *addr)
457 {
458 struct nd_router_advert *radvert;
459 char addr_str[INET6_ADDRSTRLEN];
460 struct zebra_if *zif;
461 struct prefix p;
462
463 zif = ifp->info;
464
465 inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
466
467 if (len < sizeof(struct nd_router_advert)) {
468 zlog_warn("%s(%u): Rx RA with invalid length %d from %s",
469 ifp->name, ifp->ifindex, len, addr_str);
470 return;
471 }
472 if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
473 zlog_warn(
474 "%s(%u): Rx RA with non-linklocal source address from %s",
475 ifp->name, ifp->ifindex, addr_str);
476 return;
477 }
478
479 radvert = (struct nd_router_advert *)msg;
480
481 if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit)
482 && (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit)) {
483 zlog_warn(
484 "%s(%u): Rx RA - our AdvCurHopLimit doesn't agree with %s",
485 ifp->name, ifp->ifindex, addr_str);
486 }
487
488 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
489 && !zif->rtadv.AdvManagedFlag) {
490 zlog_warn(
491 "%s(%u): Rx RA - our AdvManagedFlag doesn't agree with %s",
492 ifp->name, ifp->ifindex, addr_str);
493 }
494
495 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
496 && !zif->rtadv.AdvOtherConfigFlag) {
497 zlog_warn(
498 "%s(%u): Rx RA - our AdvOtherConfigFlag doesn't agree with %s",
499 ifp->name, ifp->ifindex, addr_str);
500 }
501
502 if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime)
503 && (ntohl(radvert->nd_ra_reachable)
504 != zif->rtadv.AdvReachableTime)) {
505 zlog_warn(
506 "%s(%u): Rx RA - our AdvReachableTime doesn't agree with %s",
507 ifp->name, ifp->ifindex, addr_str);
508 }
509
510 if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer)
511 && (ntohl(radvert->nd_ra_retransmit)
512 != (unsigned int)zif->rtadv.AdvRetransTimer)) {
513 zlog_warn(
514 "%s(%u): Rx RA - our AdvRetransTimer doesn't agree with %s",
515 ifp->name, ifp->ifindex, addr_str);
516 }
517
518 /* Create entry for neighbor if not known. */
519 p.family = AF_INET6;
520 IPV6_ADDR_COPY(&p.u.prefix, &addr->sin6_addr);
521 p.prefixlen = IPV6_MAX_PREFIXLEN;
522
523 if (!nbr_connected_check(ifp, &p))
524 nbr_connected_add_ipv6(ifp, &addr->sin6_addr);
525 }
526
527
528 static void rtadv_process_packet(u_char *buf, unsigned int len,
529 ifindex_t ifindex, int hoplimit,
530 struct sockaddr_in6 *from,
531 struct zebra_ns *zns)
532 {
533 struct icmp6_hdr *icmph;
534 struct interface *ifp;
535 struct zebra_if *zif;
536 char addr_str[INET6_ADDRSTRLEN];
537
538 inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN);
539
540 /* Interface search. */
541 ifp = if_lookup_by_index_per_ns(zns, ifindex);
542 if (ifp == NULL) {
543 zlog_warn("RA/RS received on unknown IF %u from %s", ifindex,
544 addr_str);
545 return;
546 }
547
548 if (IS_ZEBRA_DEBUG_PACKET)
549 zlog_debug("%s(%u): Rx RA/RS len %d from %s", ifp->name,
550 ifp->ifindex, len, addr_str);
551
552 if (if_is_loopback(ifp)
553 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))
554 return;
555
556 /* Check interface configuration. */
557 zif = ifp->info;
558 if (!zif->rtadv.AdvSendAdvertisements)
559 return;
560
561 /* ICMP message length check. */
562 if (len < sizeof(struct icmp6_hdr)) {
563 zlog_warn("%s(%u): Rx RA with Invalid ICMPV6 packet length %d",
564 ifp->name, ifp->ifindex, len);
565 return;
566 }
567
568 icmph = (struct icmp6_hdr *)buf;
569
570 /* ICMP message type check. */
571 if (icmph->icmp6_type != ND_ROUTER_SOLICIT
572 && icmph->icmp6_type != ND_ROUTER_ADVERT) {
573 zlog_warn("%s(%u): Rx RA - Unwanted ICMPV6 message type %d",
574 ifp->name, ifp->ifindex, icmph->icmp6_type);
575 return;
576 }
577
578 /* Hoplimit check. */
579 if (hoplimit >= 0 && hoplimit != 255) {
580 zlog_warn("%s(%u): Rx RA - Invalid hoplimit %d", ifp->name,
581 ifp->ifindex, hoplimit);
582 return;
583 }
584
585 /* Check ICMP message type. */
586 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
587 rtadv_process_solicit(ifp);
588 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
589 rtadv_process_advert(buf, len, ifp, from);
590
591 return;
592 }
593
594 static int rtadv_read(struct thread *thread)
595 {
596 int sock;
597 int len;
598 u_char buf[RTADV_MSG_SIZE];
599 struct sockaddr_in6 from;
600 ifindex_t ifindex = 0;
601 int hoplimit = -1;
602 struct zebra_ns *zns = THREAD_ARG(thread);
603
604 sock = THREAD_FD(thread);
605 zns->rtadv.ra_read = NULL;
606
607 /* Register myself. */
608 rtadv_event(zns, RTADV_READ, sock);
609
610 len = rtadv_recv_packet(zns, sock, buf, sizeof(buf), &from, &ifindex,
611 &hoplimit);
612
613 if (len < 0) {
614 zlog_warn("RA/RS recv failed, socket %u error %s", sock,
615 safe_strerror(errno));
616 return len;
617 }
618
619 rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zns);
620
621 return 0;
622 }
623
624 static int rtadv_make_socket(void)
625 {
626 int sock;
627 int ret = 0;
628 struct icmp6_filter filter;
629
630 if (zserv_privs.change(ZPRIVS_RAISE))
631 zlog_err("rtadv_make_socket: could not raise privs, %s",
632 safe_strerror(errno));
633
634 sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
635
636 if (zserv_privs.change(ZPRIVS_LOWER))
637 zlog_err("rtadv_make_socket: could not lower privs, %s",
638 safe_strerror(errno));
639
640 if (sock < 0) {
641 return -1;
642 }
643
644 ret = setsockopt_ipv6_pktinfo(sock, 1);
645 if (ret < 0) {
646 close(sock);
647 return ret;
648 }
649 ret = setsockopt_ipv6_multicast_loop(sock, 0);
650 if (ret < 0) {
651 close(sock);
652 return ret;
653 }
654 ret = setsockopt_ipv6_unicast_hops(sock, 255);
655 if (ret < 0) {
656 close(sock);
657 return ret;
658 }
659 ret = setsockopt_ipv6_multicast_hops(sock, 255);
660 if (ret < 0) {
661 close(sock);
662 return ret;
663 }
664 ret = setsockopt_ipv6_hoplimit(sock, 1);
665 if (ret < 0) {
666 close(sock);
667 return ret;
668 }
669
670 ICMP6_FILTER_SETBLOCKALL(&filter);
671 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
672 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
673
674 ret = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
675 sizeof(struct icmp6_filter));
676 if (ret < 0) {
677 zlog_info("ICMP6_FILTER set fail: %s", safe_strerror(errno));
678 return ret;
679 }
680
681 return sock;
682 }
683
684 static struct rtadv_prefix *rtadv_prefix_new(void)
685 {
686 return XCALLOC(MTYPE_RTADV_PREFIX, sizeof(struct rtadv_prefix));
687 }
688
689 static void rtadv_prefix_free(struct rtadv_prefix *rtadv_prefix)
690 {
691 XFREE(MTYPE_RTADV_PREFIX, rtadv_prefix);
692 }
693
694 static struct rtadv_prefix *rtadv_prefix_lookup(struct list *rplist,
695 struct prefix_ipv6 *p)
696 {
697 struct listnode *node;
698 struct rtadv_prefix *rprefix;
699
700 for (ALL_LIST_ELEMENTS_RO(rplist, node, rprefix))
701 if (prefix_same((struct prefix *)&rprefix->prefix,
702 (struct prefix *)p))
703 return rprefix;
704 return NULL;
705 }
706
707 static struct rtadv_prefix *rtadv_prefix_get(struct list *rplist,
708 struct prefix_ipv6 *p)
709 {
710 struct rtadv_prefix *rprefix;
711
712 rprefix = rtadv_prefix_lookup(rplist, p);
713 if (rprefix)
714 return rprefix;
715
716 rprefix = rtadv_prefix_new();
717 memcpy(&rprefix->prefix, p, sizeof(struct prefix_ipv6));
718 listnode_add(rplist, rprefix);
719
720 return rprefix;
721 }
722
723 static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp)
724 {
725 struct rtadv_prefix *rprefix;
726
727 rprefix = rtadv_prefix_get(zif->rtadv.AdvPrefixList, &rp->prefix);
728
729 /* Set parameters. */
730 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
731 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
732 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
733 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
734 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
735 }
736
737 static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp)
738 {
739 struct rtadv_prefix *rprefix;
740
741 rprefix = rtadv_prefix_lookup(zif->rtadv.AdvPrefixList, &rp->prefix);
742 if (rprefix != NULL) {
743 listnode_delete(zif->rtadv.AdvPrefixList, (void *)rprefix);
744 rtadv_prefix_free(rprefix);
745 return 1;
746 } else
747 return 0;
748 }
749
750 static void ipv6_nd_suppress_ra_set(struct interface *ifp,
751 ipv6_nd_suppress_ra_status status)
752 {
753 struct zebra_if *zif;
754 struct zebra_vrf *zvrf;
755 struct zebra_ns *zns;
756
757 zif = ifp->info;
758 zvrf = vrf_info_lookup(ifp->vrf_id);
759 zns = zvrf->zns;
760
761 if (status == RA_SUPPRESS) {
762 /* RA is currently enabled */
763 if (zif->rtadv.AdvSendAdvertisements) {
764 zif->rtadv.AdvSendAdvertisements = 0;
765 zif->rtadv.AdvIntervalTimer = 0;
766 zns->rtadv.adv_if_count--;
767
768 if_leave_all_router(zns->rtadv.sock, ifp);
769
770 if (zns->rtadv.adv_if_count == 0)
771 rtadv_event(zns, RTADV_STOP, 0);
772 }
773 } else {
774 if (!zif->rtadv.AdvSendAdvertisements) {
775 zif->rtadv.AdvSendAdvertisements = 1;
776 zif->rtadv.AdvIntervalTimer = 0;
777 zns->rtadv.adv_if_count++;
778
779 if (zif->rtadv.MaxRtrAdvInterval >= 1000) {
780 /* Enable Fast RA only when RA interval is in
781 * secs */
782 zif->rtadv.inFastRexmit = 1;
783 zif->rtadv.NumFastReXmitsRemain =
784 RTADV_NUM_FAST_REXMITS;
785 }
786
787 if_join_all_router(zns->rtadv.sock, ifp);
788
789 if (zns->rtadv.adv_if_count == 1)
790 rtadv_event(zns, RTADV_START, zns->rtadv.sock);
791 }
792 }
793 }
794
795 /*
796 * Handle client (BGP) message to enable or disable IPv6 RA on an interface.
797 * Note that while the client could request RA on an interface on which the
798 * operator has not enabled RA, RA won't be disabled upon client request
799 * if the operator has explicitly enabled RA. The enable request can also
800 * specify a RA interval (in seconds).
801 */
802 void zebra_interface_radv_set(struct zserv *client, u_short length,
803 struct zebra_vrf *zvrf, int enable)
804 {
805 struct stream *s;
806 unsigned int ifindex;
807 struct interface *ifp;
808 struct zebra_if *zif;
809 int ra_interval;
810
811 s = client->ibuf;
812
813 /* Get interface index and RA interval. */
814 ifindex = stream_getl(s);
815 ra_interval = stream_getl(s);
816
817 if (IS_ZEBRA_DEBUG_EVENT)
818 zlog_debug("%u: IF %u RA %s from client %s, interval %ds",
819 zvrf_id(zvrf), ifindex,
820 enable ? "enable" : "disable",
821 zebra_route_string(client->proto), ra_interval);
822
823 /* Locate interface and check VRF match. */
824 ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex);
825 if (!ifp) {
826 zlog_warn("%u: IF %u RA %s client %s - interface unknown",
827 zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
828 zebra_route_string(client->proto));
829 return;
830 }
831 if (ifp->vrf_id != zvrf_id(zvrf)) {
832 zlog_warn("%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
833 zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
834 zebra_route_string(client->proto), ifp->vrf_id);
835 return;
836 }
837
838 zif = ifp->info;
839 if (enable) {
840 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
841 if (ra_interval
842 && (ra_interval * 1000) < zif->rtadv.MaxRtrAdvInterval)
843 zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000;
844 } else {
845 if (!zif->rtadv.configured) {
846 zif->rtadv.MaxRtrAdvInterval =
847 RTADV_MAX_RTR_ADV_INTERVAL;
848 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
849 }
850 }
851 }
852
853 DEFUN (ipv6_nd_suppress_ra,
854 ipv6_nd_suppress_ra_cmd,
855 "ipv6 nd suppress-ra",
856 "Interface IPv6 config commands\n"
857 "Neighbor discovery\n"
858 "Suppress Router Advertisement\n")
859 {
860 VTY_DECLVAR_CONTEXT(interface, ifp);
861 struct zebra_if *zif = ifp->info;
862
863 if (if_is_loopback(ifp)
864 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
865 vty_out(vty,
866 "Cannot configure IPv6 Router Advertisements on this interface\n");
867 return CMD_WARNING_CONFIG_FAILED;
868 }
869
870 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
871 zif->rtadv.configured = 0;
872 return CMD_SUCCESS;
873 }
874
875 DEFUN (no_ipv6_nd_suppress_ra,
876 no_ipv6_nd_suppress_ra_cmd,
877 "no ipv6 nd suppress-ra",
878 NO_STR
879 "Interface IPv6 config commands\n"
880 "Neighbor discovery\n"
881 "Suppress Router Advertisement\n")
882 {
883 VTY_DECLVAR_CONTEXT(interface, ifp);
884 struct zebra_if *zif = ifp->info;
885
886 if (if_is_loopback(ifp)
887 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
888 vty_out(vty,
889 "Cannot configure IPv6 Router Advertisements on this interface\n");
890 return CMD_WARNING_CONFIG_FAILED;
891 }
892
893 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
894 zif->rtadv.configured = 1;
895 return CMD_SUCCESS;
896 }
897
898 DEFUN (ipv6_nd_ra_interval_msec,
899 ipv6_nd_ra_interval_msec_cmd,
900 "ipv6 nd ra-interval msec (70-1800000)",
901 "Interface IPv6 config commands\n"
902 "Neighbor discovery\n"
903 "Router Advertisement interval\n"
904 "Router Advertisement interval in milliseconds\n"
905 "Router Advertisement interval in milliseconds\n")
906 {
907 int idx_number = 4;
908 VTY_DECLVAR_CONTEXT(interface, ifp);
909 unsigned interval;
910 struct zebra_if *zif = ifp->info;
911 struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
912 struct zebra_ns *zns;
913
914 zns = zvrf->zns;
915 interval = strtoul(argv[idx_number]->arg, NULL, 10);
916 if ((zif->rtadv.AdvDefaultLifetime != -1
917 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) {
918 vty_out(vty,
919 "This ra-interval would conflict with configured ra-lifetime!\n");
920 return CMD_WARNING_CONFIG_FAILED;
921 }
922
923 if (zif->rtadv.MaxRtrAdvInterval % 1000)
924 zns->rtadv.adv_msec_if_count--;
925
926 if (interval % 1000)
927 zns->rtadv.adv_msec_if_count++;
928
929 zif->rtadv.MaxRtrAdvInterval = interval;
930 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
931 zif->rtadv.AdvIntervalTimer = 0;
932
933 return CMD_SUCCESS;
934 }
935
936 DEFUN (ipv6_nd_ra_interval,
937 ipv6_nd_ra_interval_cmd,
938 "ipv6 nd ra-interval (1-1800)",
939 "Interface IPv6 config commands\n"
940 "Neighbor discovery\n"
941 "Router Advertisement interval\n"
942 "Router Advertisement interval in seconds\n")
943 {
944 int idx_number = 3;
945 VTY_DECLVAR_CONTEXT(interface, ifp);
946 unsigned interval;
947 struct zebra_if *zif = ifp->info;
948 struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
949 struct zebra_ns *zns;
950
951 zns = zvrf->zns;
952 interval = strtoul(argv[idx_number]->arg, NULL, 10);
953 if ((zif->rtadv.AdvDefaultLifetime != -1
954 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) {
955 vty_out(vty,
956 "This ra-interval would conflict with configured ra-lifetime!\n");
957 return CMD_WARNING_CONFIG_FAILED;
958 }
959
960 if (zif->rtadv.MaxRtrAdvInterval % 1000)
961 zns->rtadv.adv_msec_if_count--;
962
963 /* convert to milliseconds */
964 interval = interval * 1000;
965
966 zif->rtadv.MaxRtrAdvInterval = interval;
967 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
968 zif->rtadv.AdvIntervalTimer = 0;
969
970 return CMD_SUCCESS;
971 }
972
973 DEFUN (no_ipv6_nd_ra_interval,
974 no_ipv6_nd_ra_interval_cmd,
975 "no ipv6 nd ra-interval [<(1-1800)|msec (1-1800000)>]",
976 NO_STR
977 "Interface IPv6 config commands\n"
978 "Neighbor discovery\n"
979 "Router Advertisement interval\n"
980 "Router Advertisement interval in seconds\n"
981 "Specify millisecond router advertisement interval\n"
982 "Router Advertisement interval in milliseconds\n")
983 {
984 VTY_DECLVAR_CONTEXT(interface, ifp);
985 struct zebra_if *zif = ifp->info;
986 struct zebra_vrf *zvrf;
987 struct zebra_ns *zns;
988
989 zvrf = vrf_info_lookup(ifp->vrf_id);
990 zns = zvrf->zns;
991
992 if (zif->rtadv.MaxRtrAdvInterval % 1000)
993 zns->rtadv.adv_msec_if_count--;
994
995 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
996 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
997 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
998
999 return CMD_SUCCESS;
1000 }
1001
1002 DEFUN (ipv6_nd_ra_lifetime,
1003 ipv6_nd_ra_lifetime_cmd,
1004 "ipv6 nd ra-lifetime (0-9000)",
1005 "Interface IPv6 config commands\n"
1006 "Neighbor discovery\n"
1007 "Router lifetime\n"
1008 "Router lifetime in seconds (0 stands for a non-default gw)\n")
1009 {
1010 int idx_number = 3;
1011 VTY_DECLVAR_CONTEXT(interface, ifp);
1012 struct zebra_if *zif = ifp->info;
1013 int lifetime;
1014
1015 lifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1016
1017 /* The value to be placed in the Router Lifetime field
1018 * of Router Advertisements sent from the interface,
1019 * in seconds. MUST be either zero or between
1020 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
1021 if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) {
1022 vty_out(vty,
1023 "This ra-lifetime would conflict with configured ra-interval\n");
1024 return CMD_WARNING_CONFIG_FAILED;
1025 }
1026
1027 zif->rtadv.AdvDefaultLifetime = lifetime;
1028
1029 return CMD_SUCCESS;
1030 }
1031
1032 DEFUN (no_ipv6_nd_ra_lifetime,
1033 no_ipv6_nd_ra_lifetime_cmd,
1034 "no ipv6 nd ra-lifetime [(0-9000)]",
1035 NO_STR
1036 "Interface IPv6 config commands\n"
1037 "Neighbor discovery\n"
1038 "Router lifetime\n"
1039 "Router lifetime in seconds (0 stands for a non-default gw)\n")
1040 {
1041 VTY_DECLVAR_CONTEXT(interface, ifp);
1042 struct zebra_if *zif = ifp->info;
1043
1044 zif->rtadv.AdvDefaultLifetime = -1;
1045
1046 return CMD_SUCCESS;
1047 }
1048
1049 DEFUN (ipv6_nd_reachable_time,
1050 ipv6_nd_reachable_time_cmd,
1051 "ipv6 nd reachable-time (1-3600000)",
1052 "Interface IPv6 config commands\n"
1053 "Neighbor discovery\n"
1054 "Reachable time\n"
1055 "Reachable time in milliseconds\n")
1056 {
1057 int idx_number = 3;
1058 VTY_DECLVAR_CONTEXT(interface, ifp);
1059 struct zebra_if *zif = ifp->info;
1060 zif->rtadv.AdvReachableTime = strtoul(argv[idx_number]->arg, NULL, 10);
1061 return CMD_SUCCESS;
1062 }
1063
1064 DEFUN (no_ipv6_nd_reachable_time,
1065 no_ipv6_nd_reachable_time_cmd,
1066 "no ipv6 nd reachable-time [(1-3600000)]",
1067 NO_STR
1068 "Interface IPv6 config commands\n"
1069 "Neighbor discovery\n"
1070 "Reachable time\n"
1071 "Reachable time in milliseconds\n")
1072 {
1073 VTY_DECLVAR_CONTEXT(interface, ifp);
1074 struct zebra_if *zif = ifp->info;
1075
1076 zif->rtadv.AdvReachableTime = 0;
1077
1078 return CMD_SUCCESS;
1079 }
1080
1081 DEFUN (ipv6_nd_homeagent_preference,
1082 ipv6_nd_homeagent_preference_cmd,
1083 "ipv6 nd home-agent-preference (0-65535)",
1084 "Interface IPv6 config commands\n"
1085 "Neighbor discovery\n"
1086 "Home Agent preference\n"
1087 "preference value (default is 0, least preferred)\n")
1088 {
1089 int idx_number = 3;
1090 VTY_DECLVAR_CONTEXT(interface, ifp);
1091 struct zebra_if *zif = ifp->info;
1092 zif->rtadv.HomeAgentPreference =
1093 strtoul(argv[idx_number]->arg, NULL, 10);
1094 return CMD_SUCCESS;
1095 }
1096
1097 DEFUN (no_ipv6_nd_homeagent_preference,
1098 no_ipv6_nd_homeagent_preference_cmd,
1099 "no ipv6 nd home-agent-preference [(0-65535)]",
1100 NO_STR
1101 "Interface IPv6 config commands\n"
1102 "Neighbor discovery\n"
1103 "Home Agent preference\n"
1104 "preference value (default is 0, least preferred)\n")
1105 {
1106 VTY_DECLVAR_CONTEXT(interface, ifp);
1107 struct zebra_if *zif = ifp->info;
1108
1109 zif->rtadv.HomeAgentPreference = 0;
1110
1111 return CMD_SUCCESS;
1112 }
1113
1114 DEFUN (ipv6_nd_homeagent_lifetime,
1115 ipv6_nd_homeagent_lifetime_cmd,
1116 "ipv6 nd home-agent-lifetime (0-65520)",
1117 "Interface IPv6 config commands\n"
1118 "Neighbor discovery\n"
1119 "Home Agent lifetime\n"
1120 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
1121 {
1122 int idx_number = 3;
1123 VTY_DECLVAR_CONTEXT(interface, ifp);
1124 struct zebra_if *zif = ifp->info;
1125 zif->rtadv.HomeAgentLifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1126 return CMD_SUCCESS;
1127 }
1128
1129 DEFUN (no_ipv6_nd_homeagent_lifetime,
1130 no_ipv6_nd_homeagent_lifetime_cmd,
1131 "no ipv6 nd home-agent-lifetime [(0-65520)]",
1132 NO_STR
1133 "Interface IPv6 config commands\n"
1134 "Neighbor discovery\n"
1135 "Home Agent lifetime\n"
1136 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
1137 {
1138 VTY_DECLVAR_CONTEXT(interface, ifp);
1139 struct zebra_if *zif = ifp->info;
1140
1141 zif->rtadv.HomeAgentLifetime = -1;
1142
1143 return CMD_SUCCESS;
1144 }
1145
1146 DEFUN (ipv6_nd_managed_config_flag,
1147 ipv6_nd_managed_config_flag_cmd,
1148 "ipv6 nd managed-config-flag",
1149 "Interface IPv6 config commands\n"
1150 "Neighbor discovery\n"
1151 "Managed address configuration flag\n")
1152 {
1153 VTY_DECLVAR_CONTEXT(interface, ifp);
1154 struct zebra_if *zif = ifp->info;
1155
1156 zif->rtadv.AdvManagedFlag = 1;
1157
1158 return CMD_SUCCESS;
1159 }
1160
1161 DEFUN (no_ipv6_nd_managed_config_flag,
1162 no_ipv6_nd_managed_config_flag_cmd,
1163 "no ipv6 nd managed-config-flag",
1164 NO_STR
1165 "Interface IPv6 config commands\n"
1166 "Neighbor discovery\n"
1167 "Managed address configuration flag\n")
1168 {
1169 VTY_DECLVAR_CONTEXT(interface, ifp);
1170 struct zebra_if *zif = ifp->info;
1171
1172 zif->rtadv.AdvManagedFlag = 0;
1173
1174 return CMD_SUCCESS;
1175 }
1176
1177 DEFUN (ipv6_nd_homeagent_config_flag,
1178 ipv6_nd_homeagent_config_flag_cmd,
1179 "ipv6 nd home-agent-config-flag",
1180 "Interface IPv6 config commands\n"
1181 "Neighbor discovery\n"
1182 "Home Agent configuration flag\n")
1183 {
1184 VTY_DECLVAR_CONTEXT(interface, ifp);
1185 struct zebra_if *zif = ifp->info;
1186
1187 zif->rtadv.AdvHomeAgentFlag = 1;
1188
1189 return CMD_SUCCESS;
1190 }
1191
1192 DEFUN (no_ipv6_nd_homeagent_config_flag,
1193 no_ipv6_nd_homeagent_config_flag_cmd,
1194 "no ipv6 nd home-agent-config-flag",
1195 NO_STR
1196 "Interface IPv6 config commands\n"
1197 "Neighbor discovery\n"
1198 "Home Agent configuration flag\n")
1199 {
1200 VTY_DECLVAR_CONTEXT(interface, ifp);
1201 struct zebra_if *zif = ifp->info;
1202
1203 zif->rtadv.AdvHomeAgentFlag = 0;
1204
1205 return CMD_SUCCESS;
1206 }
1207
1208 DEFUN (ipv6_nd_adv_interval_config_option,
1209 ipv6_nd_adv_interval_config_option_cmd,
1210 "ipv6 nd adv-interval-option",
1211 "Interface IPv6 config commands\n"
1212 "Neighbor discovery\n"
1213 "Advertisement Interval Option\n")
1214 {
1215 VTY_DECLVAR_CONTEXT(interface, ifp);
1216 struct zebra_if *zif = ifp->info;
1217
1218 zif->rtadv.AdvIntervalOption = 1;
1219
1220 return CMD_SUCCESS;
1221 }
1222
1223 DEFUN (no_ipv6_nd_adv_interval_config_option,
1224 no_ipv6_nd_adv_interval_config_option_cmd,
1225 "no ipv6 nd adv-interval-option",
1226 NO_STR
1227 "Interface IPv6 config commands\n"
1228 "Neighbor discovery\n"
1229 "Advertisement Interval Option\n")
1230 {
1231 VTY_DECLVAR_CONTEXT(interface, ifp);
1232 struct zebra_if *zif = ifp->info;
1233
1234 zif->rtadv.AdvIntervalOption = 0;
1235
1236 return CMD_SUCCESS;
1237 }
1238
1239 DEFUN (ipv6_nd_other_config_flag,
1240 ipv6_nd_other_config_flag_cmd,
1241 "ipv6 nd other-config-flag",
1242 "Interface IPv6 config commands\n"
1243 "Neighbor discovery\n"
1244 "Other statefull configuration flag\n")
1245 {
1246 VTY_DECLVAR_CONTEXT(interface, ifp);
1247 struct zebra_if *zif = ifp->info;
1248
1249 zif->rtadv.AdvOtherConfigFlag = 1;
1250
1251 return CMD_SUCCESS;
1252 }
1253
1254 DEFUN (no_ipv6_nd_other_config_flag,
1255 no_ipv6_nd_other_config_flag_cmd,
1256 "no ipv6 nd other-config-flag",
1257 NO_STR
1258 "Interface IPv6 config commands\n"
1259 "Neighbor discovery\n"
1260 "Other statefull configuration flag\n")
1261 {
1262 VTY_DECLVAR_CONTEXT(interface, ifp);
1263 struct zebra_if *zif = ifp->info;
1264
1265 zif->rtadv.AdvOtherConfigFlag = 0;
1266
1267 return CMD_SUCCESS;
1268 }
1269
1270 DEFUN (ipv6_nd_prefix,
1271 ipv6_nd_prefix_cmd,
1272 "ipv6 nd prefix X:X::X:X/M [<(0-4294967295)|infinite> <(0-4294967295)|infinite>] [<router-address|off-link [no-autoconfig]|no-autoconfig [off-link]>]",
1273 "Interface IPv6 config commands\n"
1274 "Neighbor discovery\n"
1275 "Prefix information\n"
1276 "IPv6 prefix\n"
1277 "Valid lifetime in seconds\n"
1278 "Infinite valid lifetime\n"
1279 "Preferred lifetime in seconds\n"
1280 "Infinite preferred lifetime\n"
1281 "Set Router Address flag\n"
1282 "Do not use prefix for onlink determination\n"
1283 "Do not use prefix for autoconfiguration\n"
1284 "Do not use prefix for autoconfiguration\n"
1285 "Do not use prefix for onlink determination\n")
1286 {
1287 /* prelude */
1288 char *prefix = argv[3]->arg;
1289 int lifetimes = (argc > 4) && (argv[4]->type == RANGE_TKN
1290 || strmatch(argv[4]->text, "infinite"));
1291 int routeropts = lifetimes ? argc > 6 : argc > 4;
1292
1293 int idx_routeropts = routeropts ? (lifetimes ? 6 : 4) : 0;
1294
1295 char *lifetime = NULL, *preflifetime = NULL;
1296 int routeraddr = 0, offlink = 0, noautoconf = 0;
1297 if (lifetimes) {
1298 lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
1299 : argv[4]->text;
1300 preflifetime = argv[5]->type == RANGE_TKN ? argv[5]->arg
1301 : argv[5]->text;
1302 }
1303 if (routeropts) {
1304 routeraddr =
1305 strmatch(argv[idx_routeropts]->text, "router-address");
1306 if (!routeraddr) {
1307 offlink = (argc > idx_routeropts + 1
1308 || strmatch(argv[idx_routeropts]->text,
1309 "off-link"));
1310 noautoconf = (argc > idx_routeropts + 1
1311 || strmatch(argv[idx_routeropts]->text,
1312 "no-autoconfig"));
1313 }
1314 }
1315
1316 /* business */
1317 VTY_DECLVAR_CONTEXT(interface, ifp);
1318 struct zebra_if *zebra_if = ifp->info;
1319 int ret;
1320 struct rtadv_prefix rp;
1321
1322 ret = str2prefix_ipv6(prefix, &rp.prefix);
1323 if (!ret) {
1324 vty_out(vty, "Malformed IPv6 prefix\n");
1325 return CMD_WARNING_CONFIG_FAILED;
1326 }
1327 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
1328 rp.AdvOnLinkFlag = !offlink;
1329 rp.AdvAutonomousFlag = !noautoconf;
1330 rp.AdvRouterAddressFlag = routeraddr;
1331 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1332 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
1333
1334 if (lifetimes) {
1335 rp.AdvValidLifetime = strmatch(lifetime, "infinite")
1336 ? UINT32_MAX
1337 : strtoll(lifetime, NULL, 10);
1338 rp.AdvPreferredLifetime =
1339 strmatch(preflifetime, "infinite")
1340 ? UINT32_MAX
1341 : strtoll(preflifetime, NULL, 10);
1342 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) {
1343 vty_out(vty, "Invalid preferred lifetime\n");
1344 return CMD_WARNING_CONFIG_FAILED;
1345 }
1346 }
1347
1348 rtadv_prefix_set(zebra_if, &rp);
1349
1350 return CMD_SUCCESS;
1351 }
1352
1353 DEFUN (no_ipv6_nd_prefix,
1354 no_ipv6_nd_prefix_cmd,
1355 "no ipv6 nd prefix X:X::X:X/M [<(0-4294967295)|infinite> <(0-4294967295)|infinite>] [<router-address|off-link [no-autoconfig]|no-autoconfig [off-link]>]",
1356 NO_STR
1357 "Interface IPv6 config commands\n"
1358 "Neighbor discovery\n"
1359 "Prefix information\n"
1360 "IPv6 prefix\n"
1361 "Valid lifetime in seconds\n"
1362 "Infinite valid lifetime\n"
1363 "Preferred lifetime in seconds\n"
1364 "Infinite preferred lifetime\n"
1365 "Set Router Address flag\n"
1366 "Do not use prefix for onlink determination\n"
1367 "Do not use prefix for autoconfiguration\n"
1368 "Do not use prefix for autoconfiguration\n"
1369 "Do not use prefix for onlink determination\n")
1370 {
1371 VTY_DECLVAR_CONTEXT(interface, ifp);
1372 struct zebra_if *zebra_if = ifp->info;
1373 int ret;
1374 struct rtadv_prefix rp;
1375 char *prefix = argv[4]->arg;
1376
1377 ret = str2prefix_ipv6(prefix, &rp.prefix);
1378 if (!ret) {
1379 vty_out(vty, "Malformed IPv6 prefix\n");
1380 return CMD_WARNING_CONFIG_FAILED;
1381 }
1382 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
1383
1384 ret = rtadv_prefix_reset(zebra_if, &rp);
1385 if (!ret) {
1386 vty_out(vty, "Non-existant IPv6 prefix\n");
1387 return CMD_WARNING_CONFIG_FAILED;
1388 }
1389
1390 return CMD_SUCCESS;
1391 }
1392
1393 DEFUN (ipv6_nd_router_preference,
1394 ipv6_nd_router_preference_cmd,
1395 "ipv6 nd router-preference <high|medium|low>",
1396 "Interface IPv6 config commands\n"
1397 "Neighbor discovery\n"
1398 "Default router preference\n"
1399 "High default router preference\n"
1400 "Medium default router preference (default)\n"
1401 "Low default router preference\n")
1402 {
1403 int idx_high_medium_low = 3;
1404 VTY_DECLVAR_CONTEXT(interface, ifp);
1405 struct zebra_if *zif = ifp->info;
1406 int i = 0;
1407
1408 while (0 != rtadv_pref_strs[i]) {
1409 if (strncmp(argv[idx_high_medium_low]->arg, rtadv_pref_strs[i],
1410 1)
1411 == 0) {
1412 zif->rtadv.DefaultPreference = i;
1413 return CMD_SUCCESS;
1414 }
1415 i++;
1416 }
1417
1418 return CMD_ERR_NO_MATCH;
1419 }
1420
1421 DEFUN (no_ipv6_nd_router_preference,
1422 no_ipv6_nd_router_preference_cmd,
1423 "no ipv6 nd router-preference [<high|medium|low>]",
1424 NO_STR
1425 "Interface IPv6 config commands\n"
1426 "Neighbor discovery\n"
1427 "Default router preference\n"
1428 "High default router preference\n"
1429 "Medium default router preference (default)\n"
1430 "Low default router preference\n")
1431 {
1432 VTY_DECLVAR_CONTEXT(interface, ifp);
1433 struct zebra_if *zif = ifp->info;
1434
1435 zif->rtadv.DefaultPreference =
1436 RTADV_PREF_MEDIUM; /* Default per RFC4191. */
1437
1438 return CMD_SUCCESS;
1439 }
1440
1441 DEFUN (ipv6_nd_mtu,
1442 ipv6_nd_mtu_cmd,
1443 "ipv6 nd mtu (1-65535)",
1444 "Interface IPv6 config commands\n"
1445 "Neighbor discovery\n"
1446 "Advertised MTU\n"
1447 "MTU in bytes\n")
1448 {
1449 int idx_number = 3;
1450 VTY_DECLVAR_CONTEXT(interface, ifp);
1451 struct zebra_if *zif = ifp->info;
1452 zif->rtadv.AdvLinkMTU = strtoul(argv[idx_number]->arg, NULL, 10);
1453 return CMD_SUCCESS;
1454 }
1455
1456 DEFUN (no_ipv6_nd_mtu,
1457 no_ipv6_nd_mtu_cmd,
1458 "no ipv6 nd mtu [(1-65535)]",
1459 NO_STR
1460 "Interface IPv6 config commands\n"
1461 "Neighbor discovery\n"
1462 "Advertised MTU\n"
1463 "MTU in bytes\n")
1464 {
1465 VTY_DECLVAR_CONTEXT(interface, ifp);
1466 struct zebra_if *zif = ifp->info;
1467 zif->rtadv.AdvLinkMTU = 0;
1468 return CMD_SUCCESS;
1469 }
1470
1471 /* Dump interface ND information to vty. */
1472 static int nd_dump_vty(struct vty *vty, struct interface *ifp)
1473 {
1474 struct zebra_if *zif;
1475 struct rtadvconf *rtadv;
1476 int interval;
1477
1478 zif = (struct zebra_if *)ifp->info;
1479 rtadv = &zif->rtadv;
1480
1481 if (rtadv->AdvSendAdvertisements) {
1482 vty_out(vty,
1483 " ND advertised reachable time is %d milliseconds\n",
1484 rtadv->AdvReachableTime);
1485 vty_out(vty,
1486 " ND advertised retransmit interval is %d milliseconds\n",
1487 rtadv->AdvRetransTimer);
1488 vty_out(vty, " ND router advertisements sent: %d rcvd: %d\n",
1489 zif->ra_sent, zif->ra_rcvd);
1490 interval = rtadv->MaxRtrAdvInterval;
1491 if (interval % 1000)
1492 vty_out(vty,
1493 " ND router advertisements are sent every "
1494 "%d milliseconds\n",
1495 interval);
1496 else
1497 vty_out(vty,
1498 " ND router advertisements are sent every "
1499 "%d seconds\n",
1500 interval / 1000);
1501 if (rtadv->AdvDefaultLifetime != -1)
1502 vty_out(vty,
1503 " ND router advertisements live for %d seconds\n",
1504 rtadv->AdvDefaultLifetime);
1505 else
1506 vty_out(vty,
1507 " ND router advertisements lifetime tracks ra-interval\n");
1508 vty_out(vty,
1509 " ND router advertisement default router preference is "
1510 "%s\n",
1511 rtadv_pref_strs[rtadv->DefaultPreference]);
1512 if (rtadv->AdvManagedFlag)
1513 vty_out(vty,
1514 " Hosts use DHCP to obtain routable addresses.\n");
1515 else
1516 vty_out(vty,
1517 " Hosts use stateless autoconfig for addresses.\n");
1518 if (rtadv->AdvHomeAgentFlag) {
1519 vty_out(vty,
1520 " ND router advertisements with Home Agent flag bit set.\n");
1521 if (rtadv->HomeAgentLifetime != -1)
1522 vty_out(vty,
1523 " Home Agent lifetime is %u seconds\n",
1524 rtadv->HomeAgentLifetime);
1525 else
1526 vty_out(vty,
1527 " Home Agent lifetime tracks ra-lifetime\n");
1528 vty_out(vty, " Home Agent preference is %u\n",
1529 rtadv->HomeAgentPreference);
1530 }
1531 if (rtadv->AdvIntervalOption)
1532 vty_out(vty,
1533 " ND router advertisements with Adv. Interval option.\n");
1534 }
1535 return 0;
1536 }
1537
1538
1539 /* Write configuration about router advertisement. */
1540 static int rtadv_config_write(struct vty *vty, struct interface *ifp)
1541 {
1542 struct zebra_if *zif;
1543 struct listnode *node;
1544 struct rtadv_prefix *rprefix;
1545 char buf[PREFIX_STRLEN];
1546 int interval;
1547
1548 zif = ifp->info;
1549
1550 if (!(if_is_loopback(ifp)
1551 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))) {
1552 if (zif->rtadv.AdvSendAdvertisements)
1553 vty_out(vty, " no ipv6 nd suppress-ra\n");
1554 }
1555
1556 interval = zif->rtadv.MaxRtrAdvInterval;
1557 if (interval % 1000)
1558 vty_out(vty, " ipv6 nd ra-interval msec %d\n", interval);
1559 else if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
1560 vty_out(vty, " ipv6 nd ra-interval %d\n", interval / 1000);
1561
1562 if (zif->rtadv.AdvIntervalOption)
1563 vty_out(vty, " ipv6 nd adv-interval-option\n");
1564
1565 if (zif->rtadv.AdvDefaultLifetime != -1)
1566 vty_out(vty, " ipv6 nd ra-lifetime %d\n",
1567 zif->rtadv.AdvDefaultLifetime);
1568
1569 if (zif->rtadv.HomeAgentPreference)
1570 vty_out(vty, " ipv6 nd home-agent-preference %u\n",
1571 zif->rtadv.HomeAgentPreference);
1572
1573 if (zif->rtadv.HomeAgentLifetime != -1)
1574 vty_out(vty, " ipv6 nd home-agent-lifetime %u\n",
1575 zif->rtadv.HomeAgentLifetime);
1576
1577 if (zif->rtadv.AdvHomeAgentFlag)
1578 vty_out(vty, " ipv6 nd home-agent-config-flag\n");
1579
1580 if (zif->rtadv.AdvReachableTime)
1581 vty_out(vty, " ipv6 nd reachable-time %d\n",
1582 zif->rtadv.AdvReachableTime);
1583
1584 if (zif->rtadv.AdvManagedFlag)
1585 vty_out(vty, " ipv6 nd managed-config-flag\n");
1586
1587 if (zif->rtadv.AdvOtherConfigFlag)
1588 vty_out(vty, " ipv6 nd other-config-flag\n");
1589
1590 if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
1591 vty_out(vty, " ipv6 nd router-preference %s\n",
1592 rtadv_pref_strs[zif->rtadv.DefaultPreference]);
1593
1594 if (zif->rtadv.AdvLinkMTU)
1595 vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU);
1596
1597 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvPrefixList, node, rprefix)) {
1598 vty_out(vty, " ipv6 nd prefix %s",
1599 prefix2str(&rprefix->prefix, buf, sizeof(buf)));
1600 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME)
1601 || (rprefix->AdvPreferredLifetime
1602 != RTADV_PREFERRED_LIFETIME)) {
1603 if (rprefix->AdvValidLifetime == UINT32_MAX)
1604 vty_out(vty, " infinite");
1605 else
1606 vty_out(vty, " %u", rprefix->AdvValidLifetime);
1607 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1608 vty_out(vty, " infinite");
1609 else
1610 vty_out(vty, " %u",
1611 rprefix->AdvPreferredLifetime);
1612 }
1613 if (!rprefix->AdvOnLinkFlag)
1614 vty_out(vty, " off-link");
1615 if (!rprefix->AdvAutonomousFlag)
1616 vty_out(vty, " no-autoconfig");
1617 if (rprefix->AdvRouterAddressFlag)
1618 vty_out(vty, " router-address");
1619 vty_out(vty, "\n");
1620 }
1621 return 0;
1622 }
1623
1624
1625 static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
1626 {
1627 struct rtadv *rtadv = &zns->rtadv;
1628
1629 switch (event) {
1630 case RTADV_START:
1631 thread_add_read(zebrad.master, rtadv_read, zns, val,
1632 &rtadv->ra_read);
1633 thread_add_event(zebrad.master, rtadv_timer, zns, 0,
1634 &rtadv->ra_timer);
1635 break;
1636 case RTADV_STOP:
1637 if (rtadv->ra_timer) {
1638 thread_cancel(rtadv->ra_timer);
1639 rtadv->ra_timer = NULL;
1640 }
1641 if (rtadv->ra_read) {
1642 thread_cancel(rtadv->ra_read);
1643 rtadv->ra_read = NULL;
1644 }
1645 break;
1646 case RTADV_TIMER:
1647 thread_add_timer(zebrad.master, rtadv_timer, zns, val,
1648 &rtadv->ra_timer);
1649 break;
1650 case RTADV_TIMER_MSEC:
1651 thread_add_timer_msec(zebrad.master, rtadv_timer, zns, val,
1652 &rtadv->ra_timer);
1653 break;
1654 case RTADV_READ:
1655 thread_add_read(zebrad.master, rtadv_read, zns, val,
1656 &rtadv->ra_read);
1657 break;
1658 default:
1659 break;
1660 }
1661 return;
1662 }
1663
1664 void rtadv_init(struct zebra_ns *zns)
1665 {
1666 zns->rtadv.sock = rtadv_make_socket();
1667 }
1668
1669 void rtadv_terminate(struct zebra_ns *zns)
1670 {
1671 rtadv_event(zns, RTADV_STOP, 0);
1672 if (zns->rtadv.sock >= 0) {
1673 close(zns->rtadv.sock);
1674 zns->rtadv.sock = -1;
1675 }
1676
1677 zns->rtadv.adv_if_count = 0;
1678 zns->rtadv.adv_msec_if_count = 0;
1679 }
1680
1681 void rtadv_cmd_init(void)
1682 {
1683 hook_register(zebra_if_extra_info, nd_dump_vty);
1684 hook_register(zebra_if_config_wr, rtadv_config_write);
1685
1686 install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1687 install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
1688 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
1689 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
1690 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1691 install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1692 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1693 install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1694 install_element(INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1695 install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1696 install_element(INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1697 install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1698 install_element(INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
1699 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
1700 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
1701 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
1702 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
1703 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
1704 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
1705 install_element(INTERFACE_NODE,
1706 &ipv6_nd_adv_interval_config_option_cmd);
1707 install_element(INTERFACE_NODE,
1708 &no_ipv6_nd_adv_interval_config_option_cmd);
1709 install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd);
1710 install_element(INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
1711 install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
1712 install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
1713 install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd);
1714 install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
1715 }
1716
1717 static int if_join_all_router(int sock, struct interface *ifp)
1718 {
1719 int ret;
1720
1721 struct ipv6_mreq mreq;
1722
1723 memset(&mreq, 0, sizeof(struct ipv6_mreq));
1724 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1725 mreq.ipv6mr_interface = ifp->ifindex;
1726
1727 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq,
1728 sizeof mreq);
1729 if (ret < 0)
1730 zlog_warn("%s(%u): Failed to join group, socket %u error %s",
1731 ifp->name, ifp->ifindex, sock, safe_strerror(errno));
1732
1733 if (IS_ZEBRA_DEBUG_EVENT)
1734 zlog_debug(
1735 "%s(%u): Join All-Routers multicast group, socket %u",
1736 ifp->name, ifp->ifindex, sock);
1737
1738 return 0;
1739 }
1740
1741 static int if_leave_all_router(int sock, struct interface *ifp)
1742 {
1743 int ret;
1744
1745 struct ipv6_mreq mreq;
1746
1747 memset(&mreq, 0, sizeof(struct ipv6_mreq));
1748 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1749 mreq.ipv6mr_interface = ifp->ifindex;
1750
1751 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq,
1752 sizeof mreq);
1753 if (ret < 0)
1754 zlog_warn("%s(%u): Failed to leave group, socket %u error %s",
1755 ifp->name, ifp->ifindex, sock, safe_strerror(errno));
1756
1757 if (IS_ZEBRA_DEBUG_EVENT)
1758 zlog_debug(
1759 "%s(%u): Leave All-Routers multicast group, socket %u",
1760 ifp->name, ifp->ifindex, sock);
1761
1762 return 0;
1763 }
1764
1765 #else
1766 void rtadv_init(struct zebra_ns *zns)
1767 {
1768 /* Empty.*/;
1769 }
1770 void rtadv_terminate(struct zebra_ns *zns)
1771 {
1772 /* Empty.*/;
1773 }
1774 void rtadv_cmd_init(void)
1775 {
1776 /* Empty.*/;
1777 }
1778 #endif /* HAVE_RTADV */