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