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