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