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