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