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