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