]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rtadv.c
rmap: Add hooks into zebra,ospf,rip for `match ip next-hop type blackhole`
[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"
fe533c56 37#include "ns.h"
43e52561 38#include "lib_errors.h"
718e3744 39
40#include "zebra/interface.h"
41#include "zebra/rtadv.h"
42#include "zebra/debug.h"
537d8ea9 43#include "zebra/rib.h"
bf094f69 44#include "zebra/zapi_msg.h"
fe18ee2d 45#include "zebra/zebra_ns.h"
7c551956 46#include "zebra/zebra_vrf.h"
364fed6b 47#include "zebra/zebra_errors.h"
a3be9fa1 48#include "zebra/zebra_router.h"
718e3744 49
edd7c245 50extern struct zebra_privs_t zserv_privs;
51
d62a17ae 52#if defined(HAVE_RTADV)
718e3744 53
fa2b17e3 54#ifdef OPEN_BSD
55#include <netinet/icmp6.h>
56#endif
57
718e3744 58/* If RFC2133 definition is used. */
59#ifndef IPV6_JOIN_GROUP
60#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
61#endif
62#ifndef IPV6_LEAVE_GROUP
63#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
64#endif
65
66#define ALLNODE "ff02::1"
67#define ALLROUTER "ff02::2"
68
110765e3
LS
69DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS")
70DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL")
71
2eb27eec
DL
72/* Order is intentional. Matches RFC4191. This array is also used for
73 command matching, so only modify with care. */
74const char *rtadv_pref_strs[] = {"medium", "high", "INVALID", "low", 0};
75
d62a17ae 76enum rtadv_event {
77 RTADV_START,
78 RTADV_STOP,
79 RTADV_TIMER,
80 RTADV_TIMER_MSEC,
81 RTADV_READ
82};
718e3744 83
d62a17ae 84static void rtadv_event(struct zebra_ns *, enum rtadv_event, int);
718e3744 85
d62a17ae 86static int if_join_all_router(int, struct interface *);
87static int if_leave_all_router(int, struct interface *);
6b0655a2 88
d62a17ae 89static int rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex)
911ad1e2 90{
d62a17ae 91 int ret = -1;
92 struct interface *iface;
93 struct zebra_if *zif;
94
95 iface = if_lookup_by_index_per_ns(zns, *ifindex);
96 if (iface && iface->info) {
97 zif = iface->info;
98 zif->ra_rcvd++;
99 ret = 0;
100 }
101 return ret;
795b5abf
QY
102}
103
d7c0a89a 104static int rtadv_recv_packet(struct zebra_ns *zns, int sock, uint8_t *buf,
d62a17ae 105 int buflen, struct sockaddr_in6 *from,
106 ifindex_t *ifindex, int *hoplimit)
718e3744 107{
d62a17ae 108 int ret;
109 struct msghdr msg;
110 struct iovec iov;
111 struct cmsghdr *cmsgptr;
112 struct in6_addr dst;
113
114 char adata[1024];
115
116 /* Fill in message and iovec. */
0af35d90 117 memset(&msg, 0, sizeof(msg));
d62a17ae 118 msg.msg_name = (void *)from;
119 msg.msg_namelen = sizeof(struct sockaddr_in6);
120 msg.msg_iov = &iov;
121 msg.msg_iovlen = 1;
122 msg.msg_control = (void *)adata;
123 msg.msg_controllen = sizeof adata;
124 iov.iov_base = buf;
125 iov.iov_len = buflen;
126
127 /* If recvmsg fail return minus value. */
128 ret = recvmsg(sock, &msg, 0);
129 if (ret < 0)
130 return ret;
131
adf0e7c6 132 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
d62a17ae 133 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
134 /* I want interface index which this packet comes from. */
135 if (cmsgptr->cmsg_level == IPPROTO_IPV6
136 && cmsgptr->cmsg_type == IPV6_PKTINFO) {
137 struct in6_pktinfo *ptr;
138
139 ptr = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
140 *ifindex = ptr->ipi6_ifindex;
141 memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
142 }
143
144 /* Incoming packet's hop limit. */
145 if (cmsgptr->cmsg_level == IPPROTO_IPV6
146 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) {
147 int *hoptr = (int *)CMSG_DATA(cmsgptr);
148 *hoplimit = *hoptr;
149 }
b0b709ab 150 }
795b5abf 151
d62a17ae 152 rtadv_increment_received(zns, ifindex);
153 return ret;
718e3744 154}
155
156#define RTADV_MSG_SIZE 4096
157
158/* Send router advertisement packet. */
d62a17ae 159static void rtadv_send_packet(int sock, struct interface *ifp)
718e3744 160{
d62a17ae 161 struct msghdr msg;
162 struct iovec iov;
163 struct cmsghdr *cmsgptr;
164 struct in6_pktinfo *pkt;
165 struct sockaddr_in6 addr;
166 static void *adata = NULL;
167 unsigned char buf[RTADV_MSG_SIZE];
168 struct nd_router_advert *rtadv;
169 int ret;
170 int len = 0;
171 struct zebra_if *zif;
172 struct rtadv_prefix *rprefix;
d7c0a89a
QY
173 uint8_t all_nodes_addr[] = {0xff, 0x02, 0, 0, 0, 0, 0, 0,
174 0, 0, 0, 0, 0, 0, 0, 1};
d62a17ae 175 struct listnode *node;
d7c0a89a 176 uint16_t pkt_RouterLifetime;
d62a17ae 177
178 /*
179 * Allocate control message bufffer. This is dynamic because
180 * CMSG_SPACE is not guaranteed not to call a function. Note that
181 * the size will be different on different architectures due to
182 * differing alignment rules.
183 */
184 if (adata == NULL) {
185 /* XXX Free on shutdown. */
b8aa3767 186 adata = calloc(1, CMSG_SPACE(sizeof(struct in6_pktinfo)));
d62a17ae 187
b8aa3767 188 if (adata == NULL) {
9df414fe 189 zlog_debug(
d62a17ae 190 "rtadv_send_packet: can't malloc control data");
b8aa3767
DS
191 exit(-1);
192 }
d62a17ae 193 }
194
195 /* Logging of packet. */
196 if (IS_ZEBRA_DEBUG_PACKET)
197 zlog_debug("%s(%u): Tx RA, socket %u", ifp->name, ifp->ifindex,
198 sock);
199
200 /* Fill in sockaddr_in6. */
201 memset(&addr, 0, sizeof(struct sockaddr_in6));
202 addr.sin6_family = AF_INET6;
718e3744 203#ifdef SIN6_LEN
d62a17ae 204 addr.sin6_len = sizeof(struct sockaddr_in6);
718e3744 205#endif /* SIN6_LEN */
d62a17ae 206 addr.sin6_port = htons(IPPROTO_ICMPV6);
207 IPV6_ADDR_COPY(&addr.sin6_addr, all_nodes_addr);
208
209 /* Fetch interface information. */
210 zif = ifp->info;
211
212 /* Make router advertisement message. */
213 rtadv = (struct nd_router_advert *)buf;
214
215 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
216 rtadv->nd_ra_code = 0;
217 rtadv->nd_ra_cksum = 0;
218
219 rtadv->nd_ra_curhoplimit = 64;
220
221 /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
222 rtadv->nd_ra_flags_reserved = zif->rtadv.AdvDefaultLifetime == 0
223 ? 0
224 : zif->rtadv.DefaultPreference;
225 rtadv->nd_ra_flags_reserved <<= 3;
226
227 if (zif->rtadv.AdvManagedFlag)
228 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
229 if (zif->rtadv.AdvOtherConfigFlag)
230 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
231 if (zif->rtadv.AdvHomeAgentFlag)
232 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
233 /* Note that according to Neighbor Discovery (RFC 4861 [18]),
234 * AdvDefaultLifetime is by default based on the value of
235 * MaxRtrAdvInterval. AdvDefaultLifetime is used in the Router Lifetime
236 * field of Router Advertisements. Given that this field is expressed
237 * in seconds, a small MaxRtrAdvInterval value can result in a zero
238 * value for this field. To prevent this, routers SHOULD keep
239 * AdvDefaultLifetime in at least one second, even if the use of
240 * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */
241 pkt_RouterLifetime =
242 zif->rtadv.AdvDefaultLifetime != -1
243 ? zif->rtadv.AdvDefaultLifetime
244 : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
245 rtadv->nd_ra_router_lifetime = htons(pkt_RouterLifetime);
246 rtadv->nd_ra_reachable = htonl(zif->rtadv.AdvReachableTime);
247 rtadv->nd_ra_retransmit = htonl(0);
248
249 len = sizeof(struct nd_router_advert);
250
251 /* If both the Home Agent Preference and Home Agent Lifetime are set to
252 * their default values specified above, this option SHOULD NOT be
253 * included in the Router Advertisement messages sent by this home
254 * agent. -- RFC6275, 7.4 */
255 if (zif->rtadv.AdvHomeAgentFlag
256 && (zif->rtadv.HomeAgentPreference
257 || zif->rtadv.HomeAgentLifetime != -1)) {
258 struct nd_opt_homeagent_info *ndopt_hai =
259 (struct nd_opt_homeagent_info *)(buf + len);
260 ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
261 ndopt_hai->nd_opt_hai_len = 1;
262 ndopt_hai->nd_opt_hai_reserved = 0;
263 ndopt_hai->nd_opt_hai_preference =
264 htons(zif->rtadv.HomeAgentPreference);
265 /* 16-bit unsigned integer. The lifetime associated with the
266 * home
267 * agent in units of seconds. The default value is the same as
268 * the
269 * Router Lifetime, as specified in the main body of the Router
270 * Advertisement. The maximum value corresponds to 18.2 hours.
271 * A
272 * value of 0 MUST NOT be used. -- RFC6275, 7.5 */
273 ndopt_hai->nd_opt_hai_lifetime =
274 htons(zif->rtadv.HomeAgentLifetime != -1
275 ? zif->rtadv.HomeAgentLifetime
276 : MAX(1, pkt_RouterLifetime) /* 0 is OK
277 for RL,
278 but not
279 for HAL*/
9d303b37 280 );
d62a17ae 281 len += sizeof(struct nd_opt_homeagent_info);
282 }
718e3744 283
d62a17ae 284 if (zif->rtadv.AdvIntervalOption) {
285 struct nd_opt_adv_interval *ndopt_adv =
286 (struct nd_opt_adv_interval *)(buf + len);
287 ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL;
288 ndopt_adv->nd_opt_ai_len = 1;
289 ndopt_adv->nd_opt_ai_reserved = 0;
290 ndopt_adv->nd_opt_ai_interval =
291 htonl(zif->rtadv.MaxRtrAdvInterval);
292 len += sizeof(struct nd_opt_adv_interval);
293 }
294
295 /* Fill in prefix. */
296 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvPrefixList, node, rprefix)) {
297 struct nd_opt_prefix_info *pinfo;
718e3744 298
d62a17ae 299 pinfo = (struct nd_opt_prefix_info *)(buf + len);
718e3744 300
d62a17ae 301 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
302 pinfo->nd_opt_pi_len = 4;
303 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
304
305 pinfo->nd_opt_pi_flags_reserved = 0;
306 if (rprefix->AdvOnLinkFlag)
307 pinfo->nd_opt_pi_flags_reserved |=
308 ND_OPT_PI_FLAG_ONLINK;
309 if (rprefix->AdvAutonomousFlag)
310 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
311 if (rprefix->AdvRouterAddressFlag)
312 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
313
314 pinfo->nd_opt_pi_valid_time = htonl(rprefix->AdvValidLifetime);
315 pinfo->nd_opt_pi_preferred_time =
316 htonl(rprefix->AdvPreferredLifetime);
317 pinfo->nd_opt_pi_reserved2 = 0;
318
319 IPV6_ADDR_COPY(&pinfo->nd_opt_pi_prefix,
320 &rprefix->prefix.prefix);
321
322#ifdef DEBUG
323 {
d7c0a89a 324 uint8_t buf[INET6_ADDRSTRLEN];
d62a17ae 325
326 zlog_debug("DEBUG %s",
327 inet_ntop(AF_INET6, &pinfo->nd_opt_pi_prefix,
328 buf, INET6_ADDRSTRLEN));
329 }
718e3744 330#endif /* DEBUG */
331
d62a17ae 332 len += sizeof(struct nd_opt_prefix_info);
333 }
334
335 /* Hardware address. */
336 if (ifp->hw_addr_len != 0) {
337 buf[len++] = ND_OPT_SOURCE_LINKADDR;
338
339 /* Option length should be rounded up to next octet if
340 the link address does not end on an octet boundary. */
341 buf[len++] = (ifp->hw_addr_len + 9) >> 3;
342
343 memcpy(buf + len, ifp->hw_addr, ifp->hw_addr_len);
344 len += ifp->hw_addr_len;
345
346 /* Pad option to end on an octet boundary. */
347 memset(buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7);
348 len += -(ifp->hw_addr_len + 2) & 0x7;
349 }
350
351 /* MTU */
352 if (zif->rtadv.AdvLinkMTU) {
353 struct nd_opt_mtu *opt = (struct nd_opt_mtu *)(buf + len);
354 opt->nd_opt_mtu_type = ND_OPT_MTU;
355 opt->nd_opt_mtu_len = 1;
356 opt->nd_opt_mtu_reserved = 0;
357 opt->nd_opt_mtu_mtu = htonl(zif->rtadv.AdvLinkMTU);
358 len += sizeof(struct nd_opt_mtu);
359 }
360
7eab94f9
LS
361 /*
362 * There is no limit on the number of configurable recursive DNS
363 * servers or search list entries. We don't want the RA message
364 * to exceed the link's MTU (risking fragmentation) or even
365 * blow the stack buffer allocated for it.
366 */
367 size_t max_len = MIN(ifp->mtu6 - 40, sizeof(buf));
368
3eb4fbb0
LS
369 /* Recursive DNS servers */
370 struct rtadv_rdnss *rdnss;
371
372 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) {
7eab94f9
LS
373 size_t opt_len =
374 sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr);
375
376 if (len + opt_len > max_len) {
377 zlog_warn(
378 "%s(%u): Tx RA: RDNSS option would exceed MTU, omitting it",
379 ifp->name, ifp->ifindex);
380 goto no_more_opts;
381 }
3eb4fbb0
LS
382 struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len);
383
384 opt->nd_opt_rdnss_type = ND_OPT_RDNSS;
7eab94f9 385 opt->nd_opt_rdnss_len = opt_len / 8;
3eb4fbb0
LS
386 opt->nd_opt_rdnss_reserved = 0;
387 opt->nd_opt_rdnss_lifetime = htonl(
388 rdnss->lifetime_set
389 ? rdnss->lifetime
390 : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval));
391
392 len += sizeof(struct nd_opt_rdnss);
7eab94f9 393
3eb4fbb0
LS
394 IPV6_ADDR_COPY(buf + len, &rdnss->addr);
395 len += sizeof(struct in6_addr);
396 }
397
398 /* DNS search list */
399 struct rtadv_dnssl *dnssl;
400
401 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) {
7eab94f9
LS
402 size_t opt_len = sizeof(struct nd_opt_dnssl)
403 + ((dnssl->encoded_len + 7) & ~7);
404
405 if (len + opt_len > max_len) {
406 zlog_warn(
407 "%s(%u): Tx RA: DNSSL option would exceed MTU, omitting it",
408 ifp->name, ifp->ifindex);
409 goto no_more_opts;
410 }
3eb4fbb0
LS
411 struct nd_opt_dnssl *opt = (struct nd_opt_dnssl *)(buf + len);
412
413 opt->nd_opt_dnssl_type = ND_OPT_DNSSL;
7eab94f9 414 opt->nd_opt_dnssl_len = opt_len / 8;
3eb4fbb0
LS
415 opt->nd_opt_dnssl_reserved = 0;
416 opt->nd_opt_dnssl_lifetime = htonl(
417 dnssl->lifetime_set
418 ? dnssl->lifetime
419 : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval));
420
421 len += sizeof(struct nd_opt_dnssl);
422
3eb4fbb0
LS
423 memcpy(buf + len, dnssl->encoded_name, dnssl->encoded_len);
424 len += dnssl->encoded_len;
425
426 /* Zero-pad to 8-octet boundary */
427 while (len % 8)
428 buf[len++] = '\0';
3eb4fbb0
LS
429 }
430
7eab94f9
LS
431no_more_opts:
432
d62a17ae 433 msg.msg_name = (void *)&addr;
434 msg.msg_namelen = sizeof(struct sockaddr_in6);
435 msg.msg_iov = &iov;
436 msg.msg_iovlen = 1;
437 msg.msg_control = (void *)adata;
438 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
439 msg.msg_flags = 0;
440 iov.iov_base = buf;
441 iov.iov_len = len;
442
adf0e7c6 443 cmsgptr = CMSG_FIRSTHDR(&msg);
d62a17ae 444 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
445 cmsgptr->cmsg_level = IPPROTO_IPV6;
446 cmsgptr->cmsg_type = IPV6_PKTINFO;
447
448 pkt = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
449 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
450 pkt->ipi6_ifindex = ifp->ifindex;
451
452 ret = sendmsg(sock, &msg, 0);
453 if (ret < 0) {
450971aa 454 flog_err_sys(EC_LIB_SOCKET,
09c866e3
QY
455 "%s(%u): Tx RA failed, socket %u error %d (%s)",
456 ifp->name, ifp->ifindex, sock, errno,
457 safe_strerror(errno));
d62a17ae 458 } else
459 zif->ra_sent++;
718e3744 460}
461
d62a17ae 462static int rtadv_timer(struct thread *thread)
718e3744 463{
d62a17ae 464 struct zebra_ns *zns = THREAD_ARG(thread);
465 struct vrf *vrf;
d62a17ae 466 struct interface *ifp;
467 struct zebra_if *zif;
468 int period;
469
a3be9fa1
DS
470 zrouter.rtadv.ra_timer = NULL;
471 if (zrouter.rtadv.adv_msec_if_count == 0) {
d62a17ae 472 period = 1000; /* 1 s */
473 rtadv_event(zns, RTADV_TIMER, 1 /* 1 s */);
474 } else {
475 period = 10; /* 10 ms */
476 rtadv_event(zns, RTADV_TIMER_MSEC, 10 /* 10 ms */);
477 }
478
a2addae8 479 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
451fda4f 480 FOR_ALL_INTERFACES (vrf, ifp) {
a2addae8
RW
481 if (if_is_loopback(ifp)
482 || CHECK_FLAG(ifp->status,
483 ZEBRA_INTERFACE_VRF_LOOPBACK)
484 || !if_is_operative(ifp))
485 continue;
486
487 zif = ifp->info;
488
489 if (zif->rtadv.AdvSendAdvertisements) {
490 if (zif->rtadv.inFastRexmit) {
491 /* We assume we fast rexmit every sec so
492 * no
493 * additional vars */
494 if (--zif->rtadv.NumFastReXmitsRemain
495 <= 0)
496 zif->rtadv.inFastRexmit = 0;
497
498 if (IS_ZEBRA_DEBUG_SEND)
499 zlog_debug(
500 "Fast RA Rexmit on interface %s",
501 ifp->name);
502
a3be9fa1
DS
503 rtadv_send_packet(zrouter.rtadv.sock,
504 ifp);
a2addae8
RW
505 } else {
506 zif->rtadv.AdvIntervalTimer -= period;
507 if (zif->rtadv.AdvIntervalTimer <= 0) {
508 /* FIXME: using
509 MaxRtrAdvInterval each
510 time isn't what section
511 6.2.4 of RFC4861 tells to do.
512 */
513 zif->rtadv.AdvIntervalTimer =
514 zif->rtadv
515 .MaxRtrAdvInterval;
516 rtadv_send_packet(
a3be9fa1
DS
517 zrouter.rtadv.sock,
518 ifp);
a2addae8 519 }
d62a17ae 520 }
521 }
522 }
d62a17ae 523
524 return 0;
718e3744 525}
526
d62a17ae 527static void rtadv_process_solicit(struct interface *ifp)
718e3744 528{
d62a17ae 529 struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
530 struct zebra_ns *zns = zvrf->zns;
718e3744 531
d62a17ae 532 assert(zns);
a3be9fa1 533 rtadv_send_packet(zrouter.rtadv.sock, ifp);
718e3744 534}
535
71974bf5
DS
536/*
537 * This function processes optional attributes off of
538 * end of a RA packet received. At this point in
539 * time we only care about this in one situation
540 * which is when a interface does not have a LL
541 * v6 address. We still need to be able to install
542 * the mac address for v4 to v6 resolution
543 */
544static void rtadv_process_optional(uint8_t *optional, unsigned int len,
545 struct interface *ifp,
546 struct sockaddr_in6 *addr)
547{
548 char *mac;
549
550 while (len > 0) {
551 struct nd_opt_hdr *opt_hdr = (struct nd_opt_hdr *)optional;
552
553 switch(opt_hdr->nd_opt_type) {
554 case ND_OPT_SOURCE_LINKADDR:
555 mac = (char *)(optional+2);
556 if_nbr_mac_to_ipv4ll_neigh_update(ifp, mac,
557 &addr->sin6_addr, 1);
558 break;
559 default:
560 break;
561 }
562
563 len -= 8 * opt_hdr->nd_opt_len;
564 optional += 8 * opt_hdr->nd_opt_len;
565 }
566}
567
d7c0a89a 568static void rtadv_process_advert(uint8_t *msg, unsigned int len,
d62a17ae 569 struct interface *ifp,
570 struct sockaddr_in6 *addr)
718e3744 571{
d62a17ae 572 struct nd_router_advert *radvert;
573 char addr_str[INET6_ADDRSTRLEN];
574 struct zebra_if *zif;
575 struct prefix p;
718e3744 576
d62a17ae 577 zif = ifp->info;
a80beece 578
d62a17ae 579 inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
580
581 if (len < sizeof(struct nd_router_advert)) {
71974bf5
DS
582 if (IS_ZEBRA_DEBUG_PACKET)
583 zlog_debug("%s(%u): Rx RA with invalid length %d from %s",
584 ifp->name, ifp->ifindex, len, addr_str);
d62a17ae 585 return;
586 }
71974bf5 587
d62a17ae 588 if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
71974bf5
DS
589 rtadv_process_optional(msg + sizeof(struct nd_router_advert),
590 len - sizeof(struct nd_router_advert),
591 ifp, addr);
592 if (IS_ZEBRA_DEBUG_PACKET)
593 zlog_debug("%s(%u): Rx RA with non-linklocal source address from %s",
594 ifp->name, ifp->ifindex, addr_str);
d62a17ae 595 return;
596 }
597
598 radvert = (struct nd_router_advert *)msg;
599
600 if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit)
601 && (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit)) {
9df414fe 602 flog_warn(
e914ccbe 603 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 604 "%s(%u): Rx RA - our AdvCurHopLimit doesn't agree with %s",
605 ifp->name, ifp->ifindex, addr_str);
606 }
607
608 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
609 && !zif->rtadv.AdvManagedFlag) {
9df414fe 610 flog_warn(
e914ccbe 611 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 612 "%s(%u): Rx RA - our AdvManagedFlag doesn't agree with %s",
613 ifp->name, ifp->ifindex, addr_str);
614 }
615
616 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
617 && !zif->rtadv.AdvOtherConfigFlag) {
9df414fe 618 flog_warn(
e914ccbe 619 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 620 "%s(%u): Rx RA - our AdvOtherConfigFlag doesn't agree with %s",
621 ifp->name, ifp->ifindex, addr_str);
622 }
623
624 if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime)
625 && (ntohl(radvert->nd_ra_reachable)
626 != zif->rtadv.AdvReachableTime)) {
9df414fe 627 flog_warn(
e914ccbe 628 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 629 "%s(%u): Rx RA - our AdvReachableTime doesn't agree with %s",
630 ifp->name, ifp->ifindex, addr_str);
631 }
632
633 if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer)
634 && (ntohl(radvert->nd_ra_retransmit)
635 != (unsigned int)zif->rtadv.AdvRetransTimer)) {
9df414fe 636 flog_warn(
e914ccbe 637 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 638 "%s(%u): Rx RA - our AdvRetransTimer doesn't agree with %s",
639 ifp->name, ifp->ifindex, addr_str);
640 }
641
642 /* Create entry for neighbor if not known. */
643 p.family = AF_INET6;
a85297a7 644 IPV6_ADDR_COPY(&p.u.prefix6, &addr->sin6_addr);
d62a17ae 645 p.prefixlen = IPV6_MAX_PREFIXLEN;
646
647 if (!nbr_connected_check(ifp, &p))
648 nbr_connected_add_ipv6(ifp, &addr->sin6_addr);
718e3744 649}
650
d62a17ae 651
d7c0a89a 652static void rtadv_process_packet(uint8_t *buf, unsigned int len,
d62a17ae 653 ifindex_t ifindex, int hoplimit,
654 struct sockaddr_in6 *from,
655 struct zebra_ns *zns)
718e3744 656{
d62a17ae 657 struct icmp6_hdr *icmph;
658 struct interface *ifp;
659 struct zebra_if *zif;
660 char addr_str[INET6_ADDRSTRLEN];
661
662 inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN);
663
664 /* Interface search. */
665 ifp = if_lookup_by_index_per_ns(zns, ifindex);
666 if (ifp == NULL) {
e914ccbe 667 flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
9df414fe 668 "RA/RS received on unknown IF %u from %s", ifindex,
d62a17ae 669 addr_str);
670 return;
671 }
672
673 if (IS_ZEBRA_DEBUG_PACKET)
674 zlog_debug("%s(%u): Rx RA/RS len %d from %s", ifp->name,
675 ifp->ifindex, len, addr_str);
676
677 if (if_is_loopback(ifp)
678 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))
679 return;
718e3744 680
d62a17ae 681 /* Check interface configuration. */
682 zif = ifp->info;
683 if (!zif->rtadv.AdvSendAdvertisements)
684 return;
718e3744 685
d62a17ae 686 /* ICMP message length check. */
687 if (len < sizeof(struct icmp6_hdr)) {
9df414fe
QY
688 zlog_debug("%s(%u): Rx RA with Invalid ICMPV6 packet length %d",
689 ifp->name, ifp->ifindex, len);
d62a17ae 690 return;
691 }
692
693 icmph = (struct icmp6_hdr *)buf;
718e3744 694
d62a17ae 695 /* ICMP message type check. */
696 if (icmph->icmp6_type != ND_ROUTER_SOLICIT
697 && icmph->icmp6_type != ND_ROUTER_ADVERT) {
9df414fe
QY
698 zlog_debug("%s(%u): Rx RA - Unwanted ICMPV6 message type %d",
699 ifp->name, ifp->ifindex, icmph->icmp6_type);
d62a17ae 700 return;
701 }
718e3744 702
d62a17ae 703 /* Hoplimit check. */
704 if (hoplimit >= 0 && hoplimit != 255) {
9df414fe
QY
705 zlog_debug("%s(%u): Rx RA - Invalid hoplimit %d", ifp->name,
706 ifp->ifindex, hoplimit);
d62a17ae 707 return;
708 }
718e3744 709
d62a17ae 710 /* Check ICMP message type. */
711 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
712 rtadv_process_solicit(ifp);
713 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
714 rtadv_process_advert(buf, len, ifp, from);
718e3744 715
d62a17ae 716 return;
718e3744 717}
718
d62a17ae 719static int rtadv_read(struct thread *thread)
718e3744 720{
d62a17ae 721 int sock;
722 int len;
d7c0a89a 723 uint8_t buf[RTADV_MSG_SIZE];
d62a17ae 724 struct sockaddr_in6 from;
725 ifindex_t ifindex = 0;
726 int hoplimit = -1;
727 struct zebra_ns *zns = THREAD_ARG(thread);
728
729 sock = THREAD_FD(thread);
a3be9fa1 730 zrouter.rtadv.ra_read = NULL;
d62a17ae 731
732 /* Register myself. */
733 rtadv_event(zns, RTADV_READ, sock);
734
735 len = rtadv_recv_packet(zns, sock, buf, sizeof(buf), &from, &ifindex,
736 &hoplimit);
737
738 if (len < 0) {
450971aa 739 flog_err_sys(EC_LIB_SOCKET,
9df414fe
QY
740 "RA/RS recv failed, socket %u error %s", sock,
741 safe_strerror(errno));
d62a17ae 742 return len;
743 }
744
745 rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zns);
746
747 return 0;
718e3744 748}
6b0655a2 749
fe533c56 750static int rtadv_make_socket(ns_id_t ns_id)
718e3744 751{
8d2dcc85 752 int sock = -1;
d62a17ae 753 int ret = 0;
754 struct icmp6_filter filter;
755
01b9e3fd 756 frr_elevate_privs(&zserv_privs) {
d62a17ae 757
01b9e3fd 758 sock = ns_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, ns_id);
d62a17ae 759
01b9e3fd 760 }
d62a17ae 761
762 if (sock < 0) {
d62a17ae 763 return -1;
764 }
765
766 ret = setsockopt_ipv6_pktinfo(sock, 1);
767 if (ret < 0) {
768 close(sock);
769 return ret;
770 }
771 ret = setsockopt_ipv6_multicast_loop(sock, 0);
772 if (ret < 0) {
773 close(sock);
774 return ret;
775 }
776 ret = setsockopt_ipv6_unicast_hops(sock, 255);
777 if (ret < 0) {
778 close(sock);
779 return ret;
780 }
781 ret = setsockopt_ipv6_multicast_hops(sock, 255);
782 if (ret < 0) {
783 close(sock);
784 return ret;
785 }
786 ret = setsockopt_ipv6_hoplimit(sock, 1);
787 if (ret < 0) {
788 close(sock);
789 return ret;
790 }
791
792 ICMP6_FILTER_SETBLOCKALL(&filter);
793 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
794 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
795
796 ret = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
797 sizeof(struct icmp6_filter));
798 if (ret < 0) {
799 zlog_info("ICMP6_FILTER set fail: %s", safe_strerror(errno));
44f12f20 800 close(sock);
d62a17ae 801 return ret;
802 }
803
804 return sock;
718e3744 805}
806
d62a17ae 807static struct rtadv_prefix *rtadv_prefix_new(void)
718e3744 808{
d62a17ae 809 return XCALLOC(MTYPE_RTADV_PREFIX, sizeof(struct rtadv_prefix));
718e3744 810}
811
d62a17ae 812static void rtadv_prefix_free(struct rtadv_prefix *rtadv_prefix)
718e3744 813{
d62a17ae 814 XFREE(MTYPE_RTADV_PREFIX, rtadv_prefix);
815}
718e3744 816
d62a17ae 817static struct rtadv_prefix *rtadv_prefix_lookup(struct list *rplist,
818 struct prefix_ipv6 *p)
819{
820 struct listnode *node;
821 struct rtadv_prefix *rprefix;
822
823 for (ALL_LIST_ELEMENTS_RO(rplist, node, rprefix))
824 if (prefix_same((struct prefix *)&rprefix->prefix,
825 (struct prefix *)p))
826 return rprefix;
827 return NULL;
718e3744 828}
829
d62a17ae 830static struct rtadv_prefix *rtadv_prefix_get(struct list *rplist,
831 struct prefix_ipv6 *p)
718e3744 832{
d62a17ae 833 struct rtadv_prefix *rprefix;
834
835 rprefix = rtadv_prefix_lookup(rplist, p);
836 if (rprefix)
837 return rprefix;
718e3744 838
d62a17ae 839 rprefix = rtadv_prefix_new();
840 memcpy(&rprefix->prefix, p, sizeof(struct prefix_ipv6));
841 listnode_add(rplist, rprefix);
718e3744 842
d62a17ae 843 return rprefix;
718e3744 844}
845
d62a17ae 846static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp)
718e3744 847{
d62a17ae 848 struct rtadv_prefix *rprefix;
849
850 rprefix = rtadv_prefix_get(zif->rtadv.AdvPrefixList, &rp->prefix);
851
852 /* Set parameters. */
853 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
854 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
855 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
856 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
857 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
718e3744 858}
859
d62a17ae 860static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp)
718e3744 861{
d62a17ae 862 struct rtadv_prefix *rprefix;
863
864 rprefix = rtadv_prefix_lookup(zif->rtadv.AdvPrefixList, &rp->prefix);
865 if (rprefix != NULL) {
866 listnode_delete(zif->rtadv.AdvPrefixList, (void *)rprefix);
867 rtadv_prefix_free(rprefix);
868 return 1;
869 } else
870 return 0;
718e3744 871}
872
d62a17ae 873static void ipv6_nd_suppress_ra_set(struct interface *ifp,
874 ipv6_nd_suppress_ra_status status)
b6120505 875{
d62a17ae 876 struct zebra_if *zif;
877 struct zebra_vrf *zvrf;
878 struct zebra_ns *zns;
879
880 zif = ifp->info;
881 zvrf = vrf_info_lookup(ifp->vrf_id);
882 zns = zvrf->zns;
883
884 if (status == RA_SUPPRESS) {
885 /* RA is currently enabled */
886 if (zif->rtadv.AdvSendAdvertisements) {
887 zif->rtadv.AdvSendAdvertisements = 0;
888 zif->rtadv.AdvIntervalTimer = 0;
a3be9fa1 889 zrouter.rtadv.adv_if_count--;
d62a17ae 890
a3be9fa1 891 if_leave_all_router(zrouter.rtadv.sock, ifp);
d62a17ae 892
a3be9fa1 893 if (zrouter.rtadv.adv_if_count == 0)
d62a17ae 894 rtadv_event(zns, RTADV_STOP, 0);
895 }
896 } else {
897 if (!zif->rtadv.AdvSendAdvertisements) {
898 zif->rtadv.AdvSendAdvertisements = 1;
899 zif->rtadv.AdvIntervalTimer = 0;
a3be9fa1 900 zrouter.rtadv.adv_if_count++;
d62a17ae 901
902 if (zif->rtadv.MaxRtrAdvInterval >= 1000) {
903 /* Enable Fast RA only when RA interval is in
904 * secs */
905 zif->rtadv.inFastRexmit = 1;
906 zif->rtadv.NumFastReXmitsRemain =
907 RTADV_NUM_FAST_REXMITS;
908 }
909
a3be9fa1 910 if_join_all_router(zrouter.rtadv.sock, ifp);
d62a17ae 911
a3be9fa1
DS
912 if (zrouter.rtadv.adv_if_count == 1)
913 rtadv_event(zns, RTADV_START,
914 zrouter.rtadv.sock);
d62a17ae 915 }
916 }
b6120505
DW
917}
918
4a04e5f7 919/*
920 * Handle client (BGP) message to enable or disable IPv6 RA on an interface.
921 * Note that while the client could request RA on an interface on which the
922 * operator has not enabled RA, RA won't be disabled upon client request
5c81b96a 923 * if the operator has explicitly enabled RA. The enable request can also
924 * specify a RA interval (in seconds).
4a04e5f7 925 */
1002497a 926static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
4a04e5f7 927{
d62a17ae 928 struct stream *s;
ec93aa12 929 ifindex_t ifindex;
d62a17ae 930 struct interface *ifp;
931 struct zebra_if *zif;
932 int ra_interval;
933
1002497a 934 s = msg;
d62a17ae 935
936 /* Get interface index and RA interval. */
ec93aa12
DS
937 STREAM_GETL(s, ifindex);
938 STREAM_GETL(s, ra_interval);
d62a17ae 939
940 if (IS_ZEBRA_DEBUG_EVENT)
941 zlog_debug("%u: IF %u RA %s from client %s, interval %ds",
1002497a
QY
942 zvrf_id(zvrf), ifindex,
943 enable ? "enable" : "disable",
d62a17ae 944 zebra_route_string(client->proto), ra_interval);
945
946 /* Locate interface and check VRF match. */
947 ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex);
948 if (!ifp) {
e914ccbe 949 flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
9df414fe 950 "%u: IF %u RA %s client %s - interface unknown",
1002497a 951 zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
d62a17ae 952 zebra_route_string(client->proto));
953 return;
954 }
955 if (ifp->vrf_id != zvrf_id(zvrf)) {
9df414fe
QY
956 zlog_debug(
957 "%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
958 zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
959 zebra_route_string(client->proto), ifp->vrf_id);
d62a17ae 960 return;
961 }
962
963 zif = ifp->info;
1002497a 964 if (enable) {
3ea48364 965 SET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
d62a17ae 966 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
967 if (ra_interval
996c9314
LB
968 && (ra_interval * 1000) < zif->rtadv.MaxRtrAdvInterval
969 && !CHECK_FLAG(zif->rtadv.ra_configured,
970 VTY_RA_INTERVAL_CONFIGURED))
d62a17ae 971 zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000;
972 } else {
3ea48364
DS
973 UNSET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
974 if (!CHECK_FLAG(zif->rtadv.ra_configured,
975 VTY_RA_INTERVAL_CONFIGURED))
d62a17ae 976 zif->rtadv.MaxRtrAdvInterval =
977 RTADV_MAX_RTR_ADV_INTERVAL;
3ea48364 978 if (!CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
d62a17ae 979 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
d62a17ae 980 }
ec93aa12
DS
981stream_failure:
982 return;
4a04e5f7 983}
984
89f4e507
QY
985void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS)
986{
1002497a 987 zebra_interface_radv_set(client, hdr, msg, zvrf, 0);
89f4e507 988}
89f4e507
QY
989void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS)
990{
1002497a 991 zebra_interface_radv_set(client, hdr, msg, zvrf, 1);
89f4e507
QY
992}
993
718e3744 994DEFUN (ipv6_nd_suppress_ra,
995 ipv6_nd_suppress_ra_cmd,
996 "ipv6 nd suppress-ra",
3e31cded 997 "Interface IPv6 config commands\n"
718e3744 998 "Neighbor discovery\n"
999 "Suppress Router Advertisement\n")
1000{
d62a17ae 1001 VTY_DECLVAR_CONTEXT(interface, ifp);
1002 struct zebra_if *zif = ifp->info;
1003
1004 if (if_is_loopback(ifp)
1005 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
1006 vty_out(vty,
1007 "Cannot configure IPv6 Router Advertisements on this interface\n");
1008 return CMD_WARNING_CONFIG_FAILED;
1009 }
1010
3ea48364
DS
1011 if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1012 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
1013
1014 UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
d62a17ae 1015 return CMD_SUCCESS;
718e3744 1016}
1017
718e3744 1018DEFUN (no_ipv6_nd_suppress_ra,
1019 no_ipv6_nd_suppress_ra_cmd,
1020 "no ipv6 nd suppress-ra",
1021 NO_STR
3e31cded 1022 "Interface IPv6 config commands\n"
718e3744 1023 "Neighbor discovery\n"
1024 "Suppress Router Advertisement\n")
1025{
d62a17ae 1026 VTY_DECLVAR_CONTEXT(interface, ifp);
1027 struct zebra_if *zif = ifp->info;
1028
1029 if (if_is_loopback(ifp)
1030 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
1031 vty_out(vty,
1032 "Cannot configure IPv6 Router Advertisements on this interface\n");
1033 return CMD_WARNING_CONFIG_FAILED;
1034 }
1035
1036 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
3ea48364 1037 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
d62a17ae 1038 return CMD_SUCCESS;
718e3744 1039}
1040
7cee1bb1 1041DEFUN (ipv6_nd_ra_interval_msec,
1042 ipv6_nd_ra_interval_msec_cmd,
6147e2c6 1043 "ipv6 nd ra-interval msec (70-1800000)",
7cee1bb1 1044 "Interface IPv6 config commands\n"
1045 "Neighbor discovery\n"
1046 "Router Advertisement interval\n"
3a2d747c 1047 "Router Advertisement interval in milliseconds\n"
7cee1bb1 1048 "Router Advertisement interval in milliseconds\n")
1049{
d62a17ae 1050 int idx_number = 4;
1051 VTY_DECLVAR_CONTEXT(interface, ifp);
1052 unsigned interval;
1053 struct zebra_if *zif = ifp->info;
d62a17ae 1054
d62a17ae 1055 interval = strtoul(argv[idx_number]->arg, NULL, 10);
1056 if ((zif->rtadv.AdvDefaultLifetime != -1
1057 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) {
1058 vty_out(vty,
1059 "This ra-interval would conflict with configured ra-lifetime!\n");
1060 return CMD_WARNING_CONFIG_FAILED;
1061 }
1062
1063 if (zif->rtadv.MaxRtrAdvInterval % 1000)
a3be9fa1 1064 zrouter.rtadv.adv_msec_if_count--;
d62a17ae 1065
1066 if (interval % 1000)
a3be9fa1 1067 zrouter.rtadv.adv_msec_if_count++;
d62a17ae 1068
3ea48364 1069 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
d62a17ae 1070 zif->rtadv.MaxRtrAdvInterval = interval;
1071 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
1072 zif->rtadv.AdvIntervalTimer = 0;
1073
1074 return CMD_SUCCESS;
7cee1bb1 1075}
1076
718e3744 1077DEFUN (ipv6_nd_ra_interval,
1078 ipv6_nd_ra_interval_cmd,
6147e2c6 1079 "ipv6 nd ra-interval (1-1800)",
3e31cded 1080 "Interface IPv6 config commands\n"
718e3744 1081 "Neighbor discovery\n"
1082 "Router Advertisement interval\n"
1083 "Router Advertisement interval in seconds\n")
1084{
d62a17ae 1085 int idx_number = 3;
1086 VTY_DECLVAR_CONTEXT(interface, ifp);
1087 unsigned interval;
1088 struct zebra_if *zif = ifp->info;
d62a17ae 1089
d62a17ae 1090 interval = strtoul(argv[idx_number]->arg, NULL, 10);
1091 if ((zif->rtadv.AdvDefaultLifetime != -1
1092 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) {
1093 vty_out(vty,
1094 "This ra-interval would conflict with configured ra-lifetime!\n");
1095 return CMD_WARNING_CONFIG_FAILED;
1096 }
1097
1098 if (zif->rtadv.MaxRtrAdvInterval % 1000)
a3be9fa1 1099 zrouter.rtadv.adv_msec_if_count--;
d62a17ae 1100
1101 /* convert to milliseconds */
1102 interval = interval * 1000;
1103
3ea48364 1104 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
d62a17ae 1105 zif->rtadv.MaxRtrAdvInterval = interval;
1106 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
1107 zif->rtadv.AdvIntervalTimer = 0;
1108
1109 return CMD_SUCCESS;
718e3744 1110}
1111
1112DEFUN (no_ipv6_nd_ra_interval,
1113 no_ipv6_nd_ra_interval_cmd,
34ccea1e 1114 "no ipv6 nd ra-interval [<(1-1800)|msec (1-1800000)>]",
718e3744 1115 NO_STR
3e31cded 1116 "Interface IPv6 config commands\n"
718e3744 1117 "Neighbor discovery\n"
34ccea1e
QY
1118 "Router Advertisement interval\n"
1119 "Router Advertisement interval in seconds\n"
1120 "Specify millisecond router advertisement interval\n"
1121 "Router Advertisement interval in milliseconds\n")
718e3744 1122{
d62a17ae 1123 VTY_DECLVAR_CONTEXT(interface, ifp);
1124 struct zebra_if *zif = ifp->info;
d62a17ae 1125
1126 if (zif->rtadv.MaxRtrAdvInterval % 1000)
a3be9fa1 1127 zrouter.rtadv.adv_msec_if_count--;
d62a17ae 1128
3ea48364
DS
1129 UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
1130
1131 if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1132 zif->rtadv.MaxRtrAdvInterval = 10000;
1133 else
1134 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
1135
d62a17ae 1136 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
3ea48364 1137 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
d62a17ae 1138
1139 return CMD_SUCCESS;
718e3744 1140}
1141
1142DEFUN (ipv6_nd_ra_lifetime,
1143 ipv6_nd_ra_lifetime_cmd,
6147e2c6 1144 "ipv6 nd ra-lifetime (0-9000)",
3e31cded 1145 "Interface IPv6 config commands\n"
718e3744 1146 "Neighbor discovery\n"
1147 "Router lifetime\n"
4afa50b3 1148 "Router lifetime in seconds (0 stands for a non-default gw)\n")
718e3744 1149{
d62a17ae 1150 int idx_number = 3;
1151 VTY_DECLVAR_CONTEXT(interface, ifp);
1152 struct zebra_if *zif = ifp->info;
1153 int lifetime;
1154
1155 lifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1156
1157 /* The value to be placed in the Router Lifetime field
1158 * of Router Advertisements sent from the interface,
1159 * in seconds. MUST be either zero or between
1160 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
1161 if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) {
1162 vty_out(vty,
1163 "This ra-lifetime would conflict with configured ra-interval\n");
1164 return CMD_WARNING_CONFIG_FAILED;
1165 }
1166
1167 zif->rtadv.AdvDefaultLifetime = lifetime;
1168
1169 return CMD_SUCCESS;
718e3744 1170}
1171
1172DEFUN (no_ipv6_nd_ra_lifetime,
1173 no_ipv6_nd_ra_lifetime_cmd,
34ccea1e 1174 "no ipv6 nd ra-lifetime [(0-9000)]",
718e3744 1175 NO_STR
3e31cded 1176 "Interface IPv6 config commands\n"
718e3744 1177 "Neighbor discovery\n"
34ccea1e
QY
1178 "Router lifetime\n"
1179 "Router lifetime in seconds (0 stands for a non-default gw)\n")
718e3744 1180{
d62a17ae 1181 VTY_DECLVAR_CONTEXT(interface, ifp);
1182 struct zebra_if *zif = ifp->info;
718e3744 1183
d62a17ae 1184 zif->rtadv.AdvDefaultLifetime = -1;
718e3744 1185
d62a17ae 1186 return CMD_SUCCESS;
718e3744 1187}
1188
1189DEFUN (ipv6_nd_reachable_time,
1190 ipv6_nd_reachable_time_cmd,
6147e2c6 1191 "ipv6 nd reachable-time (1-3600000)",
3e31cded 1192 "Interface IPv6 config commands\n"
718e3744 1193 "Neighbor discovery\n"
1194 "Reachable time\n"
1195 "Reachable time in milliseconds\n")
1196{
d62a17ae 1197 int idx_number = 3;
1198 VTY_DECLVAR_CONTEXT(interface, ifp);
1199 struct zebra_if *zif = ifp->info;
1200 zif->rtadv.AdvReachableTime = strtoul(argv[idx_number]->arg, NULL, 10);
1201 return CMD_SUCCESS;
718e3744 1202}
1203
1204DEFUN (no_ipv6_nd_reachable_time,
1205 no_ipv6_nd_reachable_time_cmd,
34ccea1e 1206 "no ipv6 nd reachable-time [(1-3600000)]",
718e3744 1207 NO_STR
3e31cded 1208 "Interface IPv6 config commands\n"
718e3744 1209 "Neighbor discovery\n"
34ccea1e
QY
1210 "Reachable time\n"
1211 "Reachable time in milliseconds\n")
718e3744 1212{
d62a17ae 1213 VTY_DECLVAR_CONTEXT(interface, ifp);
1214 struct zebra_if *zif = ifp->info;
718e3744 1215
d62a17ae 1216 zif->rtadv.AdvReachableTime = 0;
718e3744 1217
d62a17ae 1218 return CMD_SUCCESS;
718e3744 1219}
1220
7cee1bb1 1221DEFUN (ipv6_nd_homeagent_preference,
1222 ipv6_nd_homeagent_preference_cmd,
6147e2c6 1223 "ipv6 nd home-agent-preference (0-65535)",
7cee1bb1 1224 "Interface IPv6 config commands\n"
1225 "Neighbor discovery\n"
1226 "Home Agent preference\n"
4afa50b3 1227 "preference value (default is 0, least preferred)\n")
7cee1bb1 1228{
d62a17ae 1229 int idx_number = 3;
1230 VTY_DECLVAR_CONTEXT(interface, ifp);
1231 struct zebra_if *zif = ifp->info;
1232 zif->rtadv.HomeAgentPreference =
1233 strtoul(argv[idx_number]->arg, NULL, 10);
1234 return CMD_SUCCESS;
7cee1bb1 1235}
1236
1237DEFUN (no_ipv6_nd_homeagent_preference,
1238 no_ipv6_nd_homeagent_preference_cmd,
34ccea1e 1239 "no ipv6 nd home-agent-preference [(0-65535)]",
7cee1bb1 1240 NO_STR
1241 "Interface IPv6 config commands\n"
1242 "Neighbor discovery\n"
34ccea1e
QY
1243 "Home Agent preference\n"
1244 "preference value (default is 0, least preferred)\n")
7cee1bb1 1245{
d62a17ae 1246 VTY_DECLVAR_CONTEXT(interface, ifp);
1247 struct zebra_if *zif = ifp->info;
7cee1bb1 1248
d62a17ae 1249 zif->rtadv.HomeAgentPreference = 0;
7cee1bb1 1250
d62a17ae 1251 return CMD_SUCCESS;
7cee1bb1 1252}
1253
1254DEFUN (ipv6_nd_homeagent_lifetime,
1255 ipv6_nd_homeagent_lifetime_cmd,
6147e2c6 1256 "ipv6 nd home-agent-lifetime (0-65520)",
7cee1bb1 1257 "Interface IPv6 config commands\n"
1258 "Neighbor discovery\n"
1259 "Home Agent lifetime\n"
4afa50b3 1260 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
7cee1bb1 1261{
d62a17ae 1262 int idx_number = 3;
1263 VTY_DECLVAR_CONTEXT(interface, ifp);
1264 struct zebra_if *zif = ifp->info;
1265 zif->rtadv.HomeAgentLifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1266 return CMD_SUCCESS;
7cee1bb1 1267}
1268
1269DEFUN (no_ipv6_nd_homeagent_lifetime,
1270 no_ipv6_nd_homeagent_lifetime_cmd,
34ccea1e 1271 "no ipv6 nd home-agent-lifetime [(0-65520)]",
7cee1bb1 1272 NO_STR
1273 "Interface IPv6 config commands\n"
1274 "Neighbor discovery\n"
34ccea1e
QY
1275 "Home Agent lifetime\n"
1276 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
7cee1bb1 1277{
d62a17ae 1278 VTY_DECLVAR_CONTEXT(interface, ifp);
1279 struct zebra_if *zif = ifp->info;
7cee1bb1 1280
d62a17ae 1281 zif->rtadv.HomeAgentLifetime = -1;
7cee1bb1 1282
d62a17ae 1283 return CMD_SUCCESS;
7cee1bb1 1284}
1285
718e3744 1286DEFUN (ipv6_nd_managed_config_flag,
1287 ipv6_nd_managed_config_flag_cmd,
1288 "ipv6 nd managed-config-flag",
3e31cded 1289 "Interface IPv6 config commands\n"
718e3744 1290 "Neighbor discovery\n"
1291 "Managed address configuration flag\n")
1292{
d62a17ae 1293 VTY_DECLVAR_CONTEXT(interface, ifp);
1294 struct zebra_if *zif = ifp->info;
718e3744 1295
d62a17ae 1296 zif->rtadv.AdvManagedFlag = 1;
718e3744 1297
d62a17ae 1298 return CMD_SUCCESS;
718e3744 1299}
1300
1301DEFUN (no_ipv6_nd_managed_config_flag,
1302 no_ipv6_nd_managed_config_flag_cmd,
1303 "no ipv6 nd managed-config-flag",
1304 NO_STR
3e31cded 1305 "Interface IPv6 config commands\n"
718e3744 1306 "Neighbor discovery\n"
1307 "Managed address configuration flag\n")
1308{
d62a17ae 1309 VTY_DECLVAR_CONTEXT(interface, ifp);
1310 struct zebra_if *zif = ifp->info;
718e3744 1311
d62a17ae 1312 zif->rtadv.AdvManagedFlag = 0;
718e3744 1313
d62a17ae 1314 return CMD_SUCCESS;
718e3744 1315}
1316
7cee1bb1 1317DEFUN (ipv6_nd_homeagent_config_flag,
1318 ipv6_nd_homeagent_config_flag_cmd,
1319 "ipv6 nd home-agent-config-flag",
1320 "Interface IPv6 config commands\n"
1321 "Neighbor discovery\n"
1322 "Home Agent configuration flag\n")
1323{
d62a17ae 1324 VTY_DECLVAR_CONTEXT(interface, ifp);
1325 struct zebra_if *zif = ifp->info;
7cee1bb1 1326
d62a17ae 1327 zif->rtadv.AdvHomeAgentFlag = 1;
7cee1bb1 1328
d62a17ae 1329 return CMD_SUCCESS;
7cee1bb1 1330}
1331
1332DEFUN (no_ipv6_nd_homeagent_config_flag,
1333 no_ipv6_nd_homeagent_config_flag_cmd,
1334 "no ipv6 nd home-agent-config-flag",
1335 NO_STR
1336 "Interface IPv6 config commands\n"
1337 "Neighbor discovery\n"
1338 "Home Agent configuration flag\n")
1339{
d62a17ae 1340 VTY_DECLVAR_CONTEXT(interface, ifp);
1341 struct zebra_if *zif = ifp->info;
7cee1bb1 1342
d62a17ae 1343 zif->rtadv.AdvHomeAgentFlag = 0;
7cee1bb1 1344
d62a17ae 1345 return CMD_SUCCESS;
7cee1bb1 1346}
1347
1348DEFUN (ipv6_nd_adv_interval_config_option,
1349 ipv6_nd_adv_interval_config_option_cmd,
1350 "ipv6 nd adv-interval-option",
1351 "Interface IPv6 config commands\n"
1352 "Neighbor discovery\n"
1353 "Advertisement Interval Option\n")
1354{
d62a17ae 1355 VTY_DECLVAR_CONTEXT(interface, ifp);
1356 struct zebra_if *zif = ifp->info;
7cee1bb1 1357
d62a17ae 1358 zif->rtadv.AdvIntervalOption = 1;
7cee1bb1 1359
d62a17ae 1360 return CMD_SUCCESS;
7cee1bb1 1361}
1362
1363DEFUN (no_ipv6_nd_adv_interval_config_option,
1364 no_ipv6_nd_adv_interval_config_option_cmd,
1365 "no ipv6 nd adv-interval-option",
1366 NO_STR
1367 "Interface IPv6 config commands\n"
1368 "Neighbor discovery\n"
1369 "Advertisement Interval Option\n")
1370{
d62a17ae 1371 VTY_DECLVAR_CONTEXT(interface, ifp);
1372 struct zebra_if *zif = ifp->info;
7cee1bb1 1373
d62a17ae 1374 zif->rtadv.AdvIntervalOption = 0;
7cee1bb1 1375
d62a17ae 1376 return CMD_SUCCESS;
7cee1bb1 1377}
1378
718e3744 1379DEFUN (ipv6_nd_other_config_flag,
1380 ipv6_nd_other_config_flag_cmd,
1381 "ipv6 nd other-config-flag",
3e31cded 1382 "Interface IPv6 config commands\n"
718e3744 1383 "Neighbor discovery\n"
1384 "Other statefull configuration flag\n")
1385{
d62a17ae 1386 VTY_DECLVAR_CONTEXT(interface, ifp);
1387 struct zebra_if *zif = ifp->info;
718e3744 1388
d62a17ae 1389 zif->rtadv.AdvOtherConfigFlag = 1;
718e3744 1390
d62a17ae 1391 return CMD_SUCCESS;
718e3744 1392}
1393
1394DEFUN (no_ipv6_nd_other_config_flag,
1395 no_ipv6_nd_other_config_flag_cmd,
1396 "no ipv6 nd other-config-flag",
1397 NO_STR
3e31cded 1398 "Interface IPv6 config commands\n"
718e3744 1399 "Neighbor discovery\n"
1400 "Other statefull configuration flag\n")
1401{
d62a17ae 1402 VTY_DECLVAR_CONTEXT(interface, ifp);
1403 struct zebra_if *zif = ifp->info;
718e3744 1404
d62a17ae 1405 zif->rtadv.AdvOtherConfigFlag = 0;
718e3744 1406
d62a17ae 1407 return CMD_SUCCESS;
718e3744 1408}
1409
3e31cded 1410DEFUN (ipv6_nd_prefix,
1411 ipv6_nd_prefix_cmd,
34ccea1e 1412 "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 1413 "Interface IPv6 config commands\n"
718e3744 1414 "Neighbor discovery\n"
1415 "Prefix information\n"
1416 "IPv6 prefix\n"
1417 "Valid lifetime in seconds\n"
3e31cded 1418 "Infinite valid lifetime\n"
718e3744 1419 "Preferred lifetime in seconds\n"
3e31cded 1420 "Infinite preferred lifetime\n"
34ccea1e 1421 "Set Router Address flag\n"
3e31cded 1422 "Do not use prefix for onlink determination\n"
7cee1bb1 1423 "Do not use prefix for autoconfiguration\n"
34ccea1e
QY
1424 "Do not use prefix for autoconfiguration\n"
1425 "Do not use prefix for onlink determination\n")
718e3744 1426{
d62a17ae 1427 /* prelude */
1428 char *prefix = argv[3]->arg;
9d303b37
DL
1429 int lifetimes = (argc > 4) && (argv[4]->type == RANGE_TKN
1430 || strmatch(argv[4]->text, "infinite"));
d62a17ae 1431 int routeropts = lifetimes ? argc > 6 : argc > 4;
1432
1433 int idx_routeropts = routeropts ? (lifetimes ? 6 : 4) : 0;
1434
1435 char *lifetime = NULL, *preflifetime = NULL;
1436 int routeraddr = 0, offlink = 0, noautoconf = 0;
1437 if (lifetimes) {
1438 lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
1439 : argv[4]->text;
1440 preflifetime = argv[5]->type == RANGE_TKN ? argv[5]->arg
1441 : argv[5]->text;
1442 }
1443 if (routeropts) {
1444 routeraddr =
1445 strmatch(argv[idx_routeropts]->text, "router-address");
1446 if (!routeraddr) {
1447 offlink = (argc > idx_routeropts + 1
1448 || strmatch(argv[idx_routeropts]->text,
1449 "off-link"));
1450 noautoconf = (argc > idx_routeropts + 1
1451 || strmatch(argv[idx_routeropts]->text,
1452 "no-autoconfig"));
1453 }
1454 }
1455
1456 /* business */
1457 VTY_DECLVAR_CONTEXT(interface, ifp);
1458 struct zebra_if *zebra_if = ifp->info;
1459 int ret;
1460 struct rtadv_prefix rp;
1461
1462 ret = str2prefix_ipv6(prefix, &rp.prefix);
1463 if (!ret) {
1464 vty_out(vty, "Malformed IPv6 prefix\n");
1465 return CMD_WARNING_CONFIG_FAILED;
1466 }
1467 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
1468 rp.AdvOnLinkFlag = !offlink;
1469 rp.AdvAutonomousFlag = !noautoconf;
1470 rp.AdvRouterAddressFlag = routeraddr;
1471 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1472 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
1473
1474 if (lifetimes) {
1475 rp.AdvValidLifetime = strmatch(lifetime, "infinite")
1476 ? UINT32_MAX
1477 : strtoll(lifetime, NULL, 10);
1478 rp.AdvPreferredLifetime =
1479 strmatch(preflifetime, "infinite")
1480 ? UINT32_MAX
1481 : strtoll(preflifetime, NULL, 10);
1482 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) {
1483 vty_out(vty, "Invalid preferred lifetime\n");
1484 return CMD_WARNING_CONFIG_FAILED;
1485 }
1486 }
1487
1488 rtadv_prefix_set(zebra_if, &rp);
1489
1490 return CMD_SUCCESS;
718e3744 1491}
1492
3e31cded 1493DEFUN (no_ipv6_nd_prefix,
1494 no_ipv6_nd_prefix_cmd,
34ccea1e
QY
1495 "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]>]",
1496 NO_STR
3e31cded 1497 "Interface IPv6 config commands\n"
718e3744 1498 "Neighbor discovery\n"
1499 "Prefix information\n"
34ccea1e
QY
1500 "IPv6 prefix\n"
1501 "Valid lifetime in seconds\n"
1502 "Infinite valid lifetime\n"
1503 "Preferred lifetime in seconds\n"
1504 "Infinite preferred lifetime\n"
1505 "Set Router Address flag\n"
1506 "Do not use prefix for onlink determination\n"
1507 "Do not use prefix for autoconfiguration\n"
1508 "Do not use prefix for autoconfiguration\n"
1509 "Do not use prefix for onlink determination\n")
718e3744 1510{
d62a17ae 1511 VTY_DECLVAR_CONTEXT(interface, ifp);
1512 struct zebra_if *zebra_if = ifp->info;
1513 int ret;
1514 struct rtadv_prefix rp;
1515 char *prefix = argv[4]->arg;
1516
1517 ret = str2prefix_ipv6(prefix, &rp.prefix);
1518 if (!ret) {
1519 vty_out(vty, "Malformed IPv6 prefix\n");
1520 return CMD_WARNING_CONFIG_FAILED;
1521 }
1522 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
1523
1524 ret = rtadv_prefix_reset(zebra_if, &rp);
1525 if (!ret) {
1526 vty_out(vty, "Non-existant IPv6 prefix\n");
1527 return CMD_WARNING_CONFIG_FAILED;
1528 }
1529
1530 return CMD_SUCCESS;
718e3744 1531}
b60668d0
CC
1532
1533DEFUN (ipv6_nd_router_preference,
1534 ipv6_nd_router_preference_cmd,
6147e2c6 1535 "ipv6 nd router-preference <high|medium|low>",
b60668d0
CC
1536 "Interface IPv6 config commands\n"
1537 "Neighbor discovery\n"
1538 "Default router preference\n"
1539 "High default router preference\n"
58f1b7cc
DS
1540 "Medium default router preference (default)\n"
1541 "Low default router preference\n")
b60668d0 1542{
d62a17ae 1543 int idx_high_medium_low = 3;
1544 VTY_DECLVAR_CONTEXT(interface, ifp);
1545 struct zebra_if *zif = ifp->info;
1546 int i = 0;
1547
1548 while (0 != rtadv_pref_strs[i]) {
1549 if (strncmp(argv[idx_high_medium_low]->arg, rtadv_pref_strs[i],
1550 1)
1551 == 0) {
1552 zif->rtadv.DefaultPreference = i;
1553 return CMD_SUCCESS;
1554 }
1555 i++;
b60668d0 1556 }
b60668d0 1557
d62a17ae 1558 return CMD_ERR_NO_MATCH;
b60668d0
CC
1559}
1560
1561DEFUN (no_ipv6_nd_router_preference,
1562 no_ipv6_nd_router_preference_cmd,
34ccea1e 1563 "no ipv6 nd router-preference [<high|medium|low>]",
b60668d0
CC
1564 NO_STR
1565 "Interface IPv6 config commands\n"
1566 "Neighbor discovery\n"
34ccea1e
QY
1567 "Default router preference\n"
1568 "High default router preference\n"
1569 "Medium default router preference (default)\n"
1570 "Low default router preference\n")
b60668d0 1571{
d62a17ae 1572 VTY_DECLVAR_CONTEXT(interface, ifp);
1573 struct zebra_if *zif = ifp->info;
b60668d0 1574
d62a17ae 1575 zif->rtadv.DefaultPreference =
1576 RTADV_PREF_MEDIUM; /* Default per RFC4191. */
b60668d0 1577
d62a17ae 1578 return CMD_SUCCESS;
b60668d0
CC
1579}
1580
6ae93c05
DO
1581DEFUN (ipv6_nd_mtu,
1582 ipv6_nd_mtu_cmd,
6147e2c6 1583 "ipv6 nd mtu (1-65535)",
6ae93c05
DO
1584 "Interface IPv6 config commands\n"
1585 "Neighbor discovery\n"
1586 "Advertised MTU\n"
1587 "MTU in bytes\n")
1588{
d62a17ae 1589 int idx_number = 3;
1590 VTY_DECLVAR_CONTEXT(interface, ifp);
1591 struct zebra_if *zif = ifp->info;
1592 zif->rtadv.AdvLinkMTU = strtoul(argv[idx_number]->arg, NULL, 10);
1593 return CMD_SUCCESS;
6ae93c05
DO
1594}
1595
1596DEFUN (no_ipv6_nd_mtu,
1597 no_ipv6_nd_mtu_cmd,
34ccea1e 1598 "no ipv6 nd mtu [(1-65535)]",
6ae93c05
DO
1599 NO_STR
1600 "Interface IPv6 config commands\n"
1601 "Neighbor discovery\n"
34ccea1e
QY
1602 "Advertised MTU\n"
1603 "MTU in bytes\n")
6ae93c05 1604{
d62a17ae 1605 VTY_DECLVAR_CONTEXT(interface, ifp);
1606 struct zebra_if *zif = ifp->info;
1607 zif->rtadv.AdvLinkMTU = 0;
1608 return CMD_SUCCESS;
6ae93c05
DO
1609}
1610
3eb4fbb0
LS
1611static struct rtadv_rdnss *rtadv_rdnss_new(void)
1612{
1613 return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss));
1614}
1615
1616static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss)
1617{
1618 XFREE(MTYPE_RTADV_RDNSS, rdnss);
1619}
1620
1621static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list,
1622 struct rtadv_rdnss *rdnss)
1623{
1624 struct listnode *node;
1625 struct rtadv_rdnss *p;
1626
1627 for (ALL_LIST_ELEMENTS_RO(list, node, p))
1628 if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr))
1629 return p;
1630 return NULL;
1631}
1632
1633static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list,
1634 struct rtadv_rdnss *rdnss)
1635{
1636 struct rtadv_rdnss *p;
1637
1638 p = rtadv_rdnss_lookup(list, rdnss);
1639 if (p)
1640 return p;
1641
1642 p = rtadv_rdnss_new();
1643 memcpy(p, rdnss, sizeof(struct rtadv_rdnss));
1644 listnode_add(list, p);
1645
1646 return p;
1647}
1648
1649static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
1650{
1651 struct rtadv_rdnss *p;
1652
1653 p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss);
1654 p->lifetime = rdnss->lifetime;
1655 p->lifetime_set = rdnss->lifetime_set;
1656}
1657
1658static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
1659{
1660 struct rtadv_rdnss *p;
1661
1662 p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss);
1663 if (p) {
1664 listnode_delete(zif->rtadv.AdvRDNSSList, p);
1665 rtadv_rdnss_free(p);
1666 return 1;
1667 }
1668
1669 return 0;
1670}
1671
1672static struct rtadv_dnssl *rtadv_dnssl_new(void)
1673{
1674 return XCALLOC(MTYPE_RTADV_DNSSL, sizeof(struct rtadv_dnssl));
1675}
1676
1677static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl)
1678{
1679 XFREE(MTYPE_RTADV_DNSSL, dnssl);
1680}
1681
1682static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list,
1683 struct rtadv_dnssl *dnssl)
1684{
1685 struct listnode *node;
1686 struct rtadv_dnssl *p;
1687
1688 for (ALL_LIST_ELEMENTS_RO(list, node, p))
1689 if (!strcasecmp(p->name, dnssl->name))
1690 return p;
1691 return NULL;
1692}
1693
1694static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list,
1695 struct rtadv_dnssl *dnssl)
1696{
1697 struct rtadv_dnssl *p;
1698
1699 p = rtadv_dnssl_lookup(list, dnssl);
1700 if (p)
1701 return p;
1702
1703 p = rtadv_dnssl_new();
1704 memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
1705 listnode_add(list, p);
1706
1707 return p;
1708}
1709
1710static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
1711{
1712 struct rtadv_dnssl *p;
1713
1714 p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl);
1715 memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
1716}
1717
1718static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
1719{
1720 struct rtadv_dnssl *p;
1721
1722 p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl);
1723 if (p) {
1724 listnode_delete(zif->rtadv.AdvDNSSLList, p);
1725 rtadv_dnssl_free(p);
1726 return 1;
1727 }
1728
1729 return 0;
1730}
1731
1732/*
1733 * Convert dotted domain name (with or without trailing root zone dot) to
1734 * sequence of length-prefixed labels, as described in [RFC1035 3.1]. Write up
1735 * to strlen(in) + 2 octets to out.
1736 *
1737 * Returns the number of octets written to out or -1 if in does not constitute
1738 * a valid domain name.
1739 */
1740static int rtadv_dnssl_encode(uint8_t *out, const char *in)
1741{
1742 const char *label_start, *label_end;
1743 size_t outp;
1744
1745 outp = 0;
1746 label_start = in;
1747
1748 while (*label_start) {
1749 size_t label_len;
1750
1751 label_end = strchr(label_start, '.');
1752 if (label_end == NULL)
1753 label_end = label_start + strlen(label_start);
1754
1755 label_len = label_end - label_start;
1756 if (label_len >= 64)
1757 return -1; /* labels must be 63 octets or less */
1758
1759 out[outp++] = (uint8_t)label_len;
1760 memcpy(out + outp, label_start, label_len);
1761 outp += label_len;
1762 label_start += label_len;
1763 if (*label_start == '.')
1764 label_start++;
1765 }
1766
1767 out[outp++] = '\0';
1768 return outp;
1769}
1770
1771DEFUN(ipv6_nd_rdnss,
1772 ipv6_nd_rdnss_cmd,
1773 "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
1774 "Interface IPv6 config commands\n"
1775 "Neighbor discovery\n"
1776 "Recursive DNS server information\n"
1777 "IPv6 address\n"
1778 "Valid lifetime in seconds\n"
1779 "Infinite valid lifetime\n")
1780{
1781 VTY_DECLVAR_CONTEXT(interface, ifp);
1782 struct zebra_if *zif = ifp->info;
844e9180 1783 struct rtadv_rdnss rdnss = {};
3eb4fbb0
LS
1784
1785 if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) {
1786 vty_out(vty, "Malformed IPv6 address\n");
1787 return CMD_WARNING_CONFIG_FAILED;
1788 }
1789 if (argc > 4) {
1790 char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
1791 : argv[4]->text;
1792 rdnss.lifetime = strmatch(lifetime, "infinite")
1793 ? UINT32_MAX
1794 : strtoll(lifetime, NULL, 10);
1795 rdnss.lifetime_set = 1;
1796 }
1797
1798 rtadv_rdnss_set(zif, &rdnss);
1799
1800 return CMD_SUCCESS;
1801}
1802
1803DEFUN(no_ipv6_nd_rdnss,
1804 no_ipv6_nd_rdnss_cmd,
1805 "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
1806 NO_STR
1807 "Interface IPv6 config commands\n"
1808 "Neighbor discovery\n"
1809 "Recursive DNS server information\n"
1810 "IPv6 address\n"
1811 "Valid lifetime in seconds\n"
1812 "Infinite valid lifetime\n")
1813{
1814 VTY_DECLVAR_CONTEXT(interface, ifp);
1815 struct zebra_if *zif = ifp->info;
844e9180 1816 struct rtadv_rdnss rdnss = {};
3eb4fbb0
LS
1817
1818 if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) {
1819 vty_out(vty, "Malformed IPv6 address\n");
1820 return CMD_WARNING_CONFIG_FAILED;
1821 }
1822 if (rtadv_rdnss_reset(zif, &rdnss) != 1) {
1823 vty_out(vty, "Non-existant RDNSS address\n");
1824 return CMD_WARNING_CONFIG_FAILED;
1825 }
1826
1827 return CMD_SUCCESS;
1828}
1829
1830DEFUN(ipv6_nd_dnssl,
1831 ipv6_nd_dnssl_cmd,
1832 "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
1833 "Interface IPv6 config commands\n"
1834 "Neighbor discovery\n"
1835 "DNS search list information\n"
1836 "Domain name suffix\n"
1837 "Valid lifetime in seconds\n"
1838 "Infinite valid lifetime\n")
1839{
1840 VTY_DECLVAR_CONTEXT(interface, ifp);
1841 struct zebra_if *zif = ifp->info;
844e9180 1842 struct rtadv_dnssl dnssl = {};
3eb4fbb0
LS
1843 size_t len;
1844 int ret;
1845
1846 len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name));
1847 if (len == 0 || len >= sizeof(dnssl.name)) {
1848 vty_out(vty, "Malformed DNS search domain\n");
1849 return CMD_WARNING_CONFIG_FAILED;
1850 }
1851 if (dnssl.name[len - 1] == '.') {
1852 /*
1853 * Allow, but don't require, a trailing dot signifying the root
1854 * zone. Canonicalize by cutting it off if present.
1855 */
1856 dnssl.name[len - 1] = '\0';
1857 len--;
1858 }
1859 if (argc > 4) {
1860 char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
1861 : argv[4]->text;
1862 dnssl.lifetime = strmatch(lifetime, "infinite")
1863 ? UINT32_MAX
1864 : strtoll(lifetime, NULL, 10);
1865 dnssl.lifetime_set = 1;
1866 }
1867
1868 ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name);
1869 if (ret < 0) {
1870 vty_out(vty, "Malformed DNS search domain\n");
1871 return CMD_WARNING_CONFIG_FAILED;
1872 }
1873 dnssl.encoded_len = ret;
1874 rtadv_dnssl_set(zif, &dnssl);
1875
1876 return CMD_SUCCESS;
1877}
1878
1879DEFUN(no_ipv6_nd_dnssl,
1880 no_ipv6_nd_dnssl_cmd,
1881 "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
1882 NO_STR
1883 "Interface IPv6 config commands\n"
1884 "Neighbor discovery\n"
1885 "DNS search list information\n"
1886 "Domain name suffix\n"
1887 "Valid lifetime in seconds\n"
1888 "Infinite valid lifetime\n")
1889{
1890 VTY_DECLVAR_CONTEXT(interface, ifp);
1891 struct zebra_if *zif = ifp->info;
844e9180 1892 struct rtadv_dnssl dnssl = {};
3eb4fbb0
LS
1893 size_t len;
1894
1895 len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name));
1896 if (len == 0 || len >= sizeof(dnssl.name)) {
1897 vty_out(vty, "Malformed DNS search domain\n");
1898 return CMD_WARNING_CONFIG_FAILED;
1899 }
1900 if (dnssl.name[len - 1] == '.') {
1901 dnssl.name[len - 1] = '\0';
1902 len--;
1903 }
1904 if (rtadv_dnssl_reset(zif, &dnssl) != 1) {
1905 vty_out(vty, "Non-existant DNS search domain\n");
1906 return CMD_WARNING_CONFIG_FAILED;
1907 }
1908
1909 return CMD_SUCCESS;
1910}
1911
1912
2eb27eec
DL
1913/* Dump interface ND information to vty. */
1914static int nd_dump_vty(struct vty *vty, struct interface *ifp)
1915{
1916 struct zebra_if *zif;
1917 struct rtadvconf *rtadv;
1918 int interval;
1919
1920 zif = (struct zebra_if *)ifp->info;
1921 rtadv = &zif->rtadv;
1922
1923 if (rtadv->AdvSendAdvertisements) {
1924 vty_out(vty,
1925 " ND advertised reachable time is %d milliseconds\n",
1926 rtadv->AdvReachableTime);
1927 vty_out(vty,
1928 " ND advertised retransmit interval is %d milliseconds\n",
1929 rtadv->AdvRetransTimer);
1930 vty_out(vty, " ND router advertisements sent: %d rcvd: %d\n",
1931 zif->ra_sent, zif->ra_rcvd);
1932 interval = rtadv->MaxRtrAdvInterval;
1933 if (interval % 1000)
1934 vty_out(vty,
1935 " ND router advertisements are sent every "
1936 "%d milliseconds\n",
1937 interval);
1938 else
1939 vty_out(vty,
1940 " ND router advertisements are sent every "
1941 "%d seconds\n",
1942 interval / 1000);
1943 if (rtadv->AdvDefaultLifetime != -1)
1944 vty_out(vty,
1945 " ND router advertisements live for %d seconds\n",
1946 rtadv->AdvDefaultLifetime);
1947 else
1948 vty_out(vty,
1949 " ND router advertisements lifetime tracks ra-interval\n");
1950 vty_out(vty,
1951 " ND router advertisement default router preference is "
1952 "%s\n",
1953 rtadv_pref_strs[rtadv->DefaultPreference]);
1954 if (rtadv->AdvManagedFlag)
1955 vty_out(vty,
1956 " Hosts use DHCP to obtain routable addresses.\n");
1957 else
1958 vty_out(vty,
1959 " Hosts use stateless autoconfig for addresses.\n");
1960 if (rtadv->AdvHomeAgentFlag) {
1961 vty_out(vty,
1962 " ND router advertisements with Home Agent flag bit set.\n");
1963 if (rtadv->HomeAgentLifetime != -1)
1964 vty_out(vty,
1965 " Home Agent lifetime is %u seconds\n",
1966 rtadv->HomeAgentLifetime);
1967 else
1968 vty_out(vty,
1969 " Home Agent lifetime tracks ra-lifetime\n");
1970 vty_out(vty, " Home Agent preference is %u\n",
1971 rtadv->HomeAgentPreference);
1972 }
1973 if (rtadv->AdvIntervalOption)
1974 vty_out(vty,
1975 " ND router advertisements with Adv. Interval option.\n");
1976 }
1977 return 0;
1978}
1979
6ae93c05 1980
718e3744 1981/* Write configuration about router advertisement. */
2eb27eec 1982static int rtadv_config_write(struct vty *vty, struct interface *ifp)
718e3744 1983{
d62a17ae 1984 struct zebra_if *zif;
1985 struct listnode *node;
1986 struct rtadv_prefix *rprefix;
3eb4fbb0
LS
1987 struct rtadv_rdnss *rdnss;
1988 struct rtadv_dnssl *dnssl;
d62a17ae 1989 char buf[PREFIX_STRLEN];
1990 int interval;
1991
1992 zif = ifp->info;
1993
1994 if (!(if_is_loopback(ifp)
1995 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))) {
3ea48364
DS
1996 if (zif->rtadv.AdvSendAdvertisements
1997 && CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
d62a17ae 1998 vty_out(vty, " no ipv6 nd suppress-ra\n");
1999 }
2000
2001 interval = zif->rtadv.MaxRtrAdvInterval;
3ea48364
DS
2002 if (CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED)) {
2003 if (interval % 1000)
2004 vty_out(vty, " ipv6 nd ra-interval msec %d\n",
2005 interval);
2006 else if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
2007 vty_out(vty, " ipv6 nd ra-interval %d\n",
2008 interval / 1000);
2009 }
d62a17ae 2010
2011 if (zif->rtadv.AdvIntervalOption)
2012 vty_out(vty, " ipv6 nd adv-interval-option\n");
2013
2014 if (zif->rtadv.AdvDefaultLifetime != -1)
2015 vty_out(vty, " ipv6 nd ra-lifetime %d\n",
2016 zif->rtadv.AdvDefaultLifetime);
2017
2018 if (zif->rtadv.HomeAgentPreference)
2019 vty_out(vty, " ipv6 nd home-agent-preference %u\n",
2020 zif->rtadv.HomeAgentPreference);
2021
2022 if (zif->rtadv.HomeAgentLifetime != -1)
2023 vty_out(vty, " ipv6 nd home-agent-lifetime %u\n",
2024 zif->rtadv.HomeAgentLifetime);
2025
2026 if (zif->rtadv.AdvHomeAgentFlag)
2027 vty_out(vty, " ipv6 nd home-agent-config-flag\n");
2028
2029 if (zif->rtadv.AdvReachableTime)
2030 vty_out(vty, " ipv6 nd reachable-time %d\n",
2031 zif->rtadv.AdvReachableTime);
2032
2033 if (zif->rtadv.AdvManagedFlag)
2034 vty_out(vty, " ipv6 nd managed-config-flag\n");
2035
2036 if (zif->rtadv.AdvOtherConfigFlag)
2037 vty_out(vty, " ipv6 nd other-config-flag\n");
2038
2039 if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
2040 vty_out(vty, " ipv6 nd router-preference %s\n",
2041 rtadv_pref_strs[zif->rtadv.DefaultPreference]);
2042
2043 if (zif->rtadv.AdvLinkMTU)
2044 vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU);
2045
2046 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvPrefixList, node, rprefix)) {
2047 vty_out(vty, " ipv6 nd prefix %s",
2048 prefix2str(&rprefix->prefix, buf, sizeof(buf)));
2049 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME)
2050 || (rprefix->AdvPreferredLifetime
2051 != RTADV_PREFERRED_LIFETIME)) {
2052 if (rprefix->AdvValidLifetime == UINT32_MAX)
2053 vty_out(vty, " infinite");
2054 else
2055 vty_out(vty, " %u", rprefix->AdvValidLifetime);
2056 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
2057 vty_out(vty, " infinite");
2058 else
2059 vty_out(vty, " %u",
2060 rprefix->AdvPreferredLifetime);
2061 }
2062 if (!rprefix->AdvOnLinkFlag)
2063 vty_out(vty, " off-link");
2064 if (!rprefix->AdvAutonomousFlag)
2065 vty_out(vty, " no-autoconfig");
2066 if (rprefix->AdvRouterAddressFlag)
2067 vty_out(vty, " router-address");
2068 vty_out(vty, "\n");
3e31cded 2069 }
3eb4fbb0
LS
2070 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) {
2071 char buf[INET6_ADDRSTRLEN];
2072
2073 vty_out(vty, " ipv6 nd rdnss %s",
2074 inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf)));
2075 if (rdnss->lifetime_set) {
2076 if (rdnss->lifetime == UINT32_MAX)
2077 vty_out(vty, " infinite");
2078 else
2079 vty_out(vty, " %u", rdnss->lifetime);
2080 }
2081 vty_out(vty, "\n");
2082 }
2083 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) {
2084 vty_out(vty, " ipv6 nd dnssl %s", dnssl->name);
2085 if (dnssl->lifetime_set) {
2086 if (dnssl->lifetime == UINT32_MAX)
2087 vty_out(vty, " infinite");
2088 else
2089 vty_out(vty, " %u", dnssl->lifetime);
2090 }
2091 vty_out(vty, "\n");
2092 }
2eb27eec 2093 return 0;
718e3744 2094}
2095
718e3744 2096
d62a17ae 2097static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
718e3744 2098{
a3be9fa1 2099 struct rtadv *rtadv = &zrouter.rtadv;
d62a17ae 2100
2101 switch (event) {
2102 case RTADV_START:
3801e764 2103 thread_add_read(zrouter.master, rtadv_read, zns, val,
d62a17ae 2104 &rtadv->ra_read);
3801e764 2105 thread_add_event(zrouter.master, rtadv_timer, zns, 0,
d62a17ae 2106 &rtadv->ra_timer);
2107 break;
2108 case RTADV_STOP:
2109 if (rtadv->ra_timer) {
2110 thread_cancel(rtadv->ra_timer);
2111 rtadv->ra_timer = NULL;
2112 }
2113 if (rtadv->ra_read) {
2114 thread_cancel(rtadv->ra_read);
2115 rtadv->ra_read = NULL;
2116 }
2117 break;
2118 case RTADV_TIMER:
3801e764 2119 thread_add_timer(zrouter.master, rtadv_timer, zns, val,
d62a17ae 2120 &rtadv->ra_timer);
2121 break;
2122 case RTADV_TIMER_MSEC:
3801e764 2123 thread_add_timer_msec(zrouter.master, rtadv_timer, zns, val,
d62a17ae 2124 &rtadv->ra_timer);
2125 break;
2126 case RTADV_READ:
3801e764 2127 thread_add_read(zrouter.master, rtadv_read, zns, val,
d62a17ae 2128 &rtadv->ra_read);
2129 break;
2130 default:
2131 break;
718e3744 2132 }
d62a17ae 2133 return;
718e3744 2134}
2135
d62a17ae 2136void rtadv_init(struct zebra_ns *zns)
718e3744 2137{
a3be9fa1 2138 zrouter.rtadv.sock = rtadv_make_socket(zns->ns_id);
cd80d74f 2139}
718e3744 2140
d62a17ae 2141void rtadv_terminate(struct zebra_ns *zns)
cd80d74f 2142{
d62a17ae 2143 rtadv_event(zns, RTADV_STOP, 0);
a3be9fa1
DS
2144 if (zrouter.rtadv.sock >= 0) {
2145 close(zrouter.rtadv.sock);
2146 zrouter.rtadv.sock = -1;
d62a17ae 2147 }
2148
a3be9fa1
DS
2149 zrouter.rtadv.adv_if_count = 0;
2150 zrouter.rtadv.adv_msec_if_count = 0;
cd80d74f 2151}
718e3744 2152
d62a17ae 2153void rtadv_cmd_init(void)
cd80d74f 2154{
2eb27eec
DL
2155 hook_register(zebra_if_extra_info, nd_dump_vty);
2156 hook_register(zebra_if_config_wr, rtadv_config_write);
2157
d62a17ae 2158 install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
2159 install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
2160 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
2161 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
2162 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
2163 install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
2164 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
2165 install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
2166 install_element(INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
2167 install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
2168 install_element(INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
2169 install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
2170 install_element(INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
2171 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
2172 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
2173 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
2174 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
2175 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
2176 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
2177 install_element(INTERFACE_NODE,
2178 &ipv6_nd_adv_interval_config_option_cmd);
2179 install_element(INTERFACE_NODE,
2180 &no_ipv6_nd_adv_interval_config_option_cmd);
2181 install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd);
2182 install_element(INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
2183 install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
2184 install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
2185 install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd);
2186 install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
3eb4fbb0
LS
2187 install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd);
2188 install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd);
2189 install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd);
2190 install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd);
718e3744 2191}
2192
d62a17ae 2193static int if_join_all_router(int sock, struct interface *ifp)
718e3744 2194{
d62a17ae 2195 int ret;
718e3744 2196
d62a17ae 2197 struct ipv6_mreq mreq;
718e3744 2198
d62a17ae 2199 memset(&mreq, 0, sizeof(struct ipv6_mreq));
2200 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
2201 mreq.ipv6mr_interface = ifp->ifindex;
718e3744 2202
d62a17ae 2203 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq,
2204 sizeof mreq);
2205 if (ret < 0)
450971aa 2206 flog_err_sys(EC_LIB_SOCKET,
9df414fe
QY
2207 "%s(%u): Failed to join group, socket %u error %s",
2208 ifp->name, ifp->ifindex, sock,
2209 safe_strerror(errno));
718e3744 2210
d62a17ae 2211 if (IS_ZEBRA_DEBUG_EVENT)
2212 zlog_debug(
2213 "%s(%u): Join All-Routers multicast group, socket %u",
2214 ifp->name, ifp->ifindex, sock);
718e3744 2215
d62a17ae 2216 return 0;
718e3744 2217}
2218
d62a17ae 2219static int if_leave_all_router(int sock, struct interface *ifp)
718e3744 2220{
d62a17ae 2221 int ret;
718e3744 2222
d62a17ae 2223 struct ipv6_mreq mreq;
718e3744 2224
d62a17ae 2225 memset(&mreq, 0, sizeof(struct ipv6_mreq));
2226 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
2227 mreq.ipv6mr_interface = ifp->ifindex;
718e3744 2228
d62a17ae 2229 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq,
2230 sizeof mreq);
2231 if (ret < 0)
9df414fe 2232 flog_err_sys(
450971aa 2233 EC_LIB_SOCKET,
9df414fe
QY
2234 "%s(%u): Failed to leave group, socket %u error %s",
2235 ifp->name, ifp->ifindex, sock, safe_strerror(errno));
718e3744 2236
d62a17ae 2237 if (IS_ZEBRA_DEBUG_EVENT)
2238 zlog_debug(
2239 "%s(%u): Leave All-Routers multicast group, socket %u",
2240 ifp->name, ifp->ifindex, sock);
718e3744 2241
d62a17ae 2242 return 0;
718e3744 2243}
2244
2245#else
d62a17ae 2246void rtadv_init(struct zebra_ns *zns)
cd80d74f 2247{
d62a17ae 2248 /* Empty.*/;
cd80d74f 2249}
d62a17ae 2250void rtadv_terminate(struct zebra_ns *zns)
cd80d74f 2251{
d62a17ae 2252 /* Empty.*/;
cd80d74f 2253}
d62a17ae 2254void rtadv_cmd_init(void)
718e3744 2255{
d62a17ae 2256 /* Empty.*/;
718e3744 2257}
56c1f7d8 2258#endif /* HAVE_RTADV */