]> git.proxmox.com Git - mirror_frr.git/blob - zebra/rtadv.c
Merge pull request #1237 from donaldsharp/distance_special
[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 listnode *node, *nnode;
387 struct interface *ifp;
388 struct zebra_if *zif;
389 int period;
390
391 zns->rtadv.ra_timer = NULL;
392 if (zns->rtadv.adv_msec_if_count == 0) {
393 period = 1000; /* 1 s */
394 rtadv_event(zns, RTADV_TIMER, 1 /* 1 s */);
395 } else {
396 period = 10; /* 10 ms */
397 rtadv_event(zns, RTADV_TIMER_MSEC, 10 /* 10 ms */);
398 }
399
400 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
401 for (ALL_LIST_ELEMENTS(vrf->iflist, node, nnode, ifp)) {
402 if (if_is_loopback(ifp)
403 || CHECK_FLAG(ifp->status,
404 ZEBRA_INTERFACE_VRF_LOOPBACK)
405 || !if_is_operative(ifp))
406 continue;
407
408 zif = ifp->info;
409
410 if (zif->rtadv.AdvSendAdvertisements) {
411 if (zif->rtadv.inFastRexmit) {
412 /* We assume we fast rexmit every sec so
413 * no
414 * additional vars */
415 if (--zif->rtadv.NumFastReXmitsRemain
416 <= 0)
417 zif->rtadv.inFastRexmit = 0;
418
419 if (IS_ZEBRA_DEBUG_SEND)
420 zlog_debug(
421 "Fast RA Rexmit on interface %s",
422 ifp->name);
423
424 rtadv_send_packet(zns->rtadv.sock, ifp);
425 } else {
426 zif->rtadv.AdvIntervalTimer -= period;
427 if (zif->rtadv.AdvIntervalTimer <= 0) {
428 /* FIXME: using
429 MaxRtrAdvInterval each
430 time isn't what section
431 6.2.4 of RFC4861 tells to do.
432 */
433 zif->rtadv.AdvIntervalTimer =
434 zif->rtadv
435 .MaxRtrAdvInterval;
436 rtadv_send_packet(
437 zns->rtadv.sock, ifp);
438 }
439 }
440 }
441 }
442
443 return 0;
444 }
445
446 static void rtadv_process_solicit(struct interface *ifp)
447 {
448 struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
449 struct zebra_ns *zns = zvrf->zns;
450
451 assert(zns);
452 rtadv_send_packet(zns->rtadv.sock, ifp);
453 }
454
455 static void rtadv_process_advert(u_char *msg, unsigned int len,
456 struct interface *ifp,
457 struct sockaddr_in6 *addr)
458 {
459 struct nd_router_advert *radvert;
460 char addr_str[INET6_ADDRSTRLEN];
461 struct zebra_if *zif;
462 struct prefix p;
463
464 zif = ifp->info;
465
466 inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
467
468 if (len < sizeof(struct nd_router_advert)) {
469 zlog_warn("%s(%u): Rx RA with invalid length %d from %s",
470 ifp->name, ifp->ifindex, len, addr_str);
471 return;
472 }
473 if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
474 zlog_warn(
475 "%s(%u): Rx RA with non-linklocal source address from %s",
476 ifp->name, ifp->ifindex, addr_str);
477 return;
478 }
479
480 radvert = (struct nd_router_advert *)msg;
481
482 if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit)
483 && (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit)) {
484 zlog_warn(
485 "%s(%u): Rx RA - our AdvCurHopLimit doesn't agree with %s",
486 ifp->name, ifp->ifindex, addr_str);
487 }
488
489 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
490 && !zif->rtadv.AdvManagedFlag) {
491 zlog_warn(
492 "%s(%u): Rx RA - our AdvManagedFlag doesn't agree with %s",
493 ifp->name, ifp->ifindex, addr_str);
494 }
495
496 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
497 && !zif->rtadv.AdvOtherConfigFlag) {
498 zlog_warn(
499 "%s(%u): Rx RA - our AdvOtherConfigFlag doesn't agree with %s",
500 ifp->name, ifp->ifindex, addr_str);
501 }
502
503 if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime)
504 && (ntohl(radvert->nd_ra_reachable)
505 != zif->rtadv.AdvReachableTime)) {
506 zlog_warn(
507 "%s(%u): Rx RA - our AdvReachableTime doesn't agree with %s",
508 ifp->name, ifp->ifindex, addr_str);
509 }
510
511 if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer)
512 && (ntohl(radvert->nd_ra_retransmit)
513 != (unsigned int)zif->rtadv.AdvRetransTimer)) {
514 zlog_warn(
515 "%s(%u): Rx RA - our AdvRetransTimer doesn't agree with %s",
516 ifp->name, ifp->ifindex, addr_str);
517 }
518
519 /* Create entry for neighbor if not known. */
520 p.family = AF_INET6;
521 IPV6_ADDR_COPY(&p.u.prefix, &addr->sin6_addr);
522 p.prefixlen = IPV6_MAX_PREFIXLEN;
523
524 if (!nbr_connected_check(ifp, &p))
525 nbr_connected_add_ipv6(ifp, &addr->sin6_addr);
526 }
527
528
529 static void rtadv_process_packet(u_char *buf, unsigned int len,
530 ifindex_t ifindex, int hoplimit,
531 struct sockaddr_in6 *from,
532 struct zebra_ns *zns)
533 {
534 struct icmp6_hdr *icmph;
535 struct interface *ifp;
536 struct zebra_if *zif;
537 char addr_str[INET6_ADDRSTRLEN];
538
539 inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN);
540
541 /* Interface search. */
542 ifp = if_lookup_by_index_per_ns(zns, ifindex);
543 if (ifp == NULL) {
544 zlog_warn("RA/RS received on unknown IF %u from %s", ifindex,
545 addr_str);
546 return;
547 }
548
549 if (IS_ZEBRA_DEBUG_PACKET)
550 zlog_debug("%s(%u): Rx RA/RS len %d from %s", ifp->name,
551 ifp->ifindex, len, addr_str);
552
553 if (if_is_loopback(ifp)
554 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))
555 return;
556
557 /* Check interface configuration. */
558 zif = ifp->info;
559 if (!zif->rtadv.AdvSendAdvertisements)
560 return;
561
562 /* ICMP message length check. */
563 if (len < sizeof(struct icmp6_hdr)) {
564 zlog_warn("%s(%u): Rx RA with Invalid ICMPV6 packet length %d",
565 ifp->name, ifp->ifindex, len);
566 return;
567 }
568
569 icmph = (struct icmp6_hdr *)buf;
570
571 /* ICMP message type check. */
572 if (icmph->icmp6_type != ND_ROUTER_SOLICIT
573 && icmph->icmp6_type != ND_ROUTER_ADVERT) {
574 zlog_warn("%s(%u): Rx RA - Unwanted ICMPV6 message type %d",
575 ifp->name, ifp->ifindex, icmph->icmp6_type);
576 return;
577 }
578
579 /* Hoplimit check. */
580 if (hoplimit >= 0 && hoplimit != 255) {
581 zlog_warn("%s(%u): Rx RA - Invalid hoplimit %d", ifp->name,
582 ifp->ifindex, hoplimit);
583 return;
584 }
585
586 /* Check ICMP message type. */
587 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
588 rtadv_process_solicit(ifp);
589 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
590 rtadv_process_advert(buf, len, ifp, from);
591
592 return;
593 }
594
595 static int rtadv_read(struct thread *thread)
596 {
597 int sock;
598 int len;
599 u_char buf[RTADV_MSG_SIZE];
600 struct sockaddr_in6 from;
601 ifindex_t ifindex = 0;
602 int hoplimit = -1;
603 struct zebra_ns *zns = THREAD_ARG(thread);
604
605 sock = THREAD_FD(thread);
606 zns->rtadv.ra_read = NULL;
607
608 /* Register myself. */
609 rtadv_event(zns, RTADV_READ, sock);
610
611 len = rtadv_recv_packet(zns, sock, buf, sizeof(buf), &from, &ifindex,
612 &hoplimit);
613
614 if (len < 0) {
615 zlog_warn("RA/RS recv failed, socket %u error %s", sock,
616 safe_strerror(errno));
617 return len;
618 }
619
620 rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zns);
621
622 return 0;
623 }
624
625 static int rtadv_make_socket(void)
626 {
627 int sock;
628 int ret = 0;
629 struct icmp6_filter filter;
630
631 if (zserv_privs.change(ZPRIVS_RAISE))
632 zlog_err("rtadv_make_socket: could not raise privs, %s",
633 safe_strerror(errno));
634
635 sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
636
637 if (zserv_privs.change(ZPRIVS_LOWER))
638 zlog_err("rtadv_make_socket: could not lower privs, %s",
639 safe_strerror(errno));
640
641 if (sock < 0) {
642 return -1;
643 }
644
645 ret = setsockopt_ipv6_pktinfo(sock, 1);
646 if (ret < 0) {
647 close(sock);
648 return ret;
649 }
650 ret = setsockopt_ipv6_multicast_loop(sock, 0);
651 if (ret < 0) {
652 close(sock);
653 return ret;
654 }
655 ret = setsockopt_ipv6_unicast_hops(sock, 255);
656 if (ret < 0) {
657 close(sock);
658 return ret;
659 }
660 ret = setsockopt_ipv6_multicast_hops(sock, 255);
661 if (ret < 0) {
662 close(sock);
663 return ret;
664 }
665 ret = setsockopt_ipv6_hoplimit(sock, 1);
666 if (ret < 0) {
667 close(sock);
668 return ret;
669 }
670
671 ICMP6_FILTER_SETBLOCKALL(&filter);
672 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
673 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
674
675 ret = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
676 sizeof(struct icmp6_filter));
677 if (ret < 0) {
678 zlog_info("ICMP6_FILTER set fail: %s", safe_strerror(errno));
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, int sock, u_short length,
804 struct zebra_vrf *zvrf, int enable)
805 {
806 struct stream *s;
807 unsigned int 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 ifindex = stream_getl(s);
816 ra_interval = stream_getl(s);
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 }
853
854 DEFUN (ipv6_nd_suppress_ra,
855 ipv6_nd_suppress_ra_cmd,
856 "ipv6 nd suppress-ra",
857 "Interface IPv6 config commands\n"
858 "Neighbor discovery\n"
859 "Suppress Router Advertisement\n")
860 {
861 VTY_DECLVAR_CONTEXT(interface, ifp);
862 struct zebra_if *zif = ifp->info;
863
864 if (if_is_loopback(ifp)
865 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
866 vty_out(vty,
867 "Cannot configure IPv6 Router Advertisements on this interface\n");
868 return CMD_WARNING_CONFIG_FAILED;
869 }
870
871 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
872 zif->rtadv.configured = 0;
873 return CMD_SUCCESS;
874 }
875
876 DEFUN (no_ipv6_nd_suppress_ra,
877 no_ipv6_nd_suppress_ra_cmd,
878 "no ipv6 nd suppress-ra",
879 NO_STR
880 "Interface IPv6 config commands\n"
881 "Neighbor discovery\n"
882 "Suppress Router Advertisement\n")
883 {
884 VTY_DECLVAR_CONTEXT(interface, ifp);
885 struct zebra_if *zif = ifp->info;
886
887 if (if_is_loopback(ifp)
888 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
889 vty_out(vty,
890 "Cannot configure IPv6 Router Advertisements on this interface\n");
891 return CMD_WARNING_CONFIG_FAILED;
892 }
893
894 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
895 zif->rtadv.configured = 1;
896 return CMD_SUCCESS;
897 }
898
899 DEFUN (ipv6_nd_ra_interval_msec,
900 ipv6_nd_ra_interval_msec_cmd,
901 "ipv6 nd ra-interval msec (70-1800000)",
902 "Interface IPv6 config commands\n"
903 "Neighbor discovery\n"
904 "Router Advertisement interval\n"
905 "Router Advertisement interval in milliseconds\n"
906 "Router Advertisement interval in milliseconds\n")
907 {
908 int idx_number = 4;
909 VTY_DECLVAR_CONTEXT(interface, ifp);
910 unsigned interval;
911 struct zebra_if *zif = ifp->info;
912 struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
913 struct zebra_ns *zns;
914
915 zns = zvrf->zns;
916 interval = strtoul(argv[idx_number]->arg, NULL, 10);
917 if ((zif->rtadv.AdvDefaultLifetime != -1
918 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) {
919 vty_out(vty,
920 "This ra-interval would conflict with configured ra-lifetime!\n");
921 return CMD_WARNING_CONFIG_FAILED;
922 }
923
924 if (zif->rtadv.MaxRtrAdvInterval % 1000)
925 zns->rtadv.adv_msec_if_count--;
926
927 if (interval % 1000)
928 zns->rtadv.adv_msec_if_count++;
929
930 zif->rtadv.MaxRtrAdvInterval = interval;
931 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
932 zif->rtadv.AdvIntervalTimer = 0;
933
934 return CMD_SUCCESS;
935 }
936
937 DEFUN (ipv6_nd_ra_interval,
938 ipv6_nd_ra_interval_cmd,
939 "ipv6 nd ra-interval (1-1800)",
940 "Interface IPv6 config commands\n"
941 "Neighbor discovery\n"
942 "Router Advertisement interval\n"
943 "Router Advertisement interval in seconds\n")
944 {
945 int idx_number = 3;
946 VTY_DECLVAR_CONTEXT(interface, ifp);
947 unsigned interval;
948 struct zebra_if *zif = ifp->info;
949 struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
950 struct zebra_ns *zns;
951
952 zns = zvrf->zns;
953 interval = strtoul(argv[idx_number]->arg, NULL, 10);
954 if ((zif->rtadv.AdvDefaultLifetime != -1
955 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) {
956 vty_out(vty,
957 "This ra-interval would conflict with configured ra-lifetime!\n");
958 return CMD_WARNING_CONFIG_FAILED;
959 }
960
961 if (zif->rtadv.MaxRtrAdvInterval % 1000)
962 zns->rtadv.adv_msec_if_count--;
963
964 /* convert to milliseconds */
965 interval = interval * 1000;
966
967 zif->rtadv.MaxRtrAdvInterval = interval;
968 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
969 zif->rtadv.AdvIntervalTimer = 0;
970
971 return CMD_SUCCESS;
972 }
973
974 DEFUN (no_ipv6_nd_ra_interval,
975 no_ipv6_nd_ra_interval_cmd,
976 "no ipv6 nd ra-interval [<(1-1800)|msec (1-1800000)>]",
977 NO_STR
978 "Interface IPv6 config commands\n"
979 "Neighbor discovery\n"
980 "Router Advertisement interval\n"
981 "Router Advertisement interval in seconds\n"
982 "Specify millisecond router advertisement interval\n"
983 "Router Advertisement interval in milliseconds\n")
984 {
985 VTY_DECLVAR_CONTEXT(interface, ifp);
986 struct zebra_if *zif = ifp->info;
987 struct zebra_vrf *zvrf;
988 struct zebra_ns *zns;
989
990 zvrf = vrf_info_lookup(ifp->vrf_id);
991 zns = zvrf->zns;
992
993 if (zif->rtadv.MaxRtrAdvInterval % 1000)
994 zns->rtadv.adv_msec_if_count--;
995
996 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
997 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
998 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
999
1000 return CMD_SUCCESS;
1001 }
1002
1003 DEFUN (ipv6_nd_ra_lifetime,
1004 ipv6_nd_ra_lifetime_cmd,
1005 "ipv6 nd ra-lifetime (0-9000)",
1006 "Interface IPv6 config commands\n"
1007 "Neighbor discovery\n"
1008 "Router lifetime\n"
1009 "Router lifetime in seconds (0 stands for a non-default gw)\n")
1010 {
1011 int idx_number = 3;
1012 VTY_DECLVAR_CONTEXT(interface, ifp);
1013 struct zebra_if *zif = ifp->info;
1014 int lifetime;
1015
1016 lifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1017
1018 /* The value to be placed in the Router Lifetime field
1019 * of Router Advertisements sent from the interface,
1020 * in seconds. MUST be either zero or between
1021 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
1022 if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) {
1023 vty_out(vty,
1024 "This ra-lifetime would conflict with configured ra-interval\n");
1025 return CMD_WARNING_CONFIG_FAILED;
1026 }
1027
1028 zif->rtadv.AdvDefaultLifetime = lifetime;
1029
1030 return CMD_SUCCESS;
1031 }
1032
1033 DEFUN (no_ipv6_nd_ra_lifetime,
1034 no_ipv6_nd_ra_lifetime_cmd,
1035 "no ipv6 nd ra-lifetime [(0-9000)]",
1036 NO_STR
1037 "Interface IPv6 config commands\n"
1038 "Neighbor discovery\n"
1039 "Router lifetime\n"
1040 "Router lifetime in seconds (0 stands for a non-default gw)\n")
1041 {
1042 VTY_DECLVAR_CONTEXT(interface, ifp);
1043 struct zebra_if *zif = ifp->info;
1044
1045 zif->rtadv.AdvDefaultLifetime = -1;
1046
1047 return CMD_SUCCESS;
1048 }
1049
1050 DEFUN (ipv6_nd_reachable_time,
1051 ipv6_nd_reachable_time_cmd,
1052 "ipv6 nd reachable-time (1-3600000)",
1053 "Interface IPv6 config commands\n"
1054 "Neighbor discovery\n"
1055 "Reachable time\n"
1056 "Reachable time in milliseconds\n")
1057 {
1058 int idx_number = 3;
1059 VTY_DECLVAR_CONTEXT(interface, ifp);
1060 struct zebra_if *zif = ifp->info;
1061 zif->rtadv.AdvReachableTime = strtoul(argv[idx_number]->arg, NULL, 10);
1062 return CMD_SUCCESS;
1063 }
1064
1065 DEFUN (no_ipv6_nd_reachable_time,
1066 no_ipv6_nd_reachable_time_cmd,
1067 "no ipv6 nd reachable-time [(1-3600000)]",
1068 NO_STR
1069 "Interface IPv6 config commands\n"
1070 "Neighbor discovery\n"
1071 "Reachable time\n"
1072 "Reachable time in milliseconds\n")
1073 {
1074 VTY_DECLVAR_CONTEXT(interface, ifp);
1075 struct zebra_if *zif = ifp->info;
1076
1077 zif->rtadv.AdvReachableTime = 0;
1078
1079 return CMD_SUCCESS;
1080 }
1081
1082 DEFUN (ipv6_nd_homeagent_preference,
1083 ipv6_nd_homeagent_preference_cmd,
1084 "ipv6 nd home-agent-preference (0-65535)",
1085 "Interface IPv6 config commands\n"
1086 "Neighbor discovery\n"
1087 "Home Agent preference\n"
1088 "preference value (default is 0, least preferred)\n")
1089 {
1090 int idx_number = 3;
1091 VTY_DECLVAR_CONTEXT(interface, ifp);
1092 struct zebra_if *zif = ifp->info;
1093 zif->rtadv.HomeAgentPreference =
1094 strtoul(argv[idx_number]->arg, NULL, 10);
1095 return CMD_SUCCESS;
1096 }
1097
1098 DEFUN (no_ipv6_nd_homeagent_preference,
1099 no_ipv6_nd_homeagent_preference_cmd,
1100 "no ipv6 nd home-agent-preference [(0-65535)]",
1101 NO_STR
1102 "Interface IPv6 config commands\n"
1103 "Neighbor discovery\n"
1104 "Home Agent preference\n"
1105 "preference value (default is 0, least preferred)\n")
1106 {
1107 VTY_DECLVAR_CONTEXT(interface, ifp);
1108 struct zebra_if *zif = ifp->info;
1109
1110 zif->rtadv.HomeAgentPreference = 0;
1111
1112 return CMD_SUCCESS;
1113 }
1114
1115 DEFUN (ipv6_nd_homeagent_lifetime,
1116 ipv6_nd_homeagent_lifetime_cmd,
1117 "ipv6 nd home-agent-lifetime (0-65520)",
1118 "Interface IPv6 config commands\n"
1119 "Neighbor discovery\n"
1120 "Home Agent lifetime\n"
1121 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
1122 {
1123 int idx_number = 3;
1124 VTY_DECLVAR_CONTEXT(interface, ifp);
1125 struct zebra_if *zif = ifp->info;
1126 zif->rtadv.HomeAgentLifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1127 return CMD_SUCCESS;
1128 }
1129
1130 DEFUN (no_ipv6_nd_homeagent_lifetime,
1131 no_ipv6_nd_homeagent_lifetime_cmd,
1132 "no ipv6 nd home-agent-lifetime [(0-65520)]",
1133 NO_STR
1134 "Interface IPv6 config commands\n"
1135 "Neighbor discovery\n"
1136 "Home Agent lifetime\n"
1137 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
1138 {
1139 VTY_DECLVAR_CONTEXT(interface, ifp);
1140 struct zebra_if *zif = ifp->info;
1141
1142 zif->rtadv.HomeAgentLifetime = -1;
1143
1144 return CMD_SUCCESS;
1145 }
1146
1147 DEFUN (ipv6_nd_managed_config_flag,
1148 ipv6_nd_managed_config_flag_cmd,
1149 "ipv6 nd managed-config-flag",
1150 "Interface IPv6 config commands\n"
1151 "Neighbor discovery\n"
1152 "Managed address configuration flag\n")
1153 {
1154 VTY_DECLVAR_CONTEXT(interface, ifp);
1155 struct zebra_if *zif = ifp->info;
1156
1157 zif->rtadv.AdvManagedFlag = 1;
1158
1159 return CMD_SUCCESS;
1160 }
1161
1162 DEFUN (no_ipv6_nd_managed_config_flag,
1163 no_ipv6_nd_managed_config_flag_cmd,
1164 "no ipv6 nd managed-config-flag",
1165 NO_STR
1166 "Interface IPv6 config commands\n"
1167 "Neighbor discovery\n"
1168 "Managed address configuration flag\n")
1169 {
1170 VTY_DECLVAR_CONTEXT(interface, ifp);
1171 struct zebra_if *zif = ifp->info;
1172
1173 zif->rtadv.AdvManagedFlag = 0;
1174
1175 return CMD_SUCCESS;
1176 }
1177
1178 DEFUN (ipv6_nd_homeagent_config_flag,
1179 ipv6_nd_homeagent_config_flag_cmd,
1180 "ipv6 nd home-agent-config-flag",
1181 "Interface IPv6 config commands\n"
1182 "Neighbor discovery\n"
1183 "Home Agent configuration flag\n")
1184 {
1185 VTY_DECLVAR_CONTEXT(interface, ifp);
1186 struct zebra_if *zif = ifp->info;
1187
1188 zif->rtadv.AdvHomeAgentFlag = 1;
1189
1190 return CMD_SUCCESS;
1191 }
1192
1193 DEFUN (no_ipv6_nd_homeagent_config_flag,
1194 no_ipv6_nd_homeagent_config_flag_cmd,
1195 "no ipv6 nd home-agent-config-flag",
1196 NO_STR
1197 "Interface IPv6 config commands\n"
1198 "Neighbor discovery\n"
1199 "Home Agent configuration flag\n")
1200 {
1201 VTY_DECLVAR_CONTEXT(interface, ifp);
1202 struct zebra_if *zif = ifp->info;
1203
1204 zif->rtadv.AdvHomeAgentFlag = 0;
1205
1206 return CMD_SUCCESS;
1207 }
1208
1209 DEFUN (ipv6_nd_adv_interval_config_option,
1210 ipv6_nd_adv_interval_config_option_cmd,
1211 "ipv6 nd adv-interval-option",
1212 "Interface IPv6 config commands\n"
1213 "Neighbor discovery\n"
1214 "Advertisement Interval Option\n")
1215 {
1216 VTY_DECLVAR_CONTEXT(interface, ifp);
1217 struct zebra_if *zif = ifp->info;
1218
1219 zif->rtadv.AdvIntervalOption = 1;
1220
1221 return CMD_SUCCESS;
1222 }
1223
1224 DEFUN (no_ipv6_nd_adv_interval_config_option,
1225 no_ipv6_nd_adv_interval_config_option_cmd,
1226 "no ipv6 nd adv-interval-option",
1227 NO_STR
1228 "Interface IPv6 config commands\n"
1229 "Neighbor discovery\n"
1230 "Advertisement Interval Option\n")
1231 {
1232 VTY_DECLVAR_CONTEXT(interface, ifp);
1233 struct zebra_if *zif = ifp->info;
1234
1235 zif->rtadv.AdvIntervalOption = 0;
1236
1237 return CMD_SUCCESS;
1238 }
1239
1240 DEFUN (ipv6_nd_other_config_flag,
1241 ipv6_nd_other_config_flag_cmd,
1242 "ipv6 nd other-config-flag",
1243 "Interface IPv6 config commands\n"
1244 "Neighbor discovery\n"
1245 "Other statefull configuration flag\n")
1246 {
1247 VTY_DECLVAR_CONTEXT(interface, ifp);
1248 struct zebra_if *zif = ifp->info;
1249
1250 zif->rtadv.AdvOtherConfigFlag = 1;
1251
1252 return CMD_SUCCESS;
1253 }
1254
1255 DEFUN (no_ipv6_nd_other_config_flag,
1256 no_ipv6_nd_other_config_flag_cmd,
1257 "no ipv6 nd other-config-flag",
1258 NO_STR
1259 "Interface IPv6 config commands\n"
1260 "Neighbor discovery\n"
1261 "Other statefull configuration flag\n")
1262 {
1263 VTY_DECLVAR_CONTEXT(interface, ifp);
1264 struct zebra_if *zif = ifp->info;
1265
1266 zif->rtadv.AdvOtherConfigFlag = 0;
1267
1268 return CMD_SUCCESS;
1269 }
1270
1271 DEFUN (ipv6_nd_prefix,
1272 ipv6_nd_prefix_cmd,
1273 "ipv6 nd prefix X:X::X:X/M [<(0-4294967295)|infinite> <(0-4294967295)|infinite>] [<router-address|off-link [no-autoconfig]|no-autoconfig [off-link]>]",
1274 "Interface IPv6 config commands\n"
1275 "Neighbor discovery\n"
1276 "Prefix information\n"
1277 "IPv6 prefix\n"
1278 "Valid lifetime in seconds\n"
1279 "Infinite valid lifetime\n"
1280 "Preferred lifetime in seconds\n"
1281 "Infinite preferred lifetime\n"
1282 "Set Router Address flag\n"
1283 "Do not use prefix for onlink determination\n"
1284 "Do not use prefix for autoconfiguration\n"
1285 "Do not use prefix for autoconfiguration\n"
1286 "Do not use prefix for onlink determination\n")
1287 {
1288 /* prelude */
1289 char *prefix = argv[3]->arg;
1290 int lifetimes = (argc > 4) && (argv[4]->type == RANGE_TKN
1291 || strmatch(argv[4]->text, "infinite"));
1292 int routeropts = lifetimes ? argc > 6 : argc > 4;
1293
1294 int idx_routeropts = routeropts ? (lifetimes ? 6 : 4) : 0;
1295
1296 char *lifetime = NULL, *preflifetime = NULL;
1297 int routeraddr = 0, offlink = 0, noautoconf = 0;
1298 if (lifetimes) {
1299 lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
1300 : argv[4]->text;
1301 preflifetime = argv[5]->type == RANGE_TKN ? argv[5]->arg
1302 : argv[5]->text;
1303 }
1304 if (routeropts) {
1305 routeraddr =
1306 strmatch(argv[idx_routeropts]->text, "router-address");
1307 if (!routeraddr) {
1308 offlink = (argc > idx_routeropts + 1
1309 || strmatch(argv[idx_routeropts]->text,
1310 "off-link"));
1311 noautoconf = (argc > idx_routeropts + 1
1312 || strmatch(argv[idx_routeropts]->text,
1313 "no-autoconfig"));
1314 }
1315 }
1316
1317 /* business */
1318 VTY_DECLVAR_CONTEXT(interface, ifp);
1319 struct zebra_if *zebra_if = ifp->info;
1320 int ret;
1321 struct rtadv_prefix rp;
1322
1323 ret = str2prefix_ipv6(prefix, &rp.prefix);
1324 if (!ret) {
1325 vty_out(vty, "Malformed IPv6 prefix\n");
1326 return CMD_WARNING_CONFIG_FAILED;
1327 }
1328 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
1329 rp.AdvOnLinkFlag = !offlink;
1330 rp.AdvAutonomousFlag = !noautoconf;
1331 rp.AdvRouterAddressFlag = routeraddr;
1332 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1333 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
1334
1335 if (lifetimes) {
1336 rp.AdvValidLifetime = strmatch(lifetime, "infinite")
1337 ? UINT32_MAX
1338 : strtoll(lifetime, NULL, 10);
1339 rp.AdvPreferredLifetime =
1340 strmatch(preflifetime, "infinite")
1341 ? UINT32_MAX
1342 : strtoll(preflifetime, NULL, 10);
1343 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) {
1344 vty_out(vty, "Invalid preferred lifetime\n");
1345 return CMD_WARNING_CONFIG_FAILED;
1346 }
1347 }
1348
1349 rtadv_prefix_set(zebra_if, &rp);
1350
1351 return CMD_SUCCESS;
1352 }
1353
1354 DEFUN (no_ipv6_nd_prefix,
1355 no_ipv6_nd_prefix_cmd,
1356 "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]>]",
1357 NO_STR
1358 "Interface IPv6 config commands\n"
1359 "Neighbor discovery\n"
1360 "Prefix information\n"
1361 "IPv6 prefix\n"
1362 "Valid lifetime in seconds\n"
1363 "Infinite valid lifetime\n"
1364 "Preferred lifetime in seconds\n"
1365 "Infinite preferred lifetime\n"
1366 "Set Router Address flag\n"
1367 "Do not use prefix for onlink determination\n"
1368 "Do not use prefix for autoconfiguration\n"
1369 "Do not use prefix for autoconfiguration\n"
1370 "Do not use prefix for onlink determination\n")
1371 {
1372 VTY_DECLVAR_CONTEXT(interface, ifp);
1373 struct zebra_if *zebra_if = ifp->info;
1374 int ret;
1375 struct rtadv_prefix rp;
1376 char *prefix = argv[4]->arg;
1377
1378 ret = str2prefix_ipv6(prefix, &rp.prefix);
1379 if (!ret) {
1380 vty_out(vty, "Malformed IPv6 prefix\n");
1381 return CMD_WARNING_CONFIG_FAILED;
1382 }
1383 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
1384
1385 ret = rtadv_prefix_reset(zebra_if, &rp);
1386 if (!ret) {
1387 vty_out(vty, "Non-existant IPv6 prefix\n");
1388 return CMD_WARNING_CONFIG_FAILED;
1389 }
1390
1391 return CMD_SUCCESS;
1392 }
1393
1394 DEFUN (ipv6_nd_router_preference,
1395 ipv6_nd_router_preference_cmd,
1396 "ipv6 nd router-preference <high|medium|low>",
1397 "Interface IPv6 config commands\n"
1398 "Neighbor discovery\n"
1399 "Default router preference\n"
1400 "High default router preference\n"
1401 "Medium default router preference (default)\n"
1402 "Low default router preference\n")
1403 {
1404 int idx_high_medium_low = 3;
1405 VTY_DECLVAR_CONTEXT(interface, ifp);
1406 struct zebra_if *zif = ifp->info;
1407 int i = 0;
1408
1409 while (0 != rtadv_pref_strs[i]) {
1410 if (strncmp(argv[idx_high_medium_low]->arg, rtadv_pref_strs[i],
1411 1)
1412 == 0) {
1413 zif->rtadv.DefaultPreference = i;
1414 return CMD_SUCCESS;
1415 }
1416 i++;
1417 }
1418
1419 return CMD_ERR_NO_MATCH;
1420 }
1421
1422 DEFUN (no_ipv6_nd_router_preference,
1423 no_ipv6_nd_router_preference_cmd,
1424 "no ipv6 nd router-preference [<high|medium|low>]",
1425 NO_STR
1426 "Interface IPv6 config commands\n"
1427 "Neighbor discovery\n"
1428 "Default router preference\n"
1429 "High default router preference\n"
1430 "Medium default router preference (default)\n"
1431 "Low default router preference\n")
1432 {
1433 VTY_DECLVAR_CONTEXT(interface, ifp);
1434 struct zebra_if *zif = ifp->info;
1435
1436 zif->rtadv.DefaultPreference =
1437 RTADV_PREF_MEDIUM; /* Default per RFC4191. */
1438
1439 return CMD_SUCCESS;
1440 }
1441
1442 DEFUN (ipv6_nd_mtu,
1443 ipv6_nd_mtu_cmd,
1444 "ipv6 nd mtu (1-65535)",
1445 "Interface IPv6 config commands\n"
1446 "Neighbor discovery\n"
1447 "Advertised MTU\n"
1448 "MTU in bytes\n")
1449 {
1450 int idx_number = 3;
1451 VTY_DECLVAR_CONTEXT(interface, ifp);
1452 struct zebra_if *zif = ifp->info;
1453 zif->rtadv.AdvLinkMTU = strtoul(argv[idx_number]->arg, NULL, 10);
1454 return CMD_SUCCESS;
1455 }
1456
1457 DEFUN (no_ipv6_nd_mtu,
1458 no_ipv6_nd_mtu_cmd,
1459 "no ipv6 nd mtu [(1-65535)]",
1460 NO_STR
1461 "Interface IPv6 config commands\n"
1462 "Neighbor discovery\n"
1463 "Advertised MTU\n"
1464 "MTU in bytes\n")
1465 {
1466 VTY_DECLVAR_CONTEXT(interface, ifp);
1467 struct zebra_if *zif = ifp->info;
1468 zif->rtadv.AdvLinkMTU = 0;
1469 return CMD_SUCCESS;
1470 }
1471
1472 /* Dump interface ND information to vty. */
1473 static int nd_dump_vty(struct vty *vty, struct interface *ifp)
1474 {
1475 struct zebra_if *zif;
1476 struct rtadvconf *rtadv;
1477 int interval;
1478
1479 zif = (struct zebra_if *)ifp->info;
1480 rtadv = &zif->rtadv;
1481
1482 if (rtadv->AdvSendAdvertisements) {
1483 vty_out(vty,
1484 " ND advertised reachable time is %d milliseconds\n",
1485 rtadv->AdvReachableTime);
1486 vty_out(vty,
1487 " ND advertised retransmit interval is %d milliseconds\n",
1488 rtadv->AdvRetransTimer);
1489 vty_out(vty, " ND router advertisements sent: %d rcvd: %d\n",
1490 zif->ra_sent, zif->ra_rcvd);
1491 interval = rtadv->MaxRtrAdvInterval;
1492 if (interval % 1000)
1493 vty_out(vty,
1494 " ND router advertisements are sent every "
1495 "%d milliseconds\n",
1496 interval);
1497 else
1498 vty_out(vty,
1499 " ND router advertisements are sent every "
1500 "%d seconds\n",
1501 interval / 1000);
1502 if (rtadv->AdvDefaultLifetime != -1)
1503 vty_out(vty,
1504 " ND router advertisements live for %d seconds\n",
1505 rtadv->AdvDefaultLifetime);
1506 else
1507 vty_out(vty,
1508 " ND router advertisements lifetime tracks ra-interval\n");
1509 vty_out(vty,
1510 " ND router advertisement default router preference is "
1511 "%s\n",
1512 rtadv_pref_strs[rtadv->DefaultPreference]);
1513 if (rtadv->AdvManagedFlag)
1514 vty_out(vty,
1515 " Hosts use DHCP to obtain routable addresses.\n");
1516 else
1517 vty_out(vty,
1518 " Hosts use stateless autoconfig for addresses.\n");
1519 if (rtadv->AdvHomeAgentFlag) {
1520 vty_out(vty,
1521 " ND router advertisements with Home Agent flag bit set.\n");
1522 if (rtadv->HomeAgentLifetime != -1)
1523 vty_out(vty,
1524 " Home Agent lifetime is %u seconds\n",
1525 rtadv->HomeAgentLifetime);
1526 else
1527 vty_out(vty,
1528 " Home Agent lifetime tracks ra-lifetime\n");
1529 vty_out(vty, " Home Agent preference is %u\n",
1530 rtadv->HomeAgentPreference);
1531 }
1532 if (rtadv->AdvIntervalOption)
1533 vty_out(vty,
1534 " ND router advertisements with Adv. Interval option.\n");
1535 }
1536 return 0;
1537 }
1538
1539
1540 /* Write configuration about router advertisement. */
1541 static int rtadv_config_write(struct vty *vty, struct interface *ifp)
1542 {
1543 struct zebra_if *zif;
1544 struct listnode *node;
1545 struct rtadv_prefix *rprefix;
1546 char buf[PREFIX_STRLEN];
1547 int interval;
1548
1549 zif = ifp->info;
1550
1551 if (!(if_is_loopback(ifp)
1552 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))) {
1553 if (zif->rtadv.AdvSendAdvertisements)
1554 vty_out(vty, " no ipv6 nd suppress-ra\n");
1555 }
1556
1557 interval = zif->rtadv.MaxRtrAdvInterval;
1558 if (interval % 1000)
1559 vty_out(vty, " ipv6 nd ra-interval msec %d\n", interval);
1560 else if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
1561 vty_out(vty, " ipv6 nd ra-interval %d\n", interval / 1000);
1562
1563 if (zif->rtadv.AdvIntervalOption)
1564 vty_out(vty, " ipv6 nd adv-interval-option\n");
1565
1566 if (zif->rtadv.AdvDefaultLifetime != -1)
1567 vty_out(vty, " ipv6 nd ra-lifetime %d\n",
1568 zif->rtadv.AdvDefaultLifetime);
1569
1570 if (zif->rtadv.HomeAgentPreference)
1571 vty_out(vty, " ipv6 nd home-agent-preference %u\n",
1572 zif->rtadv.HomeAgentPreference);
1573
1574 if (zif->rtadv.HomeAgentLifetime != -1)
1575 vty_out(vty, " ipv6 nd home-agent-lifetime %u\n",
1576 zif->rtadv.HomeAgentLifetime);
1577
1578 if (zif->rtadv.AdvHomeAgentFlag)
1579 vty_out(vty, " ipv6 nd home-agent-config-flag\n");
1580
1581 if (zif->rtadv.AdvReachableTime)
1582 vty_out(vty, " ipv6 nd reachable-time %d\n",
1583 zif->rtadv.AdvReachableTime);
1584
1585 if (zif->rtadv.AdvManagedFlag)
1586 vty_out(vty, " ipv6 nd managed-config-flag\n");
1587
1588 if (zif->rtadv.AdvOtherConfigFlag)
1589 vty_out(vty, " ipv6 nd other-config-flag\n");
1590
1591 if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
1592 vty_out(vty, " ipv6 nd router-preference %s\n",
1593 rtadv_pref_strs[zif->rtadv.DefaultPreference]);
1594
1595 if (zif->rtadv.AdvLinkMTU)
1596 vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU);
1597
1598 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvPrefixList, node, rprefix)) {
1599 vty_out(vty, " ipv6 nd prefix %s",
1600 prefix2str(&rprefix->prefix, buf, sizeof(buf)));
1601 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME)
1602 || (rprefix->AdvPreferredLifetime
1603 != RTADV_PREFERRED_LIFETIME)) {
1604 if (rprefix->AdvValidLifetime == UINT32_MAX)
1605 vty_out(vty, " infinite");
1606 else
1607 vty_out(vty, " %u", rprefix->AdvValidLifetime);
1608 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1609 vty_out(vty, " infinite");
1610 else
1611 vty_out(vty, " %u",
1612 rprefix->AdvPreferredLifetime);
1613 }
1614 if (!rprefix->AdvOnLinkFlag)
1615 vty_out(vty, " off-link");
1616 if (!rprefix->AdvAutonomousFlag)
1617 vty_out(vty, " no-autoconfig");
1618 if (rprefix->AdvRouterAddressFlag)
1619 vty_out(vty, " router-address");
1620 vty_out(vty, "\n");
1621 }
1622 return 0;
1623 }
1624
1625
1626 static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
1627 {
1628 struct rtadv *rtadv = &zns->rtadv;
1629
1630 switch (event) {
1631 case RTADV_START:
1632 thread_add_read(zebrad.master, rtadv_read, zns, val,
1633 &rtadv->ra_read);
1634 thread_add_event(zebrad.master, rtadv_timer, zns, 0,
1635 &rtadv->ra_timer);
1636 break;
1637 case RTADV_STOP:
1638 if (rtadv->ra_timer) {
1639 thread_cancel(rtadv->ra_timer);
1640 rtadv->ra_timer = NULL;
1641 }
1642 if (rtadv->ra_read) {
1643 thread_cancel(rtadv->ra_read);
1644 rtadv->ra_read = NULL;
1645 }
1646 break;
1647 case RTADV_TIMER:
1648 thread_add_timer(zebrad.master, rtadv_timer, zns, val,
1649 &rtadv->ra_timer);
1650 break;
1651 case RTADV_TIMER_MSEC:
1652 thread_add_timer_msec(zebrad.master, rtadv_timer, zns, val,
1653 &rtadv->ra_timer);
1654 break;
1655 case RTADV_READ:
1656 thread_add_read(zebrad.master, rtadv_read, zns, val,
1657 &rtadv->ra_read);
1658 break;
1659 default:
1660 break;
1661 }
1662 return;
1663 }
1664
1665 void rtadv_init(struct zebra_ns *zns)
1666 {
1667 zns->rtadv.sock = rtadv_make_socket();
1668 }
1669
1670 void rtadv_terminate(struct zebra_ns *zns)
1671 {
1672 rtadv_event(zns, RTADV_STOP, 0);
1673 if (zns->rtadv.sock >= 0) {
1674 close(zns->rtadv.sock);
1675 zns->rtadv.sock = -1;
1676 }
1677
1678 zns->rtadv.adv_if_count = 0;
1679 zns->rtadv.adv_msec_if_count = 0;
1680 }
1681
1682 void rtadv_cmd_init(void)
1683 {
1684 hook_register(zebra_if_extra_info, nd_dump_vty);
1685 hook_register(zebra_if_config_wr, rtadv_config_write);
1686
1687 install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1688 install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
1689 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
1690 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
1691 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1692 install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1693 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1694 install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1695 install_element(INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1696 install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1697 install_element(INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1698 install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1699 install_element(INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
1700 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
1701 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
1702 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
1703 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
1704 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
1705 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
1706 install_element(INTERFACE_NODE,
1707 &ipv6_nd_adv_interval_config_option_cmd);
1708 install_element(INTERFACE_NODE,
1709 &no_ipv6_nd_adv_interval_config_option_cmd);
1710 install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd);
1711 install_element(INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
1712 install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
1713 install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
1714 install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd);
1715 install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
1716 }
1717
1718 static int if_join_all_router(int sock, struct interface *ifp)
1719 {
1720 int ret;
1721
1722 struct ipv6_mreq mreq;
1723
1724 memset(&mreq, 0, sizeof(struct ipv6_mreq));
1725 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1726 mreq.ipv6mr_interface = ifp->ifindex;
1727
1728 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq,
1729 sizeof mreq);
1730 if (ret < 0)
1731 zlog_warn("%s(%u): Failed to join group, socket %u error %s",
1732 ifp->name, ifp->ifindex, sock, safe_strerror(errno));
1733
1734 if (IS_ZEBRA_DEBUG_EVENT)
1735 zlog_debug(
1736 "%s(%u): Join All-Routers multicast group, socket %u",
1737 ifp->name, ifp->ifindex, sock);
1738
1739 return 0;
1740 }
1741
1742 static int if_leave_all_router(int sock, struct interface *ifp)
1743 {
1744 int ret;
1745
1746 struct ipv6_mreq mreq;
1747
1748 memset(&mreq, 0, sizeof(struct ipv6_mreq));
1749 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1750 mreq.ipv6mr_interface = ifp->ifindex;
1751
1752 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq,
1753 sizeof mreq);
1754 if (ret < 0)
1755 zlog_warn("%s(%u): Failed to leave group, socket %u error %s",
1756 ifp->name, ifp->ifindex, sock, safe_strerror(errno));
1757
1758 if (IS_ZEBRA_DEBUG_EVENT)
1759 zlog_debug(
1760 "%s(%u): Leave All-Routers multicast group, socket %u",
1761 ifp->name, ifp->ifindex, sock);
1762
1763 return 0;
1764 }
1765
1766 #else
1767 void rtadv_init(struct zebra_ns *zns)
1768 {
1769 /* Empty.*/;
1770 }
1771 void rtadv_terminate(struct zebra_ns *zns)
1772 {
1773 /* Empty.*/;
1774 }
1775 void rtadv_cmd_init(void)
1776 {
1777 /* Empty.*/;
1778 }
1779 #endif /* HAVE_RTADV */