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