]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rtadv.c
build, vtysh: extract vtysh commands from .xref
[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"
26#include "sockopt.h"
27#include "thread.h"
28#include "if.h"
4a04e5f7 29#include "stream.h"
718e3744 30#include "log.h"
31#include "prefix.h"
32#include "linklist.h"
33#include "command.h"
edd7c245 34#include "privs.h"
cd80d74f 35#include "vrf.h"
fe533c56 36#include "ns.h"
43e52561 37#include "lib_errors.h"
718e3744 38
39#include "zebra/interface.h"
40#include "zebra/rtadv.h"
41#include "zebra/debug.h"
537d8ea9 42#include "zebra/rib.h"
bf094f69 43#include "zebra/zapi_msg.h"
7c551956 44#include "zebra/zebra_vrf.h"
364fed6b 45#include "zebra/zebra_errors.h"
a3be9fa1 46#include "zebra/zebra_router.h"
718e3744 47
edd7c245 48extern struct zebra_privs_t zserv_privs;
49
954e1a2b
DS
50static uint32_t interfaces_configured_for_ra_from_bgp;
51
d62a17ae 52#if defined(HAVE_RTADV)
718e3744 53
d3f604f0 54#include "zebra/rtadv_clippy.c"
d3f604f0 55
bf8d3d6a 56DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix");
7c2ddfb9 57DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface");
c1344b54 58
fa2b17e3 59#ifdef OPEN_BSD
60#include <netinet/icmp6.h>
61#endif
62
718e3744 63/* If RFC2133 definition is used. */
64#ifndef IPV6_JOIN_GROUP
c258527b 65#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
718e3744 66#endif
67#ifndef IPV6_LEAVE_GROUP
c258527b 68#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
718e3744 69#endif
70
71#define ALLNODE "ff02::1"
72#define ALLROUTER "ff02::2"
73
7ca9c407
DL
74/* adv list node */
75struct adv_if {
76 char name[INTERFACE_NAMSIZ];
77 struct adv_if_list_item list_item;
78};
79
80static int adv_if_cmp(const struct adv_if *a, const struct adv_if *b)
81{
82 return if_cmp_name_func(a->name, b->name);
83}
84
85DECLARE_SORTLIST_UNIQ(adv_if_list, struct adv_if, list_item, adv_if_cmp);
86
87static int rtadv_prefix_cmp(const struct rtadv_prefix *a,
88 const struct rtadv_prefix *b)
89{
90 return prefix_cmp(&a->prefix, &b->prefix);
91}
92
93DECLARE_RBTREE_UNIQ(rtadv_prefixes, struct rtadv_prefix, item,
94 rtadv_prefix_cmp);
95
bf8d3d6a
DL
96DEFINE_MTYPE_STATIC(ZEBRA, RTADV_RDNSS, "Router Advertisement RDNSS");
97DEFINE_MTYPE_STATIC(ZEBRA, RTADV_DNSSL, "Router Advertisement DNSSL");
110765e3 98
2eb27eec
DL
99/* Order is intentional. Matches RFC4191. This array is also used for
100 command matching, so only modify with care. */
2b64873d
DL
101static const char *const rtadv_pref_strs[] = {
102 "medium", "high", "INVALID", "low", 0
103};
2eb27eec 104
d62a17ae 105enum rtadv_event {
106 RTADV_START,
107 RTADV_STOP,
108 RTADV_TIMER,
109 RTADV_TIMER_MSEC,
110 RTADV_READ
111};
718e3744 112
df9c8c57 113static void rtadv_event(struct zebra_vrf *, enum rtadv_event, int);
718e3744 114
d62a17ae 115static int if_join_all_router(int, struct interface *);
116static int if_leave_all_router(int, struct interface *);
6b0655a2 117
7c2ddfb9 118static struct zebra_vrf *rtadv_interface_get_zvrf(const struct interface *ifp)
9245fe61 119{
7c2ddfb9
SW
120 /* We use the default vrf for rtadv handling except in netns */
121 if (!vrf_is_backend_netns())
122 return vrf_info_lookup(VRF_DEFAULT);
123
096f7609 124 return ifp->vrf->info;
9245fe61
PG
125}
126
df9c8c57 127static int rtadv_increment_received(struct zebra_vrf *zvrf, ifindex_t *ifindex)
911ad1e2 128{
d62a17ae 129 int ret = -1;
130 struct interface *iface;
131 struct zebra_if *zif;
132
df9c8c57 133 iface = if_lookup_by_index(*ifindex, zvrf->vrf->vrf_id);
d62a17ae 134 if (iface && iface->info) {
135 zif = iface->info;
136 zif->ra_rcvd++;
137 ret = 0;
138 }
139 return ret;
795b5abf
QY
140}
141
df9c8c57 142static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf,
d62a17ae 143 int buflen, struct sockaddr_in6 *from,
144 ifindex_t *ifindex, int *hoplimit)
718e3744 145{
d62a17ae 146 int ret;
147 struct msghdr msg;
148 struct iovec iov;
149 struct cmsghdr *cmsgptr;
150 struct in6_addr dst;
151
152 char adata[1024];
153
154 /* Fill in message and iovec. */
0af35d90 155 memset(&msg, 0, sizeof(msg));
d62a17ae 156 msg.msg_name = (void *)from;
157 msg.msg_namelen = sizeof(struct sockaddr_in6);
158 msg.msg_iov = &iov;
159 msg.msg_iovlen = 1;
160 msg.msg_control = (void *)adata;
0d6f7fd6 161 msg.msg_controllen = sizeof(adata);
d62a17ae 162 iov.iov_base = buf;
163 iov.iov_len = buflen;
164
165 /* If recvmsg fail return minus value. */
166 ret = recvmsg(sock, &msg, 0);
167 if (ret < 0)
168 return ret;
169
adf0e7c6 170 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
d62a17ae 171 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
172 /* I want interface index which this packet comes from. */
173 if (cmsgptr->cmsg_level == IPPROTO_IPV6
174 && cmsgptr->cmsg_type == IPV6_PKTINFO) {
175 struct in6_pktinfo *ptr;
176
177 ptr = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
178 *ifindex = ptr->ipi6_ifindex;
179 memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
180 }
181
182 /* Incoming packet's hop limit. */
183 if (cmsgptr->cmsg_level == IPPROTO_IPV6
184 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) {
185 int *hoptr = (int *)CMSG_DATA(cmsgptr);
186 *hoplimit = *hoptr;
187 }
b0b709ab 188 }
795b5abf 189
df9c8c57 190 rtadv_increment_received(zvrf, ifindex);
d62a17ae 191 return ret;
718e3744 192}
193
194#define RTADV_MSG_SIZE 4096
195
196/* Send router advertisement packet. */
d7fc0e67 197static void rtadv_send_packet(int sock, struct interface *ifp,
57dd8642 198 enum ipv6_nd_suppress_ra_status stop)
718e3744 199{
d62a17ae 200 struct msghdr msg;
201 struct iovec iov;
202 struct cmsghdr *cmsgptr;
203 struct in6_pktinfo *pkt;
204 struct sockaddr_in6 addr;
205 static void *adata = NULL;
206 unsigned char buf[RTADV_MSG_SIZE];
207 struct nd_router_advert *rtadv;
208 int ret;
209 int len = 0;
210 struct zebra_if *zif;
211 struct rtadv_prefix *rprefix;
d7c0a89a
QY
212 uint8_t all_nodes_addr[] = {0xff, 0x02, 0, 0, 0, 0, 0, 0,
213 0, 0, 0, 0, 0, 0, 0, 1};
d62a17ae 214 struct listnode *node;
d7c0a89a 215 uint16_t pkt_RouterLifetime;
d62a17ae 216
217 /*
218 * Allocate control message bufffer. This is dynamic because
219 * CMSG_SPACE is not guaranteed not to call a function. Note that
220 * the size will be different on different architectures due to
221 * differing alignment rules.
222 */
223 if (adata == NULL) {
224 /* XXX Free on shutdown. */
b8aa3767 225 adata = calloc(1, CMSG_SPACE(sizeof(struct in6_pktinfo)));
d62a17ae 226
b8aa3767 227 if (adata == NULL) {
a843c5ba 228 zlog_debug("%s: can't malloc control data", __func__);
b8aa3767
DS
229 exit(-1);
230 }
d62a17ae 231 }
232
233 /* Logging of packet. */
096f7609 234 if (IS_ZEBRA_DEBUG_PACKET)
60077146 235 zlog_debug("%s(%s:%u): Tx RA, socket %u", ifp->name,
096f7609 236 ifp->vrf->name, ifp->ifindex, sock);
d62a17ae 237
238 /* Fill in sockaddr_in6. */
239 memset(&addr, 0, sizeof(struct sockaddr_in6));
240 addr.sin6_family = AF_INET6;
718e3744 241#ifdef SIN6_LEN
d62a17ae 242 addr.sin6_len = sizeof(struct sockaddr_in6);
718e3744 243#endif /* SIN6_LEN */
d62a17ae 244 addr.sin6_port = htons(IPPROTO_ICMPV6);
245 IPV6_ADDR_COPY(&addr.sin6_addr, all_nodes_addr);
246
247 /* Fetch interface information. */
248 zif = ifp->info;
249
250 /* Make router advertisement message. */
251 rtadv = (struct nd_router_advert *)buf;
252
253 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
254 rtadv->nd_ra_code = 0;
255 rtadv->nd_ra_cksum = 0;
256
fae01935 257 rtadv->nd_ra_curhoplimit = zif->rtadv.AdvCurHopLimit;
d62a17ae 258
259 /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
260 rtadv->nd_ra_flags_reserved = zif->rtadv.AdvDefaultLifetime == 0
261 ? 0
262 : zif->rtadv.DefaultPreference;
263 rtadv->nd_ra_flags_reserved <<= 3;
264
265 if (zif->rtadv.AdvManagedFlag)
266 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
267 if (zif->rtadv.AdvOtherConfigFlag)
268 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
269 if (zif->rtadv.AdvHomeAgentFlag)
270 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
271 /* Note that according to Neighbor Discovery (RFC 4861 [18]),
272 * AdvDefaultLifetime is by default based on the value of
273 * MaxRtrAdvInterval. AdvDefaultLifetime is used in the Router Lifetime
274 * field of Router Advertisements. Given that this field is expressed
275 * in seconds, a small MaxRtrAdvInterval value can result in a zero
276 * value for this field. To prevent this, routers SHOULD keep
277 * AdvDefaultLifetime in at least one second, even if the use of
278 * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */
279 pkt_RouterLifetime =
280 zif->rtadv.AdvDefaultLifetime != -1
281 ? zif->rtadv.AdvDefaultLifetime
282 : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
d7fc0e67
DS
283
284 /* send RA lifetime of 0 before stopping. rfc4861/6.2.5 */
285 rtadv->nd_ra_router_lifetime =
286 (stop == RA_SUPPRESS) ? htons(0) : htons(pkt_RouterLifetime);
d62a17ae 287 rtadv->nd_ra_reachable = htonl(zif->rtadv.AdvReachableTime);
b19ac878 288 rtadv->nd_ra_retransmit = htonl(zif->rtadv.AdvRetransTimer);
d62a17ae 289
290 len = sizeof(struct nd_router_advert);
291
292 /* If both the Home Agent Preference and Home Agent Lifetime are set to
293 * their default values specified above, this option SHOULD NOT be
294 * included in the Router Advertisement messages sent by this home
295 * agent. -- RFC6275, 7.4 */
296 if (zif->rtadv.AdvHomeAgentFlag
297 && (zif->rtadv.HomeAgentPreference
298 || zif->rtadv.HomeAgentLifetime != -1)) {
299 struct nd_opt_homeagent_info *ndopt_hai =
300 (struct nd_opt_homeagent_info *)(buf + len);
301 ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
302 ndopt_hai->nd_opt_hai_len = 1;
303 ndopt_hai->nd_opt_hai_reserved = 0;
304 ndopt_hai->nd_opt_hai_preference =
305 htons(zif->rtadv.HomeAgentPreference);
306 /* 16-bit unsigned integer. The lifetime associated with the
307 * home
308 * agent in units of seconds. The default value is the same as
309 * the
310 * Router Lifetime, as specified in the main body of the Router
311 * Advertisement. The maximum value corresponds to 18.2 hours.
312 * A
313 * value of 0 MUST NOT be used. -- RFC6275, 7.5 */
314 ndopt_hai->nd_opt_hai_lifetime =
315 htons(zif->rtadv.HomeAgentLifetime != -1
316 ? zif->rtadv.HomeAgentLifetime
317 : MAX(1, pkt_RouterLifetime) /* 0 is OK
318 for RL,
319 but not
320 for HAL*/
9d303b37 321 );
d62a17ae 322 len += sizeof(struct nd_opt_homeagent_info);
323 }
718e3744 324
d62a17ae 325 if (zif->rtadv.AdvIntervalOption) {
326 struct nd_opt_adv_interval *ndopt_adv =
327 (struct nd_opt_adv_interval *)(buf + len);
328 ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL;
329 ndopt_adv->nd_opt_ai_len = 1;
330 ndopt_adv->nd_opt_ai_reserved = 0;
331 ndopt_adv->nd_opt_ai_interval =
332 htonl(zif->rtadv.MaxRtrAdvInterval);
333 len += sizeof(struct nd_opt_adv_interval);
334 }
335
336 /* Fill in prefix. */
7ca9c407 337 frr_each (rtadv_prefixes, zif->rtadv.prefixes, rprefix) {
d62a17ae 338 struct nd_opt_prefix_info *pinfo;
718e3744 339
d62a17ae 340 pinfo = (struct nd_opt_prefix_info *)(buf + len);
718e3744 341
d62a17ae 342 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
343 pinfo->nd_opt_pi_len = 4;
344 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
345
346 pinfo->nd_opt_pi_flags_reserved = 0;
347 if (rprefix->AdvOnLinkFlag)
348 pinfo->nd_opt_pi_flags_reserved |=
349 ND_OPT_PI_FLAG_ONLINK;
350 if (rprefix->AdvAutonomousFlag)
351 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
352 if (rprefix->AdvRouterAddressFlag)
353 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
354
355 pinfo->nd_opt_pi_valid_time = htonl(rprefix->AdvValidLifetime);
356 pinfo->nd_opt_pi_preferred_time =
357 htonl(rprefix->AdvPreferredLifetime);
358 pinfo->nd_opt_pi_reserved2 = 0;
359
360 IPV6_ADDR_COPY(&pinfo->nd_opt_pi_prefix,
361 &rprefix->prefix.prefix);
362
d62a17ae 363 len += sizeof(struct nd_opt_prefix_info);
364 }
365
366 /* Hardware address. */
367 if (ifp->hw_addr_len != 0) {
368 buf[len++] = ND_OPT_SOURCE_LINKADDR;
369
370 /* Option length should be rounded up to next octet if
371 the link address does not end on an octet boundary. */
372 buf[len++] = (ifp->hw_addr_len + 9) >> 3;
373
374 memcpy(buf + len, ifp->hw_addr, ifp->hw_addr_len);
375 len += ifp->hw_addr_len;
376
377 /* Pad option to end on an octet boundary. */
378 memset(buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7);
379 len += -(ifp->hw_addr_len + 2) & 0x7;
380 }
381
382 /* MTU */
383 if (zif->rtadv.AdvLinkMTU) {
384 struct nd_opt_mtu *opt = (struct nd_opt_mtu *)(buf + len);
385 opt->nd_opt_mtu_type = ND_OPT_MTU;
386 opt->nd_opt_mtu_len = 1;
387 opt->nd_opt_mtu_reserved = 0;
388 opt->nd_opt_mtu_mtu = htonl(zif->rtadv.AdvLinkMTU);
389 len += sizeof(struct nd_opt_mtu);
390 }
391
7eab94f9
LS
392 /*
393 * There is no limit on the number of configurable recursive DNS
394 * servers or search list entries. We don't want the RA message
395 * to exceed the link's MTU (risking fragmentation) or even
396 * blow the stack buffer allocated for it.
397 */
398 size_t max_len = MIN(ifp->mtu6 - 40, sizeof(buf));
399
3eb4fbb0
LS
400 /* Recursive DNS servers */
401 struct rtadv_rdnss *rdnss;
402
403 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) {
7eab94f9
LS
404 size_t opt_len =
405 sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr);
406
407 if (len + opt_len > max_len) {
408 zlog_warn(
60077146 409 "%s(%s:%u): Tx RA: RDNSS option would exceed MTU, omitting it",
096f7609 410 ifp->name, ifp->vrf->name, ifp->ifindex);
7eab94f9
LS
411 goto no_more_opts;
412 }
3eb4fbb0
LS
413 struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len);
414
415 opt->nd_opt_rdnss_type = ND_OPT_RDNSS;
7eab94f9 416 opt->nd_opt_rdnss_len = opt_len / 8;
3eb4fbb0
LS
417 opt->nd_opt_rdnss_reserved = 0;
418 opt->nd_opt_rdnss_lifetime = htonl(
419 rdnss->lifetime_set
420 ? rdnss->lifetime
421 : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval));
422
423 len += sizeof(struct nd_opt_rdnss);
7eab94f9 424
3eb4fbb0
LS
425 IPV6_ADDR_COPY(buf + len, &rdnss->addr);
426 len += sizeof(struct in6_addr);
427 }
428
429 /* DNS search list */
430 struct rtadv_dnssl *dnssl;
431
432 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) {
7eab94f9
LS
433 size_t opt_len = sizeof(struct nd_opt_dnssl)
434 + ((dnssl->encoded_len + 7) & ~7);
435
436 if (len + opt_len > max_len) {
437 zlog_warn(
438 "%s(%u): Tx RA: DNSSL option would exceed MTU, omitting it",
439 ifp->name, ifp->ifindex);
440 goto no_more_opts;
441 }
3eb4fbb0
LS
442 struct nd_opt_dnssl *opt = (struct nd_opt_dnssl *)(buf + len);
443
444 opt->nd_opt_dnssl_type = ND_OPT_DNSSL;
7eab94f9 445 opt->nd_opt_dnssl_len = opt_len / 8;
3eb4fbb0
LS
446 opt->nd_opt_dnssl_reserved = 0;
447 opt->nd_opt_dnssl_lifetime = htonl(
448 dnssl->lifetime_set
449 ? dnssl->lifetime
450 : MAX(1, 0.003 * zif->rtadv.MaxRtrAdvInterval));
451
452 len += sizeof(struct nd_opt_dnssl);
453
3eb4fbb0
LS
454 memcpy(buf + len, dnssl->encoded_name, dnssl->encoded_len);
455 len += dnssl->encoded_len;
456
457 /* Zero-pad to 8-octet boundary */
458 while (len % 8)
459 buf[len++] = '\0';
3eb4fbb0
LS
460 }
461
7eab94f9
LS
462no_more_opts:
463
d62a17ae 464 msg.msg_name = (void *)&addr;
465 msg.msg_namelen = sizeof(struct sockaddr_in6);
466 msg.msg_iov = &iov;
467 msg.msg_iovlen = 1;
468 msg.msg_control = (void *)adata;
469 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
470 msg.msg_flags = 0;
471 iov.iov_base = buf;
472 iov.iov_len = len;
473
adf0e7c6 474 cmsgptr = CMSG_FIRSTHDR(&msg);
d62a17ae 475 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
476 cmsgptr->cmsg_level = IPPROTO_IPV6;
477 cmsgptr->cmsg_type = IPV6_PKTINFO;
478
479 pkt = (struct in6_pktinfo *)CMSG_DATA(cmsgptr);
480 memset(&pkt->ipi6_addr, 0, sizeof(struct in6_addr));
481 pkt->ipi6_ifindex = ifp->ifindex;
482
483 ret = sendmsg(sock, &msg, 0);
484 if (ret < 0) {
450971aa 485 flog_err_sys(EC_LIB_SOCKET,
09c866e3
QY
486 "%s(%u): Tx RA failed, socket %u error %d (%s)",
487 ifp->name, ifp->ifindex, sock, errno,
488 safe_strerror(errno));
d62a17ae 489 } else
490 zif->ra_sent++;
718e3744 491}
492
cc9f21da 493static void rtadv_timer(struct thread *thread)
718e3744 494{
df9c8c57 495 struct zebra_vrf *zvrf = THREAD_ARG(thread);
d62a17ae 496 struct vrf *vrf;
d62a17ae 497 struct interface *ifp;
498 struct zebra_if *zif;
499 int period;
500
df9c8c57 501 zvrf->rtadv.ra_timer = NULL;
7c2ddfb9 502 if (adv_if_list_count(&zvrf->rtadv.adv_msec_if) == 0) {
d62a17ae 503 period = 1000; /* 1 s */
df9c8c57 504 rtadv_event(zvrf, RTADV_TIMER, 1 /* 1 s */);
d62a17ae 505 } else {
506 period = 10; /* 10 ms */
df9c8c57 507 rtadv_event(zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */);
d62a17ae 508 }
509
a2addae8 510 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
451fda4f 511 FOR_ALL_INTERFACES (vrf, ifp) {
436a6a3e
TA
512 if (if_is_loopback(ifp) || !if_is_operative(ifp) ||
513 IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) ||
514 !connected_get_linklocal(ifp) ||
515 (vrf_is_backend_netns() &&
516 ifp->vrf->vrf_id != zvrf->vrf->vrf_id))
a2addae8
RW
517 continue;
518
519 zif = ifp->info;
520
521 if (zif->rtadv.AdvSendAdvertisements) {
adee8f21
DS
522 if (zif->rtadv.inFastRexmit
523 && zif->rtadv.UseFastRexmit) {
a2addae8
RW
524 /* We assume we fast rexmit every sec so
525 * no
526 * additional vars */
527 if (--zif->rtadv.NumFastReXmitsRemain
528 <= 0)
529 zif->rtadv.inFastRexmit = 0;
530
096f7609 531 if (IS_ZEBRA_DEBUG_SEND)
a2addae8 532 zlog_debug(
60077146
DS
533 "Fast RA Rexmit on interface %s(%s:%u)",
534 ifp->name,
096f7609 535 ifp->vrf->name,
60077146 536 ifp->ifindex);
a2addae8 537
7c2ddfb9
SW
538 rtadv_send_packet(zvrf->rtadv.sock, ifp,
539 RA_ENABLE);
a2addae8
RW
540 } else {
541 zif->rtadv.AdvIntervalTimer -= period;
542 if (zif->rtadv.AdvIntervalTimer <= 0) {
543 /* FIXME: using
544 MaxRtrAdvInterval each
545 time isn't what section
546 6.2.4 of RFC4861 tells to do.
547 */
548 zif->rtadv.AdvIntervalTimer =
549 zif->rtadv
550 .MaxRtrAdvInterval;
551 rtadv_send_packet(
7c2ddfb9
SW
552 zvrf->rtadv.sock, ifp,
553 RA_ENABLE);
a2addae8 554 }
d62a17ae 555 }
556 }
557 }
718e3744 558}
559
d62a17ae 560static void rtadv_process_solicit(struct interface *ifp)
718e3744 561{
7c2ddfb9 562 struct zebra_vrf *zvrf;
adee8f21 563 struct zebra_if *zif;
718e3744 564
7c2ddfb9 565 zvrf = rtadv_interface_get_zvrf(ifp);
df9c8c57 566 assert(zvrf);
adee8f21
DS
567 zif = ifp->info;
568
569 /*
570 * If FastRetransmit is enabled, send the RA immediately.
571 * If not enabled but it has been more than MIN_DELAY_BETWEEN_RAS
572 * (3 seconds) since the last RA was sent, send it now and reset
573 * the timer to start at the max (configured) again.
574 * If not enabled and it is less than 3 seconds since the last
575 * RA packet was sent, set the timer for 3 seconds so the next
576 * one will be sent with a minimum of 3 seconds between RAs.
577 * RFC4861 sec 6.2.6
578 */
579 if ((zif->rtadv.UseFastRexmit)
580 || (zif->rtadv.AdvIntervalTimer <=
581 (zif->rtadv.MaxRtrAdvInterval - MIN_DELAY_BETWEEN_RAS))) {
7c2ddfb9 582 rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_ENABLE);
adee8f21
DS
583 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
584 } else
585 zif->rtadv.AdvIntervalTimer = MIN_DELAY_BETWEEN_RAS;
718e3744 586}
587
71974bf5
DS
588/*
589 * This function processes optional attributes off of
590 * end of a RA packet received. At this point in
591 * time we only care about this in one situation
592 * which is when a interface does not have a LL
593 * v6 address. We still need to be able to install
594 * the mac address for v4 to v6 resolution
595 */
596static void rtadv_process_optional(uint8_t *optional, unsigned int len,
597 struct interface *ifp,
598 struct sockaddr_in6 *addr)
599{
600 char *mac;
601
602 while (len > 0) {
603 struct nd_opt_hdr *opt_hdr = (struct nd_opt_hdr *)optional;
604
605 switch(opt_hdr->nd_opt_type) {
606 case ND_OPT_SOURCE_LINKADDR:
607 mac = (char *)(optional+2);
608 if_nbr_mac_to_ipv4ll_neigh_update(ifp, mac,
609 &addr->sin6_addr, 1);
610 break;
611 default:
612 break;
613 }
614
615 len -= 8 * opt_hdr->nd_opt_len;
616 optional += 8 * opt_hdr->nd_opt_len;
617 }
618}
619
d7c0a89a 620static void rtadv_process_advert(uint8_t *msg, unsigned int len,
d62a17ae 621 struct interface *ifp,
622 struct sockaddr_in6 *addr)
718e3744 623{
d62a17ae 624 struct nd_router_advert *radvert;
625 char addr_str[INET6_ADDRSTRLEN];
626 struct zebra_if *zif;
627 struct prefix p;
718e3744 628
d62a17ae 629 zif = ifp->info;
a80beece 630
d62a17ae 631 inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
632
633 if (len < sizeof(struct nd_router_advert)) {
096f7609 634 if (IS_ZEBRA_DEBUG_PACKET)
60077146
DS
635 zlog_debug(
636 "%s(%s:%u): Rx RA with invalid length %d from %s",
096f7609 637 ifp->name, ifp->vrf->name, ifp->ifindex, len,
60077146 638 addr_str);
d62a17ae 639 return;
640 }
71974bf5 641
d62a17ae 642 if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
71974bf5
DS
643 rtadv_process_optional(msg + sizeof(struct nd_router_advert),
644 len - sizeof(struct nd_router_advert),
645 ifp, addr);
096f7609 646 if (IS_ZEBRA_DEBUG_PACKET)
60077146
DS
647 zlog_debug(
648 "%s(%s:%u): Rx RA with non-linklocal source address from %s",
096f7609 649 ifp->name, ifp->vrf->name, ifp->ifindex,
60077146 650 addr_str);
d62a17ae 651 return;
652 }
653
654 radvert = (struct nd_router_advert *)msg;
655
637f95bf
DS
656#define SIXHOUR2USEC (int64_t)6 * 60 * 60 * 1000000
657
658 if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit) &&
659 (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit) &&
660 (monotime_since(&zif->rtadv.lastadvcurhoplimit, NULL) >
661 SIXHOUR2USEC ||
662 zif->rtadv.lastadvcurhoplimit.tv_sec == 0)) {
9df414fe 663 flog_warn(
e914ccbe 664 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
665 "%s(%u): Rx RA - our AdvCurHopLimit (%u) doesn't agree with %s (%u)",
666 ifp->name, ifp->ifindex, zif->rtadv.AdvCurHopLimit,
667 addr_str, radvert->nd_ra_curhoplimit);
637f95bf 668 monotime(&zif->rtadv.lastadvcurhoplimit);
d62a17ae 669 }
670
637f95bf
DS
671 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) &&
672 !zif->rtadv.AdvManagedFlag &&
673 (monotime_since(&zif->rtadv.lastadvmanagedflag, NULL) >
674 SIXHOUR2USEC ||
675 zif->rtadv.lastadvmanagedflag.tv_sec == 0)) {
9df414fe 676 flog_warn(
e914ccbe 677 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
678 "%s(%u): Rx RA - our AdvManagedFlag (%u) doesn't agree with %s (%u)",
679 ifp->name, ifp->ifindex, zif->rtadv.AdvManagedFlag,
680 addr_str,
681 !!CHECK_FLAG(radvert->nd_ra_flags_reserved,
682 ND_RA_FLAG_MANAGED));
637f95bf 683 monotime(&zif->rtadv.lastadvmanagedflag);
d62a17ae 684 }
685
637f95bf
DS
686 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) &&
687 !zif->rtadv.AdvOtherConfigFlag &&
688 (monotime_since(&zif->rtadv.lastadvotherconfigflag, NULL) >
689 SIXHOUR2USEC ||
690 zif->rtadv.lastadvotherconfigflag.tv_sec == 0)) {
9df414fe 691 flog_warn(
e914ccbe 692 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
693 "%s(%u): Rx RA - our AdvOtherConfigFlag (%u) doesn't agree with %s (%u)",
694 ifp->name, ifp->ifindex, zif->rtadv.AdvOtherConfigFlag,
695 addr_str,
696 !!CHECK_FLAG(radvert->nd_ra_flags_reserved,
697 ND_RA_FLAG_OTHER));
637f95bf 698 monotime(&zif->rtadv.lastadvotherconfigflag);
d62a17ae 699 }
700
637f95bf
DS
701 if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime) &&
702 (ntohl(radvert->nd_ra_reachable) != zif->rtadv.AdvReachableTime) &&
703 (monotime_since(&zif->rtadv.lastadvreachabletime, NULL) >
704 SIXHOUR2USEC ||
705 zif->rtadv.lastadvreachabletime.tv_sec == 0)) {
9df414fe 706 flog_warn(
e914ccbe 707 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
708 "%s(%u): Rx RA - our AdvReachableTime (%u) doesn't agree with %s (%u)",
709 ifp->name, ifp->ifindex, zif->rtadv.AdvReachableTime,
710 addr_str, ntohl(radvert->nd_ra_reachable));
637f95bf 711 monotime(&zif->rtadv.lastadvreachabletime);
d62a17ae 712 }
713
820a9cad
TA
714 if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer) &&
715 (ntohl(radvert->nd_ra_retransmit) !=
637f95bf
DS
716 (unsigned int)zif->rtadv.AdvRetransTimer) &&
717 (monotime_since(&zif->rtadv.lastadvretranstimer, NULL) >
718 SIXHOUR2USEC ||
719 zif->rtadv.lastadvretranstimer.tv_sec == 0)) {
9df414fe 720 flog_warn(
e914ccbe 721 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
722 "%s(%u): Rx RA - our AdvRetransTimer (%u) doesn't agree with %s (%u)",
723 ifp->name, ifp->ifindex, zif->rtadv.AdvRetransTimer,
724 addr_str, ntohl(radvert->nd_ra_retransmit));
637f95bf 725 monotime(&zif->rtadv.lastadvretranstimer);
d62a17ae 726 }
727
728 /* Create entry for neighbor if not known. */
729 p.family = AF_INET6;
a85297a7 730 IPV6_ADDR_COPY(&p.u.prefix6, &addr->sin6_addr);
f4d81e55 731 p.prefixlen = IPV6_MAX_BITLEN;
d62a17ae 732
733 if (!nbr_connected_check(ifp, &p))
734 nbr_connected_add_ipv6(ifp, &addr->sin6_addr);
718e3744 735}
736
d62a17ae 737
d7c0a89a 738static void rtadv_process_packet(uint8_t *buf, unsigned int len,
d62a17ae 739 ifindex_t ifindex, int hoplimit,
740 struct sockaddr_in6 *from,
df9c8c57 741 struct zebra_vrf *zvrf)
718e3744 742{
d62a17ae 743 struct icmp6_hdr *icmph;
744 struct interface *ifp;
745 struct zebra_if *zif;
746 char addr_str[INET6_ADDRSTRLEN];
747
748 inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN);
749
750 /* Interface search. */
df9c8c57 751 ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
d62a17ae 752 if (ifp == NULL) {
e914ccbe 753 flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
9df414fe 754 "RA/RS received on unknown IF %u from %s", ifindex,
d62a17ae 755 addr_str);
756 return;
757 }
758
096f7609 759 if (IS_ZEBRA_DEBUG_PACKET)
60077146 760 zlog_debug("%s(%s:%u): Rx RA/RS len %d from %s", ifp->name,
096f7609 761 ifp->vrf->name, ifp->ifindex, len, addr_str);
d62a17ae 762
608c8870 763 if (if_is_loopback(ifp))
d62a17ae 764 return;
718e3744 765
d62a17ae 766 /* Check interface configuration. */
767 zif = ifp->info;
768 if (!zif->rtadv.AdvSendAdvertisements)
769 return;
718e3744 770
d62a17ae 771 /* ICMP message length check. */
772 if (len < sizeof(struct icmp6_hdr)) {
60077146
DS
773 zlog_debug(
774 "%s(%s:%u): Rx RA with Invalid ICMPV6 packet length %d",
096f7609 775 ifp->name, ifp->vrf->name, ifp->ifindex, len);
d62a17ae 776 return;
777 }
778
779 icmph = (struct icmp6_hdr *)buf;
718e3744 780
d62a17ae 781 /* ICMP message type check. */
782 if (icmph->icmp6_type != ND_ROUTER_SOLICIT
783 && icmph->icmp6_type != ND_ROUTER_ADVERT) {
60077146 784 zlog_debug("%s(%s:%u): Rx RA - Unwanted ICMPV6 message type %d",
096f7609 785 ifp->name, ifp->vrf->name, ifp->ifindex,
60077146 786 icmph->icmp6_type);
d62a17ae 787 return;
788 }
718e3744 789
d62a17ae 790 /* Hoplimit check. */
791 if (hoplimit >= 0 && hoplimit != 255) {
60077146 792 zlog_debug("%s(%s:%u): Rx RA - Invalid hoplimit %d", ifp->name,
096f7609 793 ifp->vrf->name, ifp->ifindex, hoplimit);
d62a17ae 794 return;
795 }
718e3744 796
d62a17ae 797 /* Check ICMP message type. */
798 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
799 rtadv_process_solicit(ifp);
800 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
801 rtadv_process_advert(buf, len, ifp, from);
718e3744 802
d62a17ae 803 return;
718e3744 804}
805
cc9f21da 806static void rtadv_read(struct thread *thread)
718e3744 807{
d62a17ae 808 int sock;
809 int len;
d7c0a89a 810 uint8_t buf[RTADV_MSG_SIZE];
d62a17ae 811 struct sockaddr_in6 from;
812 ifindex_t ifindex = 0;
813 int hoplimit = -1;
df9c8c57 814 struct zebra_vrf *zvrf = THREAD_ARG(thread);
d62a17ae 815
816 sock = THREAD_FD(thread);
df9c8c57 817 zvrf->rtadv.ra_read = NULL;
d62a17ae 818
819 /* Register myself. */
7c2ddfb9 820 rtadv_event(zvrf, RTADV_READ, 0);
d62a17ae 821
df9c8c57 822 len = rtadv_recv_packet(zvrf, sock, buf, sizeof(buf), &from, &ifindex,
d62a17ae 823 &hoplimit);
824
825 if (len < 0) {
450971aa 826 flog_err_sys(EC_LIB_SOCKET,
9df414fe
QY
827 "RA/RS recv failed, socket %u error %s", sock,
828 safe_strerror(errno));
cc9f21da 829 return;
d62a17ae 830 }
831
df9c8c57 832 rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zvrf);
718e3744 833}
6b0655a2 834
fe533c56 835static int rtadv_make_socket(ns_id_t ns_id)
718e3744 836{
8d2dcc85 837 int sock = -1;
d62a17ae 838 int ret = 0;
839 struct icmp6_filter filter;
e05506b8 840 int error;
d62a17ae 841
0cf6db21 842 frr_with_privs(&zserv_privs) {
d62a17ae 843
01b9e3fd 844 sock = ns_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, ns_id);
e05506b8
DS
845 /*
846 * with privs might set errno too if it fails save
847 * to the side
848 */
849 error = errno;
01b9e3fd 850 }
d62a17ae 851
852 if (sock < 0) {
e05506b8
DS
853 zlog_warn("RTADV socket for ns: %u failure to create: %s(%u)",
854 ns_id, safe_strerror(error), error);
d62a17ae 855 return -1;
856 }
857
858 ret = setsockopt_ipv6_pktinfo(sock, 1);
859 if (ret < 0) {
e05506b8 860 zlog_warn("RTADV failure to set Packet Information");
d62a17ae 861 close(sock);
862 return ret;
863 }
864 ret = setsockopt_ipv6_multicast_loop(sock, 0);
865 if (ret < 0) {
e05506b8 866 zlog_warn("RTADV failure to set multicast Loop detection");
d62a17ae 867 close(sock);
868 return ret;
869 }
870 ret = setsockopt_ipv6_unicast_hops(sock, 255);
871 if (ret < 0) {
e05506b8 872 zlog_warn("RTADV failure to set maximum unicast hops");
d62a17ae 873 close(sock);
874 return ret;
875 }
876 ret = setsockopt_ipv6_multicast_hops(sock, 255);
877 if (ret < 0) {
e05506b8 878 zlog_warn("RTADV failure to set maximum multicast hops");
d62a17ae 879 close(sock);
880 return ret;
881 }
882 ret = setsockopt_ipv6_hoplimit(sock, 1);
883 if (ret < 0) {
e05506b8 884 zlog_warn("RTADV failure to set maximum incoming hop limit");
d62a17ae 885 close(sock);
886 return ret;
887 }
888
889 ICMP6_FILTER_SETBLOCKALL(&filter);
890 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
891 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
892
893 ret = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
894 sizeof(struct icmp6_filter));
895 if (ret < 0) {
896 zlog_info("ICMP6_FILTER set fail: %s", safe_strerror(errno));
44f12f20 897 close(sock);
d62a17ae 898 return ret;
899 }
900
901 return sock;
718e3744 902}
903
7c2ddfb9
SW
904static struct adv_if *adv_if_new(const char *name)
905{
906 struct adv_if *new;
907
908 new = XCALLOC(MTYPE_ADV_IF, sizeof(struct adv_if));
909
910 strlcpy(new->name, name, sizeof(new->name));
911
912 return new;
913}
914
915static void adv_if_free(struct adv_if *adv_if)
916{
917 XFREE(MTYPE_ADV_IF, adv_if);
918}
919
2a356cee 920static bool adv_if_is_empty_internal(const struct adv_if_list_head *adv_if_head)
7c2ddfb9
SW
921{
922 return adv_if_list_count(adv_if_head) ? false : true;
923}
924
925static struct adv_if *adv_if_add_internal(struct adv_if_list_head *adv_if_head,
926 const char *name)
927{
928 struct adv_if adv_if_lookup = {};
929 struct adv_if *adv_if = NULL;
930
931 strlcpy(adv_if_lookup.name, name, sizeof(adv_if_lookup.name));
932 adv_if = adv_if_list_find(adv_if_head, &adv_if_lookup);
933
934 if (adv_if != NULL)
935 return adv_if;
936
937 adv_if = adv_if_new(adv_if_lookup.name);
938 adv_if_list_add(adv_if_head, adv_if);
939
940 return NULL;
941}
942
943static struct adv_if *adv_if_del_internal(struct adv_if_list_head *adv_if_head,
944 const char *name)
945{
946 struct adv_if adv_if_lookup = {};
947 struct adv_if *adv_if = NULL;
948
949 strlcpy(adv_if_lookup.name, name, sizeof(adv_if_lookup.name));
950 adv_if = adv_if_list_find(adv_if_head, &adv_if_lookup);
951
952 if (adv_if == NULL)
953 return NULL;
954
955 adv_if_list_del(adv_if_head, adv_if);
956
957 return adv_if;
958}
959
960static void adv_if_clean_internal(struct adv_if_list_head *adv_if_head)
961{
962 struct adv_if *node = NULL;
963
964 if (!adv_if_is_empty_internal(adv_if_head)) {
965 frr_each_safe (adv_if_list, adv_if_head, node) {
966 adv_if_list_del(adv_if_head, node);
967 adv_if_free(node);
968 }
969 }
970
971 adv_if_list_fini(adv_if_head);
972}
973
974
975/*
976 * Add to list. On Success, return NULL, otherwise return already existing
977 * adv_if.
978 */
979static struct adv_if *adv_if_add(struct zebra_vrf *zvrf, const char *name)
980{
981 struct adv_if *adv_if = NULL;
982
983 adv_if = adv_if_add_internal(&zvrf->rtadv.adv_if, name);
984
985 if (adv_if != NULL)
986 return adv_if;
987
988 if (IS_ZEBRA_DEBUG_EVENT) {
989 struct vrf *vrf = zvrf->vrf;
990
0bcf7589 991 zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
7c2ddfb9
SW
992 VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
993 adv_if_list_count(&zvrf->rtadv.adv_if));
994 }
995
996 return NULL;
997}
998
999/*
1000 * Del from list. On Success, return the adv_if, otherwise return NULL. Caller
1001 * frees.
1002 */
1003static struct adv_if *adv_if_del(struct zebra_vrf *zvrf, const char *name)
1004{
1005 struct adv_if *adv_if = NULL;
1006
1007 adv_if = adv_if_del_internal(&zvrf->rtadv.adv_if, name);
1008
1009 if (adv_if == NULL)
1010 return NULL;
1011
1012 if (IS_ZEBRA_DEBUG_EVENT) {
1013 struct vrf *vrf = zvrf->vrf;
1014
0bcf7589 1015 zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
7c2ddfb9
SW
1016 VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
1017 adv_if_list_count(&zvrf->rtadv.adv_if));
1018 }
1019
1020 return adv_if;
1021}
1022
1023/*
1024 * Add to list. On Success, return NULL, otherwise return already existing
1025 * adv_if.
1026 */
1027static struct adv_if *adv_msec_if_add(struct zebra_vrf *zvrf, const char *name)
1028{
1029 struct adv_if *adv_if = NULL;
1030
1031 adv_if = adv_if_add_internal(&zvrf->rtadv.adv_msec_if, name);
1032
1033 if (adv_if != NULL)
1034 return adv_if;
1035
1036 if (IS_ZEBRA_DEBUG_EVENT) {
1037 struct vrf *vrf = zvrf->vrf;
1038
0bcf7589 1039 zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
7c2ddfb9
SW
1040 VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
1041 adv_if_list_count(&zvrf->rtadv.adv_msec_if));
1042 }
1043
1044 return NULL;
1045}
1046
1047/*
1048 * Del from list. On Success, return the adv_if, otherwise return NULL. Caller
1049 * frees.
1050 */
1051static struct adv_if *adv_msec_if_del(struct zebra_vrf *zvrf, const char *name)
1052{
1053 struct adv_if *adv_if = NULL;
1054
1055 adv_if = adv_if_del_internal(&zvrf->rtadv.adv_msec_if, name);
1056
1057 if (adv_if == NULL)
1058 return NULL;
1059
1060 if (IS_ZEBRA_DEBUG_EVENT) {
1061 struct vrf *vrf = zvrf->vrf;
1062
0bcf7589 1063 zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
7c2ddfb9
SW
1064 VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
1065 adv_if_list_count(&zvrf->rtadv.adv_msec_if));
1066 }
1067
1068 return adv_if;
1069}
1070
1071/* Clean adv_if list, called on vrf terminate */
1072static void adv_if_clean(struct zebra_vrf *zvrf)
1073{
1074 if (IS_ZEBRA_DEBUG_EVENT) {
1075 struct vrf *vrf = zvrf->vrf;
1076
0bcf7589 1077 zlog_debug("%s: %s:%u count: %zu -> 0", __func__,
7c2ddfb9
SW
1078 VRF_LOGNAME(vrf), zvrf_id(zvrf),
1079 adv_if_list_count(&zvrf->rtadv.adv_if));
1080 }
1081
1082 adv_if_clean_internal(&zvrf->rtadv.adv_if);
1083}
1084
1085/* Clean adv_msec_if list, called on vrf terminate */
1086static void adv_msec_if_clean(struct zebra_vrf *zvrf)
1087{
1088 if (IS_ZEBRA_DEBUG_EVENT) {
1089 struct vrf *vrf = zvrf->vrf;
1090
0bcf7589 1091 zlog_debug("%s: %s:%u count: %zu -> 0", __func__,
7c2ddfb9
SW
1092 VRF_LOGNAME(vrf), zvrf_id(zvrf),
1093 adv_if_list_count(&zvrf->rtadv.adv_msec_if));
1094 }
1095
1096 adv_if_clean_internal(&zvrf->rtadv.adv_msec_if);
1097}
1098
d62a17ae 1099static struct rtadv_prefix *rtadv_prefix_new(void)
718e3744 1100{
d62a17ae 1101 return XCALLOC(MTYPE_RTADV_PREFIX, sizeof(struct rtadv_prefix));
718e3744 1102}
1103
d62a17ae 1104static void rtadv_prefix_free(struct rtadv_prefix *rtadv_prefix)
718e3744 1105{
d62a17ae 1106 XFREE(MTYPE_RTADV_PREFIX, rtadv_prefix);
1107}
718e3744 1108
7ca9c407 1109static struct rtadv_prefix *rtadv_prefix_get(struct rtadv_prefixes_head *list,
d62a17ae 1110 struct prefix_ipv6 *p)
718e3744 1111{
7ca9c407
DL
1112 struct rtadv_prefix *rprefix, ref;
1113
1114 ref.prefix = *p;
d62a17ae 1115
7ca9c407 1116 rprefix = rtadv_prefixes_find(list, &ref);
d62a17ae 1117 if (rprefix)
1118 return rprefix;
718e3744 1119
d62a17ae 1120 rprefix = rtadv_prefix_new();
1121 memcpy(&rprefix->prefix, p, sizeof(struct prefix_ipv6));
7ca9c407 1122 rtadv_prefixes_add(list, rprefix);
718e3744 1123
d62a17ae 1124 return rprefix;
718e3744 1125}
1126
2a855763
DS
1127static void rtadv_prefix_set_defaults(struct rtadv_prefix *rp)
1128{
1129 rp->AdvAutonomousFlag = 1;
1130 rp->AdvOnLinkFlag = 1;
1131 rp->AdvRouterAddressFlag = 0;
1132 rp->AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
1133 rp->AdvValidLifetime = RTADV_VALID_LIFETIME;
1134}
1135
d62a17ae 1136static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp)
718e3744 1137{
d62a17ae 1138 struct rtadv_prefix *rprefix;
1139
7ca9c407 1140 rprefix = rtadv_prefix_get(zif->rtadv.prefixes, &rp->prefix);
d62a17ae 1141
2a855763
DS
1142 /*
1143 * Set parameters based on where the prefix is created.
1144 * If auto-created based on kernel address addition, set the
1145 * default values. If created from a manual "ipv6 nd prefix"
1146 * command, take the parameters from the manual command. Note
1147 * that if the manual command exists, the default values will
1148 * not overwrite the manual values.
1149 */
1150 if (rp->AdvPrefixCreate == PREFIX_SRC_MANUAL) {
1151 if (rprefix->AdvPrefixCreate == PREFIX_SRC_AUTO)
1152 rprefix->AdvPrefixCreate = PREFIX_SRC_BOTH;
1153 else
1154 rprefix->AdvPrefixCreate = PREFIX_SRC_MANUAL;
1155
1156 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
1157 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
1158 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
1159 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
1160 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
1161 } else if (rp->AdvPrefixCreate == PREFIX_SRC_AUTO) {
1162 if (rprefix->AdvPrefixCreate == PREFIX_SRC_MANUAL)
1163 rprefix->AdvPrefixCreate = PREFIX_SRC_BOTH;
1164 else {
1165 rprefix->AdvPrefixCreate = PREFIX_SRC_AUTO;
1166 rtadv_prefix_set_defaults(rprefix);
1167 }
1168 }
718e3744 1169}
1170
d62a17ae 1171static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp)
718e3744 1172{
d62a17ae 1173 struct rtadv_prefix *rprefix;
1174
7ca9c407 1175 rprefix = rtadv_prefixes_find(zif->rtadv.prefixes, rp);
d62a17ae 1176 if (rprefix != NULL) {
2a855763
DS
1177
1178 /*
1179 * When deleting an address from the list, need to take care
1180 * it wasn't defined both automatically via kernel
1181 * address addition as well as manually by vtysh cli. If both,
1182 * we don't actually delete but may change the parameters
1183 * back to default if a manually defined entry is deleted.
1184 */
1185 if (rp->AdvPrefixCreate == PREFIX_SRC_MANUAL) {
1186 if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) {
1187 rprefix->AdvPrefixCreate = PREFIX_SRC_AUTO;
1188 rtadv_prefix_set_defaults(rprefix);
1189 return 1;
1190 }
1191 } else if (rp->AdvPrefixCreate == PREFIX_SRC_AUTO) {
1192 if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) {
1193 rprefix->AdvPrefixCreate = PREFIX_SRC_MANUAL;
1194 return 1;
1195 }
1196 }
1197
7ca9c407 1198 rtadv_prefixes_del(zif->rtadv.prefixes, rprefix);
d62a17ae 1199 rtadv_prefix_free(rprefix);
1200 return 1;
1201 } else
1202 return 0;
718e3744 1203}
1204
2a855763
DS
1205/* Add IPv6 prefixes learned from the kernel to the RA prefix list */
1206void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p)
1207{
1208 struct rtadv_prefix rp;
1209
1210 rp.prefix = *p;
1211 apply_mask_ipv6(&rp.prefix);
1212 rp.AdvPrefixCreate = PREFIX_SRC_AUTO;
1213 rtadv_prefix_set(zif, &rp);
1214}
1215
1216/* Delete IPv6 prefixes removed by the kernel from the RA prefix list */
1217void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p)
1218{
1219 struct rtadv_prefix rp;
1220
1221 rp.prefix = *((struct prefix_ipv6 *)p);
1222 apply_mask_ipv6(&rp.prefix);
1223 rp.AdvPrefixCreate = PREFIX_SRC_AUTO;
1224 rtadv_prefix_reset(zif, &rp);
1225}
1226
7937058b
DS
1227static void rtadv_start_interface_events(struct zebra_vrf *zvrf,
1228 struct zebra_if *zif)
1229{
1230 struct adv_if *adv_if = NULL;
1231
1232 if (zif->ifp->ifindex == IFINDEX_INTERNAL) {
1233 if (IS_ZEBRA_DEBUG_EVENT)
1234 zlog_debug(
1235 "%s(%s) has not configured an ifindex yet, delaying until we have one",
1236 zif->ifp->name, zvrf->vrf->name);
1237 return;
1238 }
1239
1240 adv_if = adv_if_add(zvrf, zif->ifp->name);
1241 if (adv_if != NULL)
1242 return; /* Already added */
1243
1244 if_join_all_router(zvrf->rtadv.sock, zif->ifp);
1245
1246 if (adv_if_list_count(&zvrf->rtadv.adv_if) == 1)
1247 rtadv_event(zvrf, RTADV_START, 0);
1248}
1249
d62a17ae 1250static void ipv6_nd_suppress_ra_set(struct interface *ifp,
57dd8642 1251 enum ipv6_nd_suppress_ra_status status)
b6120505 1252{
d62a17ae 1253 struct zebra_if *zif;
1254 struct zebra_vrf *zvrf;
7c2ddfb9 1255 struct adv_if *adv_if = NULL;
d62a17ae 1256
1257 zif = ifp->info;
7c2ddfb9
SW
1258
1259 zvrf = rtadv_interface_get_zvrf(ifp);
d62a17ae 1260
1261 if (status == RA_SUPPRESS) {
1262 /* RA is currently enabled */
1263 if (zif->rtadv.AdvSendAdvertisements) {
7c2ddfb9 1264 rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_SUPPRESS);
d62a17ae 1265 zif->rtadv.AdvSendAdvertisements = 0;
1266 zif->rtadv.AdvIntervalTimer = 0;
d62a17ae 1267
7c2ddfb9
SW
1268 adv_if = adv_if_del(zvrf, ifp->name);
1269 if (adv_if == NULL)
1270 return; /* Nothing to delete */
1271
1272 adv_if_free(adv_if);
d62a17ae 1273
7c2ddfb9
SW
1274 if_leave_all_router(zvrf->rtadv.sock, ifp);
1275
1276 if (adv_if_list_count(&zvrf->rtadv.adv_if) == 0)
df9c8c57 1277 rtadv_event(zvrf, RTADV_STOP, 0);
d62a17ae 1278 }
1279 } else {
1280 if (!zif->rtadv.AdvSendAdvertisements) {
1281 zif->rtadv.AdvSendAdvertisements = 1;
1282 zif->rtadv.AdvIntervalTimer = 0;
adee8f21
DS
1283 if ((zif->rtadv.MaxRtrAdvInterval >= 1000)
1284 && zif->rtadv.UseFastRexmit) {
1285 /*
1286 * Enable Fast RA only when RA interval is in
1287 * secs and Fast RA retransmit is enabled
1288 */
d62a17ae 1289 zif->rtadv.inFastRexmit = 1;
1290 zif->rtadv.NumFastReXmitsRemain =
1291 RTADV_NUM_FAST_REXMITS;
1292 }
1293
7937058b 1294 rtadv_start_interface_events(zvrf, zif);
d62a17ae 1295 }
1296 }
b6120505
DW
1297}
1298
4a04e5f7 1299/*
1300 * Handle client (BGP) message to enable or disable IPv6 RA on an interface.
1301 * Note that while the client could request RA on an interface on which the
1302 * operator has not enabled RA, RA won't be disabled upon client request
5c81b96a 1303 * if the operator has explicitly enabled RA. The enable request can also
1304 * specify a RA interval (in seconds).
4a04e5f7 1305 */
1002497a 1306static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
4a04e5f7 1307{
d62a17ae 1308 struct stream *s;
ec93aa12 1309 ifindex_t ifindex;
d62a17ae 1310 struct interface *ifp;
1311 struct zebra_if *zif;
bbad0276 1312 uint32_t ra_interval;
d62a17ae 1313
1002497a 1314 s = msg;
d62a17ae 1315
1316 /* Get interface index and RA interval. */
ec93aa12 1317 STREAM_GETL(s, ifindex);
bbad0276 1318 STREAM_GETL(s, ra_interval);
d62a17ae 1319
60077146
DS
1320 if (IS_ZEBRA_DEBUG_EVENT) {
1321 struct vrf *vrf = zvrf->vrf;
1322
1323 zlog_debug("%s:%u: IF %u RA %s from client %s, interval %ums",
1324 VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
1002497a 1325 enable ? "enable" : "disable",
d62a17ae 1326 zebra_route_string(client->proto), ra_interval);
60077146 1327 }
d62a17ae 1328
1329 /* Locate interface and check VRF match. */
df9c8c57 1330 ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
d62a17ae 1331 if (!ifp) {
60077146
DS
1332 struct vrf *vrf = zvrf->vrf;
1333
e914ccbe 1334 flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
60077146
DS
1335 "%s:%u: IF %u RA %s client %s - interface unknown",
1336 VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
1337 enable ? "enable" : "disable",
d62a17ae 1338 zebra_route_string(client->proto));
1339 return;
1340 }
096f7609 1341 if (vrf_is_backend_netns() && ifp->vrf->vrf_id != zvrf_id(zvrf)) {
9df414fe 1342 zlog_debug(
60077146 1343 "%s:%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
096f7609 1344 ifp->vrf->name, zvrf_id(zvrf), ifindex,
60077146 1345 enable ? "enable" : "disable",
096f7609 1346 zebra_route_string(client->proto), ifp->vrf->vrf_id);
d62a17ae 1347 return;
1348 }
1349
1350 zif = ifp->info;
1002497a 1351 if (enable) {
954e1a2b
DS
1352 if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1353 interfaces_configured_for_ra_from_bgp++;
1354
3ea48364 1355 SET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
d62a17ae 1356 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
1357 if (ra_interval
40441c3d 1358 && (ra_interval * 1000) < (unsigned int) zif->rtadv.MaxRtrAdvInterval
996c9314
LB
1359 && !CHECK_FLAG(zif->rtadv.ra_configured,
1360 VTY_RA_INTERVAL_CONFIGURED))
d62a17ae 1361 zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000;
1362 } else {
954e1a2b
DS
1363 if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1364 interfaces_configured_for_ra_from_bgp--;
1365
3ea48364
DS
1366 UNSET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
1367 if (!CHECK_FLAG(zif->rtadv.ra_configured,
1368 VTY_RA_INTERVAL_CONFIGURED))
d62a17ae 1369 zif->rtadv.MaxRtrAdvInterval =
1370 RTADV_MAX_RTR_ADV_INTERVAL;
3ea48364 1371 if (!CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
d62a17ae 1372 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
d62a17ae 1373 }
ec93aa12
DS
1374stream_failure:
1375 return;
4a04e5f7 1376}
1377
d7fc0e67
DS
1378/*
1379 * send router lifetime value of zero in RAs on this interface since we're
1380 * ceasing to advertise and want to let our neighbors know.
1381 * RFC 4861 secion 6.2.5
1382 */
1383void rtadv_stop_ra(struct interface *ifp)
1384{
1385 struct zebra_if *zif;
1386 struct zebra_vrf *zvrf;
1387
1388 zif = ifp->info;
7c2ddfb9 1389 zvrf = rtadv_interface_get_zvrf(ifp);
d7fc0e67
DS
1390
1391 if (zif->rtadv.AdvSendAdvertisements)
7c2ddfb9 1392 rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_SUPPRESS);
d7fc0e67
DS
1393}
1394
1395/*
5a7aea85 1396 * Send router lifetime value of zero in RAs on all interfaces since we're
d7fc0e67
DS
1397 * ceasing to advertise globally and want to let all of our neighbors know
1398 * RFC 4861 secion 6.2.5
5a7aea85
DS
1399 *
1400 * Delete all ipv6 global prefixes added to the router advertisement prefix
1401 * lists prior to ceasing.
d7fc0e67
DS
1402 */
1403void rtadv_stop_ra_all(void)
1404{
1405 struct vrf *vrf;
1406 struct interface *ifp;
5a7aea85
DS
1407 struct zebra_if *zif;
1408 struct rtadv_prefix *rprefix;
d7fc0e67
DS
1409
1410 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
5a7aea85
DS
1411 FOR_ALL_INTERFACES (vrf, ifp) {
1412 zif = ifp->info;
1413
7ca9c407
DL
1414 frr_each_safe (rtadv_prefixes, zif->rtadv.prefixes,
1415 rprefix)
5a7aea85
DS
1416 rtadv_prefix_reset(zif, rprefix);
1417
d7fc0e67 1418 rtadv_stop_ra(ifp);
5a7aea85 1419 }
d7fc0e67
DS
1420}
1421
89f4e507
QY
1422void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS)
1423{
1002497a 1424 zebra_interface_radv_set(client, hdr, msg, zvrf, 0);
89f4e507 1425}
89f4e507
QY
1426void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS)
1427{
1002497a 1428 zebra_interface_radv_set(client, hdr, msg, zvrf, 1);
89f4e507
QY
1429}
1430
2a356cee
SW
1431static void show_zvrf_rtadv_adv_if_helper(struct vty *vty,
1432 struct adv_if_list_head *adv_if_head)
1433{
1434 struct adv_if *node = NULL;
1435
1436 if (!adv_if_is_empty_internal(adv_if_head)) {
1437 frr_each (adv_if_list, adv_if_head, node) {
1438 vty_out(vty, " %s\n", node->name);
1439 }
1440 }
1441
1442 vty_out(vty, "\n");
1443}
1444
1445static void show_zvrf_rtadv_helper(struct vty *vty, struct zebra_vrf *zvrf)
1446{
1447 vty_out(vty, "VRF: %s\n", zvrf_name(zvrf));
1448 vty_out(vty, " Interfaces:\n");
1449 show_zvrf_rtadv_adv_if_helper(vty, &zvrf->rtadv.adv_if);
1450
1451 vty_out(vty, " Interfaces(msec):\n");
1452 show_zvrf_rtadv_adv_if_helper(vty, &zvrf->rtadv.adv_msec_if);
1453}
1454
1455DEFPY(show_ipv6_nd_ra_if, show_ipv6_nd_ra_if_cmd,
1456 "show ipv6 nd ra-interfaces [vrf<NAME$vrf_name|all$vrf_all>]",
1457 SHOW_STR IP6_STR
1458 "Neighbor discovery\n"
1459 "Route Advertisement Interfaces\n" VRF_FULL_CMD_HELP_STR)
1460{
1461 struct zebra_vrf *zvrf = NULL;
1462
1463 if (!vrf_is_backend_netns() && (vrf_name || vrf_all)) {
1464 vty_out(vty,
1465 "%% VRF subcommand only applicable for netns-based vrfs.\n");
1466 return CMD_WARNING;
1467 }
1468
1469 if (vrf_all) {
1470 struct vrf *vrf;
1471
1472 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1473 struct zebra_vrf *zvrf;
1474
1475 zvrf = vrf->info;
1476 if (!zvrf)
1477 continue;
1478
1479 show_zvrf_rtadv_helper(vty, zvrf);
1480 }
1481
1482 return CMD_SUCCESS;
1483 }
1484
1485 if (vrf_name)
1486 zvrf = zebra_vrf_lookup_by_name(vrf_name);
1487 else
1488 zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
1489
1490 if (!zvrf) {
1491 vty_out(vty, "%% VRF '%s' specified does not exist\n",
1492 vrf_name);
1493 return CMD_WARNING;
1494 }
1495
1496 show_zvrf_rtadv_helper(vty, zvrf);
1497
1498 return CMD_SUCCESS;
1499}
1500
adee8f21
DS
1501DEFUN (ipv6_nd_ra_fast_retrans,
1502 ipv6_nd_ra_fast_retrans_cmd,
1503 "ipv6 nd ra-fast-retrans",
1504 "Interface IPv6 config commands\n"
1505 "Neighbor discovery\n"
1506 "Fast retransmit of RA packets\n")
1507{
1508 VTY_DECLVAR_CONTEXT(interface, ifp);
1509 struct zebra_if *zif = ifp->info;
1510
608c8870 1511 if (if_is_loopback(ifp)) {
adee8f21
DS
1512 vty_out(vty,
1513 "Cannot configure IPv6 Router Advertisements on this interface\n");
1514 return CMD_WARNING_CONFIG_FAILED;
1515 }
1516
1517 zif->rtadv.UseFastRexmit = true;
1518
1519 return CMD_SUCCESS;
1520}
1521
1522DEFUN (no_ipv6_nd_ra_fast_retrans,
1523 no_ipv6_nd_ra_fast_retrans_cmd,
1524 "no ipv6 nd ra-fast-retrans",
1525 NO_STR
1526 "Interface IPv6 config commands\n"
1527 "Neighbor discovery\n"
1528 "Fast retransmit of RA packets\n")
1529{
1530 VTY_DECLVAR_CONTEXT(interface, ifp);
1531 struct zebra_if *zif = ifp->info;
1532
608c8870 1533 if (if_is_loopback(ifp)) {
adee8f21
DS
1534 vty_out(vty,
1535 "Cannot configure IPv6 Router Advertisements on this interface\n");
1536 return CMD_WARNING_CONFIG_FAILED;
1537 }
1538
1539 zif->rtadv.UseFastRexmit = false;
1540
1541 return CMD_SUCCESS;
1542}
1543
fae01935
DS
1544DEFPY (ipv6_nd_ra_hop_limit,
1545 ipv6_nd_ra_hop_limit_cmd,
1546 "ipv6 nd ra-hop-limit (0-255)$hopcount",
1547 "Interface IPv6 config commands\n"
1548 "Neighbor discovery\n"
1549 "Advertisement Hop Limit\n"
1550 "Advertisement Hop Limit in hops (default:64)\n")
1551{
1552 VTY_DECLVAR_CONTEXT(interface, ifp);
1553 struct zebra_if *zif = ifp->info;
1554
608c8870 1555 if (if_is_loopback(ifp)) {
fae01935
DS
1556 vty_out(vty,
1557 "Cannot configure IPv6 Router Advertisements on this interface\n");
1558 return CMD_WARNING_CONFIG_FAILED;
1559 }
1560
1561 zif->rtadv.AdvCurHopLimit = hopcount;
1562
1563 return CMD_SUCCESS;
1564}
1565
1566DEFPY (no_ipv6_nd_ra_hop_limit,
1567 no_ipv6_nd_ra_hop_limit_cmd,
1568 "no ipv6 nd ra-hop-limit [(0-255)]",
1569 NO_STR
1570 "Interface IPv6 config commands\n"
1571 "Neighbor discovery\n"
1572 "Advertisement Hop Limit\n"
1573 "Advertisement Hop Limit in hops\n")
1574{
1575 VTY_DECLVAR_CONTEXT(interface, ifp);
1576 struct zebra_if *zif = ifp->info;
1577
608c8870 1578 if (if_is_loopback(ifp)) {
fae01935
DS
1579 vty_out(vty,
1580 "Cannot configure IPv6 Router Advertisements on this interface\n");
1581 return CMD_WARNING_CONFIG_FAILED;
1582 }
1583
1584 zif->rtadv.AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT;
1585
1586 return CMD_SUCCESS;
1587}
1588
b19ac878
DS
1589DEFPY (ipv6_nd_ra_retrans_interval,
1590 ipv6_nd_ra_retrans_interval_cmd,
1591 "ipv6 nd ra-retrans-interval (0-4294967295)$interval",
1592 "Interface IPv6 config commands\n"
1593 "Neighbor discovery\n"
1594 "Advertisement Retransmit Interval\n"
1595 "Advertisement Retransmit Interval in msec\n")
1596{
1597 VTY_DECLVAR_CONTEXT(interface, ifp);
1598 struct zebra_if *zif = ifp->info;
1599
608c8870 1600 if (if_is_loopback(ifp)) {
b19ac878
DS
1601 vty_out(vty,
1602 "Cannot configure IPv6 Router Advertisements on loopback interface\n");
1603 return CMD_WARNING_CONFIG_FAILED;
1604 }
1605
1606 zif->rtadv.AdvRetransTimer = interval;
1607
1608 return CMD_SUCCESS;
1609}
1610
1611DEFPY (no_ipv6_nd_ra_retrans_interval,
1612 no_ipv6_nd_ra_retrans_interval_cmd,
1613 "no ipv6 nd ra-retrans-interval [(0-4294967295)]",
1614 NO_STR
1615 "Interface IPv6 config commands\n"
1616 "Neighbor discovery\n"
1617 "Advertisement Retransmit Interval\n"
1618 "Advertisement Retransmit Interval in msec\n")
1619{
1620 VTY_DECLVAR_CONTEXT(interface, ifp);
1621 struct zebra_if *zif = ifp->info;
1622
608c8870 1623 if (if_is_loopback(ifp)) {
b19ac878
DS
1624 vty_out(vty,
1625 "Cannot remove IPv6 Router Advertisements on loopback interface\n");
1626 return CMD_WARNING_CONFIG_FAILED;
1627 }
1628
1629 zif->rtadv.AdvRetransTimer = 0;
1630
1631 return CMD_SUCCESS;
1632}
1633
718e3744 1634DEFUN (ipv6_nd_suppress_ra,
1635 ipv6_nd_suppress_ra_cmd,
1636 "ipv6 nd suppress-ra",
3e31cded 1637 "Interface IPv6 config commands\n"
718e3744 1638 "Neighbor discovery\n"
1639 "Suppress Router Advertisement\n")
1640{
d62a17ae 1641 VTY_DECLVAR_CONTEXT(interface, ifp);
1642 struct zebra_if *zif = ifp->info;
1643
608c8870 1644 if (if_is_loopback(ifp)) {
d62a17ae 1645 vty_out(vty,
1646 "Cannot configure IPv6 Router Advertisements on this interface\n");
1647 return CMD_WARNING_CONFIG_FAILED;
1648 }
1649
3ea48364
DS
1650 if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1651 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
1652
1653 UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
d62a17ae 1654 return CMD_SUCCESS;
718e3744 1655}
1656
718e3744 1657DEFUN (no_ipv6_nd_suppress_ra,
1658 no_ipv6_nd_suppress_ra_cmd,
1659 "no ipv6 nd suppress-ra",
1660 NO_STR
3e31cded 1661 "Interface IPv6 config commands\n"
718e3744 1662 "Neighbor discovery\n"
1663 "Suppress Router Advertisement\n")
1664{
d62a17ae 1665 VTY_DECLVAR_CONTEXT(interface, ifp);
1666 struct zebra_if *zif = ifp->info;
1667
608c8870 1668 if (if_is_loopback(ifp)) {
d62a17ae 1669 vty_out(vty,
1670 "Cannot configure IPv6 Router Advertisements on this interface\n");
1671 return CMD_WARNING_CONFIG_FAILED;
1672 }
1673
1674 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
3ea48364 1675 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
d62a17ae 1676 return CMD_SUCCESS;
718e3744 1677}
1678
7cee1bb1 1679DEFUN (ipv6_nd_ra_interval_msec,
1680 ipv6_nd_ra_interval_msec_cmd,
6147e2c6 1681 "ipv6 nd ra-interval msec (70-1800000)",
7cee1bb1 1682 "Interface IPv6 config commands\n"
1683 "Neighbor discovery\n"
1684 "Router Advertisement interval\n"
3a2d747c 1685 "Router Advertisement interval in milliseconds\n"
7cee1bb1 1686 "Router Advertisement interval in milliseconds\n")
1687{
d62a17ae 1688 int idx_number = 4;
1689 VTY_DECLVAR_CONTEXT(interface, ifp);
1690 unsigned interval;
1691 struct zebra_if *zif = ifp->info;
df9c8c57 1692 struct zebra_vrf *zvrf;
7c2ddfb9 1693 struct adv_if *adv_if;
df9c8c57 1694
7c2ddfb9 1695 zvrf = rtadv_interface_get_zvrf(ifp);
d62a17ae 1696
d62a17ae 1697 interval = strtoul(argv[idx_number]->arg, NULL, 10);
1698 if ((zif->rtadv.AdvDefaultLifetime != -1
1699 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) {
1700 vty_out(vty,
1701 "This ra-interval would conflict with configured ra-lifetime!\n");
1702 return CMD_WARNING_CONFIG_FAILED;
1703 }
1704
7c2ddfb9
SW
1705 if (zif->rtadv.MaxRtrAdvInterval % 1000) {
1706 adv_if = adv_msec_if_del(zvrf, ifp->name);
1707 if (adv_if != NULL)
1708 adv_if_free(adv_if);
1709 }
d62a17ae 1710
1711 if (interval % 1000)
7c2ddfb9 1712 (void)adv_msec_if_add(zvrf, ifp->name);
d62a17ae 1713
3ea48364 1714 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
d62a17ae 1715 zif->rtadv.MaxRtrAdvInterval = interval;
1716 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
1717 zif->rtadv.AdvIntervalTimer = 0;
1718
1719 return CMD_SUCCESS;
7cee1bb1 1720}
1721
718e3744 1722DEFUN (ipv6_nd_ra_interval,
1723 ipv6_nd_ra_interval_cmd,
6147e2c6 1724 "ipv6 nd ra-interval (1-1800)",
3e31cded 1725 "Interface IPv6 config commands\n"
718e3744 1726 "Neighbor discovery\n"
1727 "Router Advertisement interval\n"
1728 "Router Advertisement interval in seconds\n")
1729{
d62a17ae 1730 int idx_number = 3;
1731 VTY_DECLVAR_CONTEXT(interface, ifp);
1732 unsigned interval;
1733 struct zebra_if *zif = ifp->info;
df9c8c57 1734 struct zebra_vrf *zvrf;
7c2ddfb9 1735 struct adv_if *adv_if;
df9c8c57 1736
7c2ddfb9 1737 zvrf = rtadv_interface_get_zvrf(ifp);
d62a17ae 1738
d62a17ae 1739 interval = strtoul(argv[idx_number]->arg, NULL, 10);
1740 if ((zif->rtadv.AdvDefaultLifetime != -1
1741 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) {
1742 vty_out(vty,
1743 "This ra-interval would conflict with configured ra-lifetime!\n");
1744 return CMD_WARNING_CONFIG_FAILED;
1745 }
1746
7c2ddfb9
SW
1747 if (zif->rtadv.MaxRtrAdvInterval % 1000) {
1748 adv_if = adv_msec_if_del(zvrf, ifp->name);
1749 if (adv_if != NULL)
1750 adv_if_free(adv_if);
1751 }
d62a17ae 1752
1753 /* convert to milliseconds */
1754 interval = interval * 1000;
1755
3ea48364 1756 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
d62a17ae 1757 zif->rtadv.MaxRtrAdvInterval = interval;
1758 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
1759 zif->rtadv.AdvIntervalTimer = 0;
1760
1761 return CMD_SUCCESS;
718e3744 1762}
1763
1764DEFUN (no_ipv6_nd_ra_interval,
1765 no_ipv6_nd_ra_interval_cmd,
34ccea1e 1766 "no ipv6 nd ra-interval [<(1-1800)|msec (1-1800000)>]",
718e3744 1767 NO_STR
3e31cded 1768 "Interface IPv6 config commands\n"
718e3744 1769 "Neighbor discovery\n"
34ccea1e
QY
1770 "Router Advertisement interval\n"
1771 "Router Advertisement interval in seconds\n"
1772 "Specify millisecond router advertisement interval\n"
1773 "Router Advertisement interval in milliseconds\n")
718e3744 1774{
d62a17ae 1775 VTY_DECLVAR_CONTEXT(interface, ifp);
1776 struct zebra_if *zif = ifp->info;
df9c8c57 1777 struct zebra_vrf *zvrf = NULL;
7c2ddfb9 1778 struct adv_if *adv_if;
df9c8c57 1779
7c2ddfb9 1780 zvrf = rtadv_interface_get_zvrf(ifp);
d62a17ae 1781
7c2ddfb9
SW
1782 if (zif->rtadv.MaxRtrAdvInterval % 1000) {
1783 adv_if = adv_msec_if_del(zvrf, ifp->name);
1784 if (adv_if != NULL)
1785 adv_if_free(adv_if);
1786 }
d62a17ae 1787
3ea48364
DS
1788 UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
1789
1790 if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1791 zif->rtadv.MaxRtrAdvInterval = 10000;
1792 else
1793 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
1794
d62a17ae 1795 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
3ea48364 1796 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
d62a17ae 1797
1798 return CMD_SUCCESS;
718e3744 1799}
1800
1801DEFUN (ipv6_nd_ra_lifetime,
1802 ipv6_nd_ra_lifetime_cmd,
6147e2c6 1803 "ipv6 nd ra-lifetime (0-9000)",
3e31cded 1804 "Interface IPv6 config commands\n"
718e3744 1805 "Neighbor discovery\n"
1806 "Router lifetime\n"
4afa50b3 1807 "Router lifetime in seconds (0 stands for a non-default gw)\n")
718e3744 1808{
d62a17ae 1809 int idx_number = 3;
1810 VTY_DECLVAR_CONTEXT(interface, ifp);
1811 struct zebra_if *zif = ifp->info;
1812 int lifetime;
1813
1814 lifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1815
1816 /* The value to be placed in the Router Lifetime field
1817 * of Router Advertisements sent from the interface,
1818 * in seconds. MUST be either zero or between
1819 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
1820 if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) {
1821 vty_out(vty,
1822 "This ra-lifetime would conflict with configured ra-interval\n");
1823 return CMD_WARNING_CONFIG_FAILED;
1824 }
1825
1826 zif->rtadv.AdvDefaultLifetime = lifetime;
1827
1828 return CMD_SUCCESS;
718e3744 1829}
1830
1831DEFUN (no_ipv6_nd_ra_lifetime,
1832 no_ipv6_nd_ra_lifetime_cmd,
34ccea1e 1833 "no ipv6 nd ra-lifetime [(0-9000)]",
718e3744 1834 NO_STR
3e31cded 1835 "Interface IPv6 config commands\n"
718e3744 1836 "Neighbor discovery\n"
34ccea1e
QY
1837 "Router lifetime\n"
1838 "Router lifetime in seconds (0 stands for a non-default gw)\n")
718e3744 1839{
d62a17ae 1840 VTY_DECLVAR_CONTEXT(interface, ifp);
1841 struct zebra_if *zif = ifp->info;
718e3744 1842
d62a17ae 1843 zif->rtadv.AdvDefaultLifetime = -1;
718e3744 1844
d62a17ae 1845 return CMD_SUCCESS;
718e3744 1846}
1847
1848DEFUN (ipv6_nd_reachable_time,
1849 ipv6_nd_reachable_time_cmd,
6147e2c6 1850 "ipv6 nd reachable-time (1-3600000)",
3e31cded 1851 "Interface IPv6 config commands\n"
718e3744 1852 "Neighbor discovery\n"
1853 "Reachable time\n"
1854 "Reachable time in milliseconds\n")
1855{
d62a17ae 1856 int idx_number = 3;
1857 VTY_DECLVAR_CONTEXT(interface, ifp);
1858 struct zebra_if *zif = ifp->info;
1859 zif->rtadv.AdvReachableTime = strtoul(argv[idx_number]->arg, NULL, 10);
1860 return CMD_SUCCESS;
718e3744 1861}
1862
1863DEFUN (no_ipv6_nd_reachable_time,
1864 no_ipv6_nd_reachable_time_cmd,
34ccea1e 1865 "no ipv6 nd reachable-time [(1-3600000)]",
718e3744 1866 NO_STR
3e31cded 1867 "Interface IPv6 config commands\n"
718e3744 1868 "Neighbor discovery\n"
34ccea1e
QY
1869 "Reachable time\n"
1870 "Reachable time in milliseconds\n")
718e3744 1871{
d62a17ae 1872 VTY_DECLVAR_CONTEXT(interface, ifp);
1873 struct zebra_if *zif = ifp->info;
718e3744 1874
d62a17ae 1875 zif->rtadv.AdvReachableTime = 0;
718e3744 1876
d62a17ae 1877 return CMD_SUCCESS;
718e3744 1878}
1879
7cee1bb1 1880DEFUN (ipv6_nd_homeagent_preference,
1881 ipv6_nd_homeagent_preference_cmd,
6147e2c6 1882 "ipv6 nd home-agent-preference (0-65535)",
7cee1bb1 1883 "Interface IPv6 config commands\n"
1884 "Neighbor discovery\n"
1885 "Home Agent preference\n"
4afa50b3 1886 "preference value (default is 0, least preferred)\n")
7cee1bb1 1887{
d62a17ae 1888 int idx_number = 3;
1889 VTY_DECLVAR_CONTEXT(interface, ifp);
1890 struct zebra_if *zif = ifp->info;
1891 zif->rtadv.HomeAgentPreference =
1892 strtoul(argv[idx_number]->arg, NULL, 10);
1893 return CMD_SUCCESS;
7cee1bb1 1894}
1895
1896DEFUN (no_ipv6_nd_homeagent_preference,
1897 no_ipv6_nd_homeagent_preference_cmd,
34ccea1e 1898 "no ipv6 nd home-agent-preference [(0-65535)]",
7cee1bb1 1899 NO_STR
1900 "Interface IPv6 config commands\n"
1901 "Neighbor discovery\n"
34ccea1e
QY
1902 "Home Agent preference\n"
1903 "preference value (default is 0, least preferred)\n")
7cee1bb1 1904{
d62a17ae 1905 VTY_DECLVAR_CONTEXT(interface, ifp);
1906 struct zebra_if *zif = ifp->info;
7cee1bb1 1907
d62a17ae 1908 zif->rtadv.HomeAgentPreference = 0;
7cee1bb1 1909
d62a17ae 1910 return CMD_SUCCESS;
7cee1bb1 1911}
1912
1913DEFUN (ipv6_nd_homeagent_lifetime,
1914 ipv6_nd_homeagent_lifetime_cmd,
6147e2c6 1915 "ipv6 nd home-agent-lifetime (0-65520)",
7cee1bb1 1916 "Interface IPv6 config commands\n"
1917 "Neighbor discovery\n"
1918 "Home Agent lifetime\n"
4afa50b3 1919 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
7cee1bb1 1920{
d62a17ae 1921 int idx_number = 3;
1922 VTY_DECLVAR_CONTEXT(interface, ifp);
1923 struct zebra_if *zif = ifp->info;
1924 zif->rtadv.HomeAgentLifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1925 return CMD_SUCCESS;
7cee1bb1 1926}
1927
1928DEFUN (no_ipv6_nd_homeagent_lifetime,
1929 no_ipv6_nd_homeagent_lifetime_cmd,
34ccea1e 1930 "no ipv6 nd home-agent-lifetime [(0-65520)]",
7cee1bb1 1931 NO_STR
1932 "Interface IPv6 config commands\n"
1933 "Neighbor discovery\n"
34ccea1e
QY
1934 "Home Agent lifetime\n"
1935 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
7cee1bb1 1936{
d62a17ae 1937 VTY_DECLVAR_CONTEXT(interface, ifp);
1938 struct zebra_if *zif = ifp->info;
7cee1bb1 1939
d62a17ae 1940 zif->rtadv.HomeAgentLifetime = -1;
7cee1bb1 1941
d62a17ae 1942 return CMD_SUCCESS;
7cee1bb1 1943}
1944
718e3744 1945DEFUN (ipv6_nd_managed_config_flag,
1946 ipv6_nd_managed_config_flag_cmd,
1947 "ipv6 nd managed-config-flag",
3e31cded 1948 "Interface IPv6 config commands\n"
718e3744 1949 "Neighbor discovery\n"
1950 "Managed address configuration flag\n")
1951{
d62a17ae 1952 VTY_DECLVAR_CONTEXT(interface, ifp);
1953 struct zebra_if *zif = ifp->info;
718e3744 1954
d62a17ae 1955 zif->rtadv.AdvManagedFlag = 1;
718e3744 1956
d62a17ae 1957 return CMD_SUCCESS;
718e3744 1958}
1959
1960DEFUN (no_ipv6_nd_managed_config_flag,
1961 no_ipv6_nd_managed_config_flag_cmd,
1962 "no ipv6 nd managed-config-flag",
1963 NO_STR
3e31cded 1964 "Interface IPv6 config commands\n"
718e3744 1965 "Neighbor discovery\n"
1966 "Managed address configuration flag\n")
1967{
d62a17ae 1968 VTY_DECLVAR_CONTEXT(interface, ifp);
1969 struct zebra_if *zif = ifp->info;
718e3744 1970
d62a17ae 1971 zif->rtadv.AdvManagedFlag = 0;
718e3744 1972
d62a17ae 1973 return CMD_SUCCESS;
718e3744 1974}
1975
7cee1bb1 1976DEFUN (ipv6_nd_homeagent_config_flag,
1977 ipv6_nd_homeagent_config_flag_cmd,
1978 "ipv6 nd home-agent-config-flag",
1979 "Interface IPv6 config commands\n"
1980 "Neighbor discovery\n"
1981 "Home Agent configuration flag\n")
1982{
d62a17ae 1983 VTY_DECLVAR_CONTEXT(interface, ifp);
1984 struct zebra_if *zif = ifp->info;
7cee1bb1 1985
d62a17ae 1986 zif->rtadv.AdvHomeAgentFlag = 1;
7cee1bb1 1987
d62a17ae 1988 return CMD_SUCCESS;
7cee1bb1 1989}
1990
1991DEFUN (no_ipv6_nd_homeagent_config_flag,
1992 no_ipv6_nd_homeagent_config_flag_cmd,
1993 "no ipv6 nd home-agent-config-flag",
1994 NO_STR
1995 "Interface IPv6 config commands\n"
1996 "Neighbor discovery\n"
1997 "Home Agent configuration flag\n")
1998{
d62a17ae 1999 VTY_DECLVAR_CONTEXT(interface, ifp);
2000 struct zebra_if *zif = ifp->info;
7cee1bb1 2001
d62a17ae 2002 zif->rtadv.AdvHomeAgentFlag = 0;
7cee1bb1 2003
d62a17ae 2004 return CMD_SUCCESS;
7cee1bb1 2005}
2006
2007DEFUN (ipv6_nd_adv_interval_config_option,
2008 ipv6_nd_adv_interval_config_option_cmd,
2009 "ipv6 nd adv-interval-option",
2010 "Interface IPv6 config commands\n"
2011 "Neighbor discovery\n"
2012 "Advertisement Interval Option\n")
2013{
d62a17ae 2014 VTY_DECLVAR_CONTEXT(interface, ifp);
2015 struct zebra_if *zif = ifp->info;
7cee1bb1 2016
d62a17ae 2017 zif->rtadv.AdvIntervalOption = 1;
7cee1bb1 2018
d62a17ae 2019 return CMD_SUCCESS;
7cee1bb1 2020}
2021
2022DEFUN (no_ipv6_nd_adv_interval_config_option,
2023 no_ipv6_nd_adv_interval_config_option_cmd,
2024 "no ipv6 nd adv-interval-option",
2025 NO_STR
2026 "Interface IPv6 config commands\n"
2027 "Neighbor discovery\n"
2028 "Advertisement Interval Option\n")
2029{
d62a17ae 2030 VTY_DECLVAR_CONTEXT(interface, ifp);
2031 struct zebra_if *zif = ifp->info;
7cee1bb1 2032
d62a17ae 2033 zif->rtadv.AdvIntervalOption = 0;
7cee1bb1 2034
d62a17ae 2035 return CMD_SUCCESS;
7cee1bb1 2036}
2037
718e3744 2038DEFUN (ipv6_nd_other_config_flag,
2039 ipv6_nd_other_config_flag_cmd,
2040 "ipv6 nd other-config-flag",
3e31cded 2041 "Interface IPv6 config commands\n"
718e3744 2042 "Neighbor discovery\n"
2043 "Other statefull configuration flag\n")
2044{
d62a17ae 2045 VTY_DECLVAR_CONTEXT(interface, ifp);
2046 struct zebra_if *zif = ifp->info;
718e3744 2047
d62a17ae 2048 zif->rtadv.AdvOtherConfigFlag = 1;
718e3744 2049
d62a17ae 2050 return CMD_SUCCESS;
718e3744 2051}
2052
2053DEFUN (no_ipv6_nd_other_config_flag,
2054 no_ipv6_nd_other_config_flag_cmd,
2055 "no ipv6 nd other-config-flag",
2056 NO_STR
3e31cded 2057 "Interface IPv6 config commands\n"
718e3744 2058 "Neighbor discovery\n"
2059 "Other statefull configuration flag\n")
2060{
d62a17ae 2061 VTY_DECLVAR_CONTEXT(interface, ifp);
2062 struct zebra_if *zif = ifp->info;
718e3744 2063
d62a17ae 2064 zif->rtadv.AdvOtherConfigFlag = 0;
718e3744 2065
d62a17ae 2066 return CMD_SUCCESS;
718e3744 2067}
2068
3e31cded 2069DEFUN (ipv6_nd_prefix,
2070 ipv6_nd_prefix_cmd,
34ccea1e 2071 "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 2072 "Interface IPv6 config commands\n"
718e3744 2073 "Neighbor discovery\n"
2074 "Prefix information\n"
2075 "IPv6 prefix\n"
2076 "Valid lifetime in seconds\n"
3e31cded 2077 "Infinite valid lifetime\n"
718e3744 2078 "Preferred lifetime in seconds\n"
3e31cded 2079 "Infinite preferred lifetime\n"
34ccea1e 2080 "Set Router Address flag\n"
3e31cded 2081 "Do not use prefix for onlink determination\n"
7cee1bb1 2082 "Do not use prefix for autoconfiguration\n"
34ccea1e
QY
2083 "Do not use prefix for autoconfiguration\n"
2084 "Do not use prefix for onlink determination\n")
718e3744 2085{
d62a17ae 2086 /* prelude */
2087 char *prefix = argv[3]->arg;
9d303b37
DL
2088 int lifetimes = (argc > 4) && (argv[4]->type == RANGE_TKN
2089 || strmatch(argv[4]->text, "infinite"));
d62a17ae 2090 int routeropts = lifetimes ? argc > 6 : argc > 4;
2091
2092 int idx_routeropts = routeropts ? (lifetimes ? 6 : 4) : 0;
2093
2094 char *lifetime = NULL, *preflifetime = NULL;
2095 int routeraddr = 0, offlink = 0, noautoconf = 0;
2096 if (lifetimes) {
2097 lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
2098 : argv[4]->text;
2099 preflifetime = argv[5]->type == RANGE_TKN ? argv[5]->arg
2100 : argv[5]->text;
2101 }
2102 if (routeropts) {
2103 routeraddr =
2104 strmatch(argv[idx_routeropts]->text, "router-address");
2105 if (!routeraddr) {
2106 offlink = (argc > idx_routeropts + 1
2107 || strmatch(argv[idx_routeropts]->text,
2108 "off-link"));
2109 noautoconf = (argc > idx_routeropts + 1
2110 || strmatch(argv[idx_routeropts]->text,
2111 "no-autoconfig"));
2112 }
2113 }
2114
2115 /* business */
2116 VTY_DECLVAR_CONTEXT(interface, ifp);
2117 struct zebra_if *zebra_if = ifp->info;
2118 int ret;
2119 struct rtadv_prefix rp;
2120
2121 ret = str2prefix_ipv6(prefix, &rp.prefix);
2122 if (!ret) {
2123 vty_out(vty, "Malformed IPv6 prefix\n");
2124 return CMD_WARNING_CONFIG_FAILED;
2125 }
2126 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
2127 rp.AdvOnLinkFlag = !offlink;
2128 rp.AdvAutonomousFlag = !noautoconf;
2129 rp.AdvRouterAddressFlag = routeraddr;
2130 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
2131 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
2a855763 2132 rp.AdvPrefixCreate = PREFIX_SRC_MANUAL;
d62a17ae 2133
2134 if (lifetimes) {
2135 rp.AdvValidLifetime = strmatch(lifetime, "infinite")
2136 ? UINT32_MAX
2137 : strtoll(lifetime, NULL, 10);
2138 rp.AdvPreferredLifetime =
2139 strmatch(preflifetime, "infinite")
2140 ? UINT32_MAX
2141 : strtoll(preflifetime, NULL, 10);
2142 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) {
2143 vty_out(vty, "Invalid preferred lifetime\n");
2144 return CMD_WARNING_CONFIG_FAILED;
2145 }
2146 }
2147
2148 rtadv_prefix_set(zebra_if, &rp);
2149
2150 return CMD_SUCCESS;
718e3744 2151}
2152
3e31cded 2153DEFUN (no_ipv6_nd_prefix,
2154 no_ipv6_nd_prefix_cmd,
34ccea1e
QY
2155 "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]>]",
2156 NO_STR
3e31cded 2157 "Interface IPv6 config commands\n"
718e3744 2158 "Neighbor discovery\n"
2159 "Prefix information\n"
34ccea1e
QY
2160 "IPv6 prefix\n"
2161 "Valid lifetime in seconds\n"
2162 "Infinite valid lifetime\n"
2163 "Preferred lifetime in seconds\n"
2164 "Infinite preferred lifetime\n"
2165 "Set Router Address flag\n"
2166 "Do not use prefix for onlink determination\n"
2167 "Do not use prefix for autoconfiguration\n"
2168 "Do not use prefix for autoconfiguration\n"
2169 "Do not use prefix for onlink determination\n")
718e3744 2170{
d62a17ae 2171 VTY_DECLVAR_CONTEXT(interface, ifp);
2172 struct zebra_if *zebra_if = ifp->info;
2173 int ret;
2174 struct rtadv_prefix rp;
2175 char *prefix = argv[4]->arg;
2176
2177 ret = str2prefix_ipv6(prefix, &rp.prefix);
2178 if (!ret) {
2179 vty_out(vty, "Malformed IPv6 prefix\n");
2180 return CMD_WARNING_CONFIG_FAILED;
2181 }
2182 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
2a855763 2183 rp.AdvPrefixCreate = PREFIX_SRC_MANUAL;
d62a17ae 2184
2185 ret = rtadv_prefix_reset(zebra_if, &rp);
2186 if (!ret) {
2187 vty_out(vty, "Non-existant IPv6 prefix\n");
2188 return CMD_WARNING_CONFIG_FAILED;
2189 }
2190
2191 return CMD_SUCCESS;
718e3744 2192}
b60668d0
CC
2193
2194DEFUN (ipv6_nd_router_preference,
2195 ipv6_nd_router_preference_cmd,
6147e2c6 2196 "ipv6 nd router-preference <high|medium|low>",
b60668d0
CC
2197 "Interface IPv6 config commands\n"
2198 "Neighbor discovery\n"
2199 "Default router preference\n"
2200 "High default router preference\n"
58f1b7cc
DS
2201 "Medium default router preference (default)\n"
2202 "Low default router preference\n")
b60668d0 2203{
d62a17ae 2204 int idx_high_medium_low = 3;
2205 VTY_DECLVAR_CONTEXT(interface, ifp);
2206 struct zebra_if *zif = ifp->info;
2207 int i = 0;
2208
2209 while (0 != rtadv_pref_strs[i]) {
2210 if (strncmp(argv[idx_high_medium_low]->arg, rtadv_pref_strs[i],
2211 1)
2212 == 0) {
2213 zif->rtadv.DefaultPreference = i;
2214 return CMD_SUCCESS;
2215 }
2216 i++;
b60668d0 2217 }
b60668d0 2218
d62a17ae 2219 return CMD_ERR_NO_MATCH;
b60668d0
CC
2220}
2221
2222DEFUN (no_ipv6_nd_router_preference,
2223 no_ipv6_nd_router_preference_cmd,
34ccea1e 2224 "no ipv6 nd router-preference [<high|medium|low>]",
b60668d0
CC
2225 NO_STR
2226 "Interface IPv6 config commands\n"
2227 "Neighbor discovery\n"
34ccea1e
QY
2228 "Default router preference\n"
2229 "High default router preference\n"
2230 "Medium default router preference (default)\n"
2231 "Low default router preference\n")
b60668d0 2232{
d62a17ae 2233 VTY_DECLVAR_CONTEXT(interface, ifp);
2234 struct zebra_if *zif = ifp->info;
b60668d0 2235
d62a17ae 2236 zif->rtadv.DefaultPreference =
2237 RTADV_PREF_MEDIUM; /* Default per RFC4191. */
b60668d0 2238
d62a17ae 2239 return CMD_SUCCESS;
b60668d0
CC
2240}
2241
6ae93c05
DO
2242DEFUN (ipv6_nd_mtu,
2243 ipv6_nd_mtu_cmd,
6147e2c6 2244 "ipv6 nd mtu (1-65535)",
6ae93c05
DO
2245 "Interface IPv6 config commands\n"
2246 "Neighbor discovery\n"
2247 "Advertised MTU\n"
2248 "MTU in bytes\n")
2249{
d62a17ae 2250 int idx_number = 3;
2251 VTY_DECLVAR_CONTEXT(interface, ifp);
2252 struct zebra_if *zif = ifp->info;
2253 zif->rtadv.AdvLinkMTU = strtoul(argv[idx_number]->arg, NULL, 10);
2254 return CMD_SUCCESS;
6ae93c05
DO
2255}
2256
2257DEFUN (no_ipv6_nd_mtu,
2258 no_ipv6_nd_mtu_cmd,
34ccea1e 2259 "no ipv6 nd mtu [(1-65535)]",
6ae93c05
DO
2260 NO_STR
2261 "Interface IPv6 config commands\n"
2262 "Neighbor discovery\n"
34ccea1e
QY
2263 "Advertised MTU\n"
2264 "MTU in bytes\n")
6ae93c05 2265{
d62a17ae 2266 VTY_DECLVAR_CONTEXT(interface, ifp);
2267 struct zebra_if *zif = ifp->info;
2268 zif->rtadv.AdvLinkMTU = 0;
2269 return CMD_SUCCESS;
6ae93c05
DO
2270}
2271
3eb4fbb0
LS
2272static struct rtadv_rdnss *rtadv_rdnss_new(void)
2273{
2274 return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss));
2275}
2276
2277static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss)
2278{
2279 XFREE(MTYPE_RTADV_RDNSS, rdnss);
2280}
2281
2282static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list,
2283 struct rtadv_rdnss *rdnss)
2284{
2285 struct listnode *node;
2286 struct rtadv_rdnss *p;
2287
2288 for (ALL_LIST_ELEMENTS_RO(list, node, p))
2289 if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr))
2290 return p;
2291 return NULL;
2292}
2293
2294static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list,
2295 struct rtadv_rdnss *rdnss)
2296{
2297 struct rtadv_rdnss *p;
2298
2299 p = rtadv_rdnss_lookup(list, rdnss);
2300 if (p)
2301 return p;
2302
2303 p = rtadv_rdnss_new();
2304 memcpy(p, rdnss, sizeof(struct rtadv_rdnss));
2305 listnode_add(list, p);
2306
2307 return p;
2308}
2309
2310static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
2311{
2312 struct rtadv_rdnss *p;
2313
2314 p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss);
2315 p->lifetime = rdnss->lifetime;
2316 p->lifetime_set = rdnss->lifetime_set;
2317}
2318
2319static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
2320{
2321 struct rtadv_rdnss *p;
2322
2323 p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss);
2324 if (p) {
2325 listnode_delete(zif->rtadv.AdvRDNSSList, p);
2326 rtadv_rdnss_free(p);
2327 return 1;
2328 }
2329
2330 return 0;
2331}
2332
2333static struct rtadv_dnssl *rtadv_dnssl_new(void)
2334{
2335 return XCALLOC(MTYPE_RTADV_DNSSL, sizeof(struct rtadv_dnssl));
2336}
2337
2338static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl)
2339{
2340 XFREE(MTYPE_RTADV_DNSSL, dnssl);
2341}
2342
2343static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list,
2344 struct rtadv_dnssl *dnssl)
2345{
2346 struct listnode *node;
2347 struct rtadv_dnssl *p;
2348
2349 for (ALL_LIST_ELEMENTS_RO(list, node, p))
2350 if (!strcasecmp(p->name, dnssl->name))
2351 return p;
2352 return NULL;
2353}
2354
2355static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list,
2356 struct rtadv_dnssl *dnssl)
2357{
2358 struct rtadv_dnssl *p;
2359
2360 p = rtadv_dnssl_lookup(list, dnssl);
2361 if (p)
2362 return p;
2363
2364 p = rtadv_dnssl_new();
2365 memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
2366 listnode_add(list, p);
2367
2368 return p;
2369}
2370
2371static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
2372{
2373 struct rtadv_dnssl *p;
2374
2375 p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl);
2376 memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
2377}
2378
2379static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
2380{
2381 struct rtadv_dnssl *p;
2382
2383 p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl);
2384 if (p) {
2385 listnode_delete(zif->rtadv.AdvDNSSLList, p);
2386 rtadv_dnssl_free(p);
2387 return 1;
2388 }
2389
2390 return 0;
2391}
2392
2393/*
2394 * Convert dotted domain name (with or without trailing root zone dot) to
2395 * sequence of length-prefixed labels, as described in [RFC1035 3.1]. Write up
2396 * to strlen(in) + 2 octets to out.
2397 *
2398 * Returns the number of octets written to out or -1 if in does not constitute
2399 * a valid domain name.
2400 */
2401static int rtadv_dnssl_encode(uint8_t *out, const char *in)
2402{
2403 const char *label_start, *label_end;
2404 size_t outp;
2405
2406 outp = 0;
2407 label_start = in;
2408
2409 while (*label_start) {
2410 size_t label_len;
2411
2412 label_end = strchr(label_start, '.');
2413 if (label_end == NULL)
2414 label_end = label_start + strlen(label_start);
2415
2416 label_len = label_end - label_start;
2417 if (label_len >= 64)
2418 return -1; /* labels must be 63 octets or less */
2419
2420 out[outp++] = (uint8_t)label_len;
2421 memcpy(out + outp, label_start, label_len);
2422 outp += label_len;
2423 label_start += label_len;
2424 if (*label_start == '.')
2425 label_start++;
2426 }
2427
2428 out[outp++] = '\0';
2429 return outp;
2430}
2431
2432DEFUN(ipv6_nd_rdnss,
2433 ipv6_nd_rdnss_cmd,
2434 "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
2435 "Interface IPv6 config commands\n"
2436 "Neighbor discovery\n"
2437 "Recursive DNS server information\n"
2438 "IPv6 address\n"
2439 "Valid lifetime in seconds\n"
2440 "Infinite valid lifetime\n")
2441{
2442 VTY_DECLVAR_CONTEXT(interface, ifp);
2443 struct zebra_if *zif = ifp->info;
844e9180 2444 struct rtadv_rdnss rdnss = {};
3eb4fbb0
LS
2445
2446 if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) {
2447 vty_out(vty, "Malformed IPv6 address\n");
2448 return CMD_WARNING_CONFIG_FAILED;
2449 }
2450 if (argc > 4) {
2451 char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
2452 : argv[4]->text;
2453 rdnss.lifetime = strmatch(lifetime, "infinite")
2454 ? UINT32_MAX
2455 : strtoll(lifetime, NULL, 10);
2456 rdnss.lifetime_set = 1;
2457 }
2458
2459 rtadv_rdnss_set(zif, &rdnss);
2460
2461 return CMD_SUCCESS;
2462}
2463
2464DEFUN(no_ipv6_nd_rdnss,
2465 no_ipv6_nd_rdnss_cmd,
2466 "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
2467 NO_STR
2468 "Interface IPv6 config commands\n"
2469 "Neighbor discovery\n"
2470 "Recursive DNS server information\n"
2471 "IPv6 address\n"
2472 "Valid lifetime in seconds\n"
2473 "Infinite valid lifetime\n")
2474{
2475 VTY_DECLVAR_CONTEXT(interface, ifp);
2476 struct zebra_if *zif = ifp->info;
844e9180 2477 struct rtadv_rdnss rdnss = {};
3eb4fbb0
LS
2478
2479 if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) {
2480 vty_out(vty, "Malformed IPv6 address\n");
2481 return CMD_WARNING_CONFIG_FAILED;
2482 }
2483 if (rtadv_rdnss_reset(zif, &rdnss) != 1) {
2484 vty_out(vty, "Non-existant RDNSS address\n");
2485 return CMD_WARNING_CONFIG_FAILED;
2486 }
2487
2488 return CMD_SUCCESS;
2489}
2490
2491DEFUN(ipv6_nd_dnssl,
2492 ipv6_nd_dnssl_cmd,
2493 "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
2494 "Interface IPv6 config commands\n"
2495 "Neighbor discovery\n"
2496 "DNS search list information\n"
2497 "Domain name suffix\n"
2498 "Valid lifetime in seconds\n"
2499 "Infinite valid lifetime\n")
2500{
2501 VTY_DECLVAR_CONTEXT(interface, ifp);
2502 struct zebra_if *zif = ifp->info;
844e9180 2503 struct rtadv_dnssl dnssl = {};
3eb4fbb0
LS
2504 size_t len;
2505 int ret;
2506
2507 len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name));
2508 if (len == 0 || len >= sizeof(dnssl.name)) {
2509 vty_out(vty, "Malformed DNS search domain\n");
2510 return CMD_WARNING_CONFIG_FAILED;
2511 }
2512 if (dnssl.name[len - 1] == '.') {
2513 /*
2514 * Allow, but don't require, a trailing dot signifying the root
2515 * zone. Canonicalize by cutting it off if present.
2516 */
2517 dnssl.name[len - 1] = '\0';
2518 len--;
2519 }
2520 if (argc > 4) {
2521 char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
2522 : argv[4]->text;
2523 dnssl.lifetime = strmatch(lifetime, "infinite")
2524 ? UINT32_MAX
2525 : strtoll(lifetime, NULL, 10);
2526 dnssl.lifetime_set = 1;
2527 }
2528
2529 ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name);
2530 if (ret < 0) {
2531 vty_out(vty, "Malformed DNS search domain\n");
2532 return CMD_WARNING_CONFIG_FAILED;
2533 }
2534 dnssl.encoded_len = ret;
2535 rtadv_dnssl_set(zif, &dnssl);
2536
2537 return CMD_SUCCESS;
2538}
2539
2540DEFUN(no_ipv6_nd_dnssl,
2541 no_ipv6_nd_dnssl_cmd,
2542 "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
2543 NO_STR
2544 "Interface IPv6 config commands\n"
2545 "Neighbor discovery\n"
2546 "DNS search list information\n"
2547 "Domain name suffix\n"
2548 "Valid lifetime in seconds\n"
2549 "Infinite valid lifetime\n")
2550{
2551 VTY_DECLVAR_CONTEXT(interface, ifp);
2552 struct zebra_if *zif = ifp->info;
844e9180 2553 struct rtadv_dnssl dnssl = {};
3eb4fbb0
LS
2554 size_t len;
2555
2556 len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name));
2557 if (len == 0 || len >= sizeof(dnssl.name)) {
2558 vty_out(vty, "Malformed DNS search domain\n");
2559 return CMD_WARNING_CONFIG_FAILED;
2560 }
2561 if (dnssl.name[len - 1] == '.') {
2562 dnssl.name[len - 1] = '\0';
2563 len--;
2564 }
2565 if (rtadv_dnssl_reset(zif, &dnssl) != 1) {
2566 vty_out(vty, "Non-existant DNS search domain\n");
2567 return CMD_WARNING_CONFIG_FAILED;
2568 }
2569
2570 return CMD_SUCCESS;
2571}
2572
2573
2eb27eec
DL
2574/* Dump interface ND information to vty. */
2575static int nd_dump_vty(struct vty *vty, struct interface *ifp)
2576{
2577 struct zebra_if *zif;
2578 struct rtadvconf *rtadv;
2579 int interval;
2580
2581 zif = (struct zebra_if *)ifp->info;
2582 rtadv = &zif->rtadv;
2583
2584 if (rtadv->AdvSendAdvertisements) {
2585 vty_out(vty,
2586 " ND advertised reachable time is %d milliseconds\n",
2587 rtadv->AdvReachableTime);
2588 vty_out(vty,
b19ac878 2589 " ND advertised retransmit interval is %u milliseconds\n",
2eb27eec 2590 rtadv->AdvRetransTimer);
fae01935
DS
2591 vty_out(vty, " ND advertised hop-count limit is %d hops\n",
2592 rtadv->AdvCurHopLimit);
2eb27eec
DL
2593 vty_out(vty, " ND router advertisements sent: %d rcvd: %d\n",
2594 zif->ra_sent, zif->ra_rcvd);
2595 interval = rtadv->MaxRtrAdvInterval;
2596 if (interval % 1000)
2597 vty_out(vty,
3efd0893 2598 " ND router advertisements are sent every %d milliseconds\n",
2eb27eec
DL
2599 interval);
2600 else
2601 vty_out(vty,
3efd0893 2602 " ND router advertisements are sent every %d seconds\n",
2eb27eec 2603 interval / 1000);
adee8f21
DS
2604 if (!rtadv->UseFastRexmit)
2605 vty_out(vty,
2606 " ND router advertisements do not use fast retransmit\n");
2607
2eb27eec
DL
2608 if (rtadv->AdvDefaultLifetime != -1)
2609 vty_out(vty,
2610 " ND router advertisements live for %d seconds\n",
2611 rtadv->AdvDefaultLifetime);
2612 else
2613 vty_out(vty,
2614 " ND router advertisements lifetime tracks ra-interval\n");
2615 vty_out(vty,
3efd0893 2616 " ND router advertisement default router preference is %s\n",
2eb27eec
DL
2617 rtadv_pref_strs[rtadv->DefaultPreference]);
2618 if (rtadv->AdvManagedFlag)
2619 vty_out(vty,
2620 " Hosts use DHCP to obtain routable addresses.\n");
2621 else
2622 vty_out(vty,
2623 " Hosts use stateless autoconfig for addresses.\n");
2624 if (rtadv->AdvHomeAgentFlag) {
2625 vty_out(vty,
2626 " ND router advertisements with Home Agent flag bit set.\n");
2627 if (rtadv->HomeAgentLifetime != -1)
2628 vty_out(vty,
2629 " Home Agent lifetime is %u seconds\n",
2630 rtadv->HomeAgentLifetime);
2631 else
2632 vty_out(vty,
2633 " Home Agent lifetime tracks ra-lifetime\n");
2634 vty_out(vty, " Home Agent preference is %u\n",
2635 rtadv->HomeAgentPreference);
2636 }
2637 if (rtadv->AdvIntervalOption)
2638 vty_out(vty,
2639 " ND router advertisements with Adv. Interval option.\n");
2640 }
2641 return 0;
2642}
2643
6ae93c05 2644
718e3744 2645/* Write configuration about router advertisement. */
2eb27eec 2646static int rtadv_config_write(struct vty *vty, struct interface *ifp)
718e3744 2647{
d62a17ae 2648 struct zebra_if *zif;
2649 struct listnode *node;
2650 struct rtadv_prefix *rprefix;
3eb4fbb0
LS
2651 struct rtadv_rdnss *rdnss;
2652 struct rtadv_dnssl *dnssl;
d62a17ae 2653 int interval;
2654
2655 zif = ifp->info;
2656
608c8870 2657 if (!if_is_loopback(ifp)) {
3ea48364
DS
2658 if (zif->rtadv.AdvSendAdvertisements
2659 && CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
d62a17ae 2660 vty_out(vty, " no ipv6 nd suppress-ra\n");
2661 }
2662
2663 interval = zif->rtadv.MaxRtrAdvInterval;
3ea48364
DS
2664 if (CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED)) {
2665 if (interval % 1000)
2666 vty_out(vty, " ipv6 nd ra-interval msec %d\n",
2667 interval);
2668 else if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
2669 vty_out(vty, " ipv6 nd ra-interval %d\n",
2670 interval / 1000);
2671 }
d62a17ae 2672
2673 if (zif->rtadv.AdvIntervalOption)
2674 vty_out(vty, " ipv6 nd adv-interval-option\n");
2675
adee8f21
DS
2676 if (!zif->rtadv.UseFastRexmit)
2677 vty_out(vty, " no ipv6 nd ra-fast-retrans\n");
2678
b19ac878
DS
2679 if (zif->rtadv.AdvRetransTimer != 0)
2680 vty_out(vty, " ipv6 nd ra-retrans-interval %u\n",
2681 zif->rtadv.AdvRetransTimer);
2682
fae01935
DS
2683 if (zif->rtadv.AdvCurHopLimit != RTADV_DEFAULT_HOPLIMIT)
2684 vty_out(vty, " ipv6 nd ra-hop-limit %d\n",
2685 zif->rtadv.AdvCurHopLimit);
2686
d62a17ae 2687 if (zif->rtadv.AdvDefaultLifetime != -1)
2688 vty_out(vty, " ipv6 nd ra-lifetime %d\n",
2689 zif->rtadv.AdvDefaultLifetime);
2690
2691 if (zif->rtadv.HomeAgentPreference)
2692 vty_out(vty, " ipv6 nd home-agent-preference %u\n",
2693 zif->rtadv.HomeAgentPreference);
2694
2695 if (zif->rtadv.HomeAgentLifetime != -1)
2696 vty_out(vty, " ipv6 nd home-agent-lifetime %u\n",
2697 zif->rtadv.HomeAgentLifetime);
2698
2699 if (zif->rtadv.AdvHomeAgentFlag)
2700 vty_out(vty, " ipv6 nd home-agent-config-flag\n");
2701
2702 if (zif->rtadv.AdvReachableTime)
2703 vty_out(vty, " ipv6 nd reachable-time %d\n",
2704 zif->rtadv.AdvReachableTime);
2705
2706 if (zif->rtadv.AdvManagedFlag)
2707 vty_out(vty, " ipv6 nd managed-config-flag\n");
2708
2709 if (zif->rtadv.AdvOtherConfigFlag)
2710 vty_out(vty, " ipv6 nd other-config-flag\n");
2711
2712 if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
2713 vty_out(vty, " ipv6 nd router-preference %s\n",
2714 rtadv_pref_strs[zif->rtadv.DefaultPreference]);
2715
2716 if (zif->rtadv.AdvLinkMTU)
2717 vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU);
2718
7ca9c407 2719 frr_each (rtadv_prefixes, zif->rtadv.prefixes, rprefix) {
2a855763
DS
2720 if ((rprefix->AdvPrefixCreate == PREFIX_SRC_MANUAL)
2721 || (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH)) {
2dbe669b 2722 vty_out(vty, " ipv6 nd prefix %pFX", &rprefix->prefix);
2a855763
DS
2723 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME)
2724 || (rprefix->AdvPreferredLifetime
2725 != RTADV_PREFERRED_LIFETIME)) {
2726 if (rprefix->AdvValidLifetime == UINT32_MAX)
2727 vty_out(vty, " infinite");
2728 else
2729 vty_out(vty, " %u",
2730 rprefix->AdvValidLifetime);
2731 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
2732 vty_out(vty, " infinite");
2733 else
2734 vty_out(vty, " %u",
2735 rprefix->AdvPreferredLifetime);
2736 }
2737 if (!rprefix->AdvOnLinkFlag)
2738 vty_out(vty, " off-link");
2739 if (!rprefix->AdvAutonomousFlag)
2740 vty_out(vty, " no-autoconfig");
2741 if (rprefix->AdvRouterAddressFlag)
2742 vty_out(vty, " router-address");
2743 vty_out(vty, "\n");
d62a17ae 2744 }
3e31cded 2745 }
2a855763 2746
3eb4fbb0
LS
2747 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) {
2748 char buf[INET6_ADDRSTRLEN];
2749
2750 vty_out(vty, " ipv6 nd rdnss %s",
2751 inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf)));
2752 if (rdnss->lifetime_set) {
2753 if (rdnss->lifetime == UINT32_MAX)
2754 vty_out(vty, " infinite");
2755 else
2756 vty_out(vty, " %u", rdnss->lifetime);
2757 }
2758 vty_out(vty, "\n");
2759 }
2760 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) {
2761 vty_out(vty, " ipv6 nd dnssl %s", dnssl->name);
2762 if (dnssl->lifetime_set) {
2763 if (dnssl->lifetime == UINT32_MAX)
2764 vty_out(vty, " infinite");
2765 else
2766 vty_out(vty, " %u", dnssl->lifetime);
2767 }
2768 vty_out(vty, "\n");
2769 }
2eb27eec 2770 return 0;
718e3744 2771}
2772
718e3744 2773
df9c8c57 2774static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
718e3744 2775{
7c2ddfb9 2776 struct rtadv *rtadv;
d62a17ae 2777
60077146
DS
2778 if (IS_ZEBRA_DEBUG_EVENT) {
2779 struct vrf *vrf = zvrf->vrf;
2780
2781 zlog_debug("%s(%s) with event: %d and val: %d", __func__,
2782 VRF_LOGNAME(vrf), event, val);
2783 }
2784
7c2ddfb9
SW
2785 rtadv = &zvrf->rtadv;
2786
d62a17ae 2787 switch (event) {
2788 case RTADV_START:
7c2ddfb9 2789 thread_add_read(zrouter.master, rtadv_read, zvrf, rtadv->sock,
d62a17ae 2790 &rtadv->ra_read);
df9c8c57 2791 thread_add_event(zrouter.master, rtadv_timer, zvrf, 0,
d62a17ae 2792 &rtadv->ra_timer);
2793 break;
2794 case RTADV_STOP:
311c15ee
DS
2795 THREAD_OFF(rtadv->ra_timer);
2796 THREAD_OFF(rtadv->ra_read);
d62a17ae 2797 break;
2798 case RTADV_TIMER:
df9c8c57 2799 thread_add_timer(zrouter.master, rtadv_timer, zvrf, val,
d62a17ae 2800 &rtadv->ra_timer);
2801 break;
2802 case RTADV_TIMER_MSEC:
df9c8c57 2803 thread_add_timer_msec(zrouter.master, rtadv_timer, zvrf, val,
d62a17ae 2804 &rtadv->ra_timer);
2805 break;
2806 case RTADV_READ:
7c2ddfb9 2807 thread_add_read(zrouter.master, rtadv_read, zvrf, rtadv->sock,
d62a17ae 2808 &rtadv->ra_read);
2809 break;
2810 default:
2811 break;
718e3744 2812 }
d62a17ae 2813 return;
718e3744 2814}
2815
7ca9c407
DL
2816void rtadv_if_up(struct zebra_if *zif)
2817{
7937058b
DS
2818 struct zebra_vrf *zvrf = rtadv_interface_get_zvrf(zif->ifp);
2819
7ca9c407
DL
2820 /* Enable fast tx of RA if enabled && RA interval is not in msecs */
2821 if (zif->rtadv.AdvSendAdvertisements &&
2822 (zif->rtadv.MaxRtrAdvInterval >= 1000) &&
2823 zif->rtadv.UseFastRexmit) {
2824 zif->rtadv.inFastRexmit = 1;
2825 zif->rtadv.NumFastReXmitsRemain = RTADV_NUM_FAST_REXMITS;
2826 }
7937058b
DS
2827
2828 /*
2829 * startup the state machine, if it hasn't been already
2830 * due to a delayed ifindex on startup ordering
2831 */
2832 if (zif->rtadv.AdvSendAdvertisements)
2833 rtadv_start_interface_events(zvrf, zif);
7ca9c407
DL
2834}
2835
2836void rtadv_if_init(struct zebra_if *zif)
2837{
2838 /* Set default router advertise values. */
2839 struct rtadvconf *rtadv;
2840
2841 rtadv = &zif->rtadv;
2842
2843 rtadv->AdvSendAdvertisements = 0;
2844 rtadv->MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
2845 rtadv->MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
2846 rtadv->AdvIntervalTimer = 0;
2847 rtadv->AdvManagedFlag = 0;
2848 rtadv->AdvOtherConfigFlag = 0;
2849 rtadv->AdvHomeAgentFlag = 0;
2850 rtadv->AdvLinkMTU = 0;
2851 rtadv->AdvReachableTime = 0;
2852 rtadv->AdvRetransTimer = 0;
2853 rtadv->AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT;
2854 memset(&rtadv->lastadvcurhoplimit, 0,
2855 sizeof(rtadv->lastadvcurhoplimit));
2856 memset(&rtadv->lastadvmanagedflag, 0,
2857 sizeof(rtadv->lastadvmanagedflag));
2858 memset(&rtadv->lastadvotherconfigflag, 0,
2859 sizeof(rtadv->lastadvotherconfigflag));
2860 memset(&rtadv->lastadvreachabletime, 0,
2861 sizeof(rtadv->lastadvreachabletime));
2862 memset(&rtadv->lastadvretranstimer, 0,
2863 sizeof(rtadv->lastadvretranstimer));
2864 rtadv->AdvDefaultLifetime = -1; /* derive from MaxRtrAdvInterval */
2865 rtadv->HomeAgentPreference = 0;
2866 rtadv->HomeAgentLifetime = -1; /* derive from AdvDefaultLifetime */
2867 rtadv->AdvIntervalOption = 0;
2868 rtadv->UseFastRexmit = true;
2869 rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
2870
2871 rtadv_prefixes_init(rtadv->prefixes);
2872
2873 rtadv->AdvRDNSSList = list_new();
2874 rtadv->AdvDNSSLList = list_new();
2875}
2876
2877void rtadv_if_fini(struct zebra_if *zif)
2878{
2879 struct rtadvconf *rtadv;
2880 struct rtadv_prefix *rp;
2881
2882 rtadv = &zif->rtadv;
2883
2884 while ((rp = rtadv_prefixes_pop(rtadv->prefixes)))
2885 rtadv_prefix_free(rp);
2886
2887 list_delete(&rtadv->AdvRDNSSList);
2888 list_delete(&rtadv->AdvDNSSLList);
2889}
2890
7c2ddfb9 2891void rtadv_vrf_init(struct zebra_vrf *zvrf)
718e3744 2892{
7c2ddfb9
SW
2893 if (!vrf_is_backend_netns() && (zvrf_id(zvrf) != VRF_DEFAULT))
2894 return;
2895
2896 zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id);
cd80d74f 2897}
718e3744 2898
aab5893a 2899void rtadv_vrf_terminate(struct zebra_vrf *zvrf)
cd80d74f 2900{
7c2ddfb9
SW
2901 if (!vrf_is_backend_netns() && (zvrf_id(zvrf) != VRF_DEFAULT))
2902 return;
2903
df9c8c57
PG
2904 rtadv_event(zvrf, RTADV_STOP, 0);
2905 if (zvrf->rtadv.sock >= 0) {
2906 close(zvrf->rtadv.sock);
2907 zvrf->rtadv.sock = -1;
d62a17ae 2908 }
aab5893a 2909
7c2ddfb9
SW
2910 adv_if_clean(zvrf);
2911 adv_msec_if_clean(zvrf);
aab5893a
DS
2912}
2913
d62a17ae 2914void rtadv_cmd_init(void)
cd80d74f 2915{
954e1a2b
DS
2916 interfaces_configured_for_ra_from_bgp = 0;
2917
2eb27eec
DL
2918 hook_register(zebra_if_extra_info, nd_dump_vty);
2919 hook_register(zebra_if_config_wr, rtadv_config_write);
2920
2a356cee
SW
2921 install_element(VIEW_NODE, &show_ipv6_nd_ra_if_cmd);
2922
adee8f21
DS
2923 install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd);
2924 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_fast_retrans_cmd);
b19ac878
DS
2925 install_element(INTERFACE_NODE, &ipv6_nd_ra_retrans_interval_cmd);
2926 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_retrans_interval_cmd);
fae01935
DS
2927 install_element(INTERFACE_NODE, &ipv6_nd_ra_hop_limit_cmd);
2928 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_hop_limit_cmd);
d62a17ae 2929 install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
2930 install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
2931 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
2932 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
2933 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
2934 install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
2935 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
2936 install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
2937 install_element(INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
2938 install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
2939 install_element(INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
2940 install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
2941 install_element(INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
2942 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
2943 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
2944 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
2945 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
2946 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
2947 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
2948 install_element(INTERFACE_NODE,
2949 &ipv6_nd_adv_interval_config_option_cmd);
2950 install_element(INTERFACE_NODE,
2951 &no_ipv6_nd_adv_interval_config_option_cmd);
2952 install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd);
2953 install_element(INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
2954 install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
2955 install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
2956 install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd);
2957 install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
3eb4fbb0
LS
2958 install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd);
2959 install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd);
2960 install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd);
2961 install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd);
718e3744 2962}
2963
d62a17ae 2964static int if_join_all_router(int sock, struct interface *ifp)
718e3744 2965{
d62a17ae 2966 int ret;
718e3744 2967
d62a17ae 2968 struct ipv6_mreq mreq;
718e3744 2969
6006b807 2970 memset(&mreq, 0, sizeof(mreq));
d62a17ae 2971 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
2972 mreq.ipv6mr_interface = ifp->ifindex;
718e3744 2973
d62a17ae 2974 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq,
0d6f7fd6 2975 sizeof(mreq));
d62a17ae 2976 if (ret < 0)
450971aa 2977 flog_err_sys(EC_LIB_SOCKET,
9df414fe
QY
2978 "%s(%u): Failed to join group, socket %u error %s",
2979 ifp->name, ifp->ifindex, sock,
2980 safe_strerror(errno));
718e3744 2981
096f7609 2982 if (IS_ZEBRA_DEBUG_EVENT)
d62a17ae 2983 zlog_debug(
60077146 2984 "%s(%s:%u): Join All-Routers multicast group, socket %u",
096f7609 2985 ifp->name, ifp->vrf->name, ifp->ifindex, sock);
718e3744 2986
d62a17ae 2987 return 0;
718e3744 2988}
2989
d62a17ae 2990static int if_leave_all_router(int sock, struct interface *ifp)
718e3744 2991{
d62a17ae 2992 int ret;
718e3744 2993
d62a17ae 2994 struct ipv6_mreq mreq;
718e3744 2995
6006b807 2996 memset(&mreq, 0, sizeof(mreq));
d62a17ae 2997 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
2998 mreq.ipv6mr_interface = ifp->ifindex;
718e3744 2999
d62a17ae 3000 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq,
0d6f7fd6 3001 sizeof(mreq));
096f7609 3002 if (ret < 0)
9df414fe 3003 flog_err_sys(
450971aa 3004 EC_LIB_SOCKET,
60077146 3005 "%s(%s:%u): Failed to leave group, socket %u error %s",
096f7609 3006 ifp->name, ifp->vrf->name, ifp->ifindex, sock,
60077146 3007 safe_strerror(errno));
718e3744 3008
096f7609 3009 if (IS_ZEBRA_DEBUG_EVENT)
d62a17ae 3010 zlog_debug(
60077146 3011 "%s(%s:%u): Leave All-Routers multicast group, socket %u",
096f7609
IR
3012 ifp->name, ifp->vrf->name, ifp->ifindex, sock);
3013
d62a17ae 3014 return 0;
718e3744 3015}
3016
954e1a2b
DS
3017bool rtadv_compiled_in(void)
3018{
3019 return true;
3020}
3021
7ca9c407 3022#else /* !HAVE_RTADV */
e748c7a4
DS
3023/*
3024 * If the end user does not have RADV enabled we should
3025 * handle this better
3026 */
3027void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS)
3028{
3029 if (IS_ZEBRA_DEBUG_PACKET)
3030 zlog_debug(
3031 "Received %s command, but ZEBRA is not compiled with Router Advertisements on",
3032 zserv_command_string(hdr->command));
3033
3034 return;
3035}
3036
3037void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS)
3038{
3039 if (IS_ZEBRA_DEBUG_PACKET)
3040 zlog_debug(
3041 "Received %s command, but ZEBRA is not compiled with Router Advertisements on",
3042 zserv_command_string(hdr->command));
3043
3044 return;
3045}
3046
954e1a2b
DS
3047bool rtadv_compiled_in(void)
3048{
3049 return false;
3050}
3051
56c1f7d8 3052#endif /* HAVE_RTADV */
954e1a2b
DS
3053
3054uint32_t rtadv_get_interfaces_configured_from_bgp(void)
3055{
3056 return interfaces_configured_for_ra_from_bgp;
3057}