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