]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rtadv.c
Merge pull request #12687 from opensourcerouting/build-mkdir-p
[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
d9f11963
DS
588static const char *rtadv_optionalhdr2str(uint8_t opt_type)
589{
590 switch (opt_type) {
591 case ND_OPT_SOURCE_LINKADDR:
592 return "Optional Source Link Address";
593 case ND_OPT_TARGET_LINKADDR:
594 return "Optional Target Link Address";
595 case ND_OPT_PREFIX_INFORMATION:
596 return "Optional Prefix Information";
597 case ND_OPT_REDIRECTED_HEADER:
598 return "Optional Redirected Header";
599 case ND_OPT_MTU:
600 return "Optional MTU";
601 case ND_OPT_RTR_ADV_INTERVAL:
602 return "Optional Advertisement Interval";
603 case ND_OPT_HOME_AGENT_INFO:
604 return "Optional Home Agent Information";
605 }
606
607 return "Unknown Optional Type";
608}
609
71974bf5
DS
610/*
611 * This function processes optional attributes off of
612 * end of a RA packet received. At this point in
613 * time we only care about this in one situation
614 * which is when a interface does not have a LL
615 * v6 address. We still need to be able to install
616 * the mac address for v4 to v6 resolution
617 */
618static void rtadv_process_optional(uint8_t *optional, unsigned int len,
619 struct interface *ifp,
620 struct sockaddr_in6 *addr)
621{
622 char *mac;
623
624 while (len > 0) {
625 struct nd_opt_hdr *opt_hdr = (struct nd_opt_hdr *)optional;
626
627 switch(opt_hdr->nd_opt_type) {
628 case ND_OPT_SOURCE_LINKADDR:
629 mac = (char *)(optional+2);
630 if_nbr_mac_to_ipv4ll_neigh_update(ifp, mac,
631 &addr->sin6_addr, 1);
632 break;
633 default:
d9f11963
DS
634 if (IS_ZEBRA_DEBUG_PACKET)
635 zlog_debug(
636 "%s:Received Packet with optional Header type %s(%u) that is being ignored",
637 __func__,
638 rtadv_optionalhdr2str(
639 opt_hdr->nd_opt_type),
640 opt_hdr->nd_opt_type);
71974bf5
DS
641 break;
642 }
643
644 len -= 8 * opt_hdr->nd_opt_len;
645 optional += 8 * opt_hdr->nd_opt_len;
646 }
647}
648
d7c0a89a 649static void rtadv_process_advert(uint8_t *msg, unsigned int len,
d62a17ae 650 struct interface *ifp,
651 struct sockaddr_in6 *addr)
718e3744 652{
d62a17ae 653 struct nd_router_advert *radvert;
654 char addr_str[INET6_ADDRSTRLEN];
655 struct zebra_if *zif;
656 struct prefix p;
718e3744 657
d62a17ae 658 zif = ifp->info;
a80beece 659
d62a17ae 660 inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
661
662 if (len < sizeof(struct nd_router_advert)) {
096f7609 663 if (IS_ZEBRA_DEBUG_PACKET)
60077146
DS
664 zlog_debug(
665 "%s(%s:%u): Rx RA with invalid length %d from %s",
096f7609 666 ifp->name, ifp->vrf->name, ifp->ifindex, len,
60077146 667 addr_str);
d62a17ae 668 return;
669 }
71974bf5 670
d62a17ae 671 if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
71974bf5
DS
672 rtadv_process_optional(msg + sizeof(struct nd_router_advert),
673 len - sizeof(struct nd_router_advert),
674 ifp, addr);
096f7609 675 if (IS_ZEBRA_DEBUG_PACKET)
60077146
DS
676 zlog_debug(
677 "%s(%s:%u): Rx RA with non-linklocal source address from %s",
096f7609 678 ifp->name, ifp->vrf->name, ifp->ifindex,
60077146 679 addr_str);
d62a17ae 680 return;
681 }
682
683 radvert = (struct nd_router_advert *)msg;
684
637f95bf
DS
685#define SIXHOUR2USEC (int64_t)6 * 60 * 60 * 1000000
686
687 if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit) &&
688 (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit) &&
689 (monotime_since(&zif->rtadv.lastadvcurhoplimit, NULL) >
690 SIXHOUR2USEC ||
691 zif->rtadv.lastadvcurhoplimit.tv_sec == 0)) {
9df414fe 692 flog_warn(
e914ccbe 693 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
694 "%s(%u): Rx RA - our AdvCurHopLimit (%u) doesn't agree with %s (%u)",
695 ifp->name, ifp->ifindex, zif->rtadv.AdvCurHopLimit,
696 addr_str, radvert->nd_ra_curhoplimit);
637f95bf 697 monotime(&zif->rtadv.lastadvcurhoplimit);
d62a17ae 698 }
699
637f95bf
DS
700 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) &&
701 !zif->rtadv.AdvManagedFlag &&
702 (monotime_since(&zif->rtadv.lastadvmanagedflag, NULL) >
703 SIXHOUR2USEC ||
704 zif->rtadv.lastadvmanagedflag.tv_sec == 0)) {
9df414fe 705 flog_warn(
e914ccbe 706 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
707 "%s(%u): Rx RA - our AdvManagedFlag (%u) doesn't agree with %s (%u)",
708 ifp->name, ifp->ifindex, zif->rtadv.AdvManagedFlag,
709 addr_str,
710 !!CHECK_FLAG(radvert->nd_ra_flags_reserved,
711 ND_RA_FLAG_MANAGED));
637f95bf 712 monotime(&zif->rtadv.lastadvmanagedflag);
d62a17ae 713 }
714
637f95bf
DS
715 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) &&
716 !zif->rtadv.AdvOtherConfigFlag &&
717 (monotime_since(&zif->rtadv.lastadvotherconfigflag, NULL) >
718 SIXHOUR2USEC ||
719 zif->rtadv.lastadvotherconfigflag.tv_sec == 0)) {
9df414fe 720 flog_warn(
e914ccbe 721 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
722 "%s(%u): Rx RA - our AdvOtherConfigFlag (%u) doesn't agree with %s (%u)",
723 ifp->name, ifp->ifindex, zif->rtadv.AdvOtherConfigFlag,
724 addr_str,
725 !!CHECK_FLAG(radvert->nd_ra_flags_reserved,
726 ND_RA_FLAG_OTHER));
637f95bf 727 monotime(&zif->rtadv.lastadvotherconfigflag);
d62a17ae 728 }
729
637f95bf
DS
730 if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime) &&
731 (ntohl(radvert->nd_ra_reachable) != zif->rtadv.AdvReachableTime) &&
732 (monotime_since(&zif->rtadv.lastadvreachabletime, NULL) >
733 SIXHOUR2USEC ||
734 zif->rtadv.lastadvreachabletime.tv_sec == 0)) {
9df414fe 735 flog_warn(
e914ccbe 736 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
737 "%s(%u): Rx RA - our AdvReachableTime (%u) doesn't agree with %s (%u)",
738 ifp->name, ifp->ifindex, zif->rtadv.AdvReachableTime,
739 addr_str, ntohl(radvert->nd_ra_reachable));
637f95bf 740 monotime(&zif->rtadv.lastadvreachabletime);
d62a17ae 741 }
742
820a9cad
TA
743 if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer) &&
744 (ntohl(radvert->nd_ra_retransmit) !=
637f95bf
DS
745 (unsigned int)zif->rtadv.AdvRetransTimer) &&
746 (monotime_since(&zif->rtadv.lastadvretranstimer, NULL) >
747 SIXHOUR2USEC ||
748 zif->rtadv.lastadvretranstimer.tv_sec == 0)) {
9df414fe 749 flog_warn(
e914ccbe 750 EC_ZEBRA_RA_PARAM_MISMATCH,
99e66e52
TA
751 "%s(%u): Rx RA - our AdvRetransTimer (%u) doesn't agree with %s (%u)",
752 ifp->name, ifp->ifindex, zif->rtadv.AdvRetransTimer,
753 addr_str, ntohl(radvert->nd_ra_retransmit));
637f95bf 754 monotime(&zif->rtadv.lastadvretranstimer);
d62a17ae 755 }
756
757 /* Create entry for neighbor if not known. */
758 p.family = AF_INET6;
a85297a7 759 IPV6_ADDR_COPY(&p.u.prefix6, &addr->sin6_addr);
f4d81e55 760 p.prefixlen = IPV6_MAX_BITLEN;
d62a17ae 761
762 if (!nbr_connected_check(ifp, &p))
763 nbr_connected_add_ipv6(ifp, &addr->sin6_addr);
718e3744 764}
765
d62a17ae 766
d7c0a89a 767static void rtadv_process_packet(uint8_t *buf, unsigned int len,
d62a17ae 768 ifindex_t ifindex, int hoplimit,
769 struct sockaddr_in6 *from,
df9c8c57 770 struct zebra_vrf *zvrf)
718e3744 771{
d62a17ae 772 struct icmp6_hdr *icmph;
773 struct interface *ifp;
774 struct zebra_if *zif;
775 char addr_str[INET6_ADDRSTRLEN];
776
777 inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN);
778
779 /* Interface search. */
df9c8c57 780 ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
d62a17ae 781 if (ifp == NULL) {
e914ccbe 782 flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
9df414fe 783 "RA/RS received on unknown IF %u from %s", ifindex,
d62a17ae 784 addr_str);
785 return;
786 }
787
096f7609 788 if (IS_ZEBRA_DEBUG_PACKET)
60077146 789 zlog_debug("%s(%s:%u): Rx RA/RS len %d from %s", ifp->name,
096f7609 790 ifp->vrf->name, ifp->ifindex, len, addr_str);
d62a17ae 791
608c8870 792 if (if_is_loopback(ifp))
d62a17ae 793 return;
718e3744 794
d62a17ae 795 /* Check interface configuration. */
796 zif = ifp->info;
797 if (!zif->rtadv.AdvSendAdvertisements)
798 return;
718e3744 799
d62a17ae 800 /* ICMP message length check. */
801 if (len < sizeof(struct icmp6_hdr)) {
60077146
DS
802 zlog_debug(
803 "%s(%s:%u): Rx RA with Invalid ICMPV6 packet length %d",
096f7609 804 ifp->name, ifp->vrf->name, ifp->ifindex, len);
d62a17ae 805 return;
806 }
807
808 icmph = (struct icmp6_hdr *)buf;
718e3744 809
d62a17ae 810 /* ICMP message type check. */
811 if (icmph->icmp6_type != ND_ROUTER_SOLICIT
812 && icmph->icmp6_type != ND_ROUTER_ADVERT) {
60077146 813 zlog_debug("%s(%s:%u): Rx RA - Unwanted ICMPV6 message type %d",
096f7609 814 ifp->name, ifp->vrf->name, ifp->ifindex,
60077146 815 icmph->icmp6_type);
d62a17ae 816 return;
817 }
718e3744 818
d62a17ae 819 /* Hoplimit check. */
820 if (hoplimit >= 0 && hoplimit != 255) {
60077146 821 zlog_debug("%s(%s:%u): Rx RA - Invalid hoplimit %d", ifp->name,
096f7609 822 ifp->vrf->name, ifp->ifindex, hoplimit);
d62a17ae 823 return;
824 }
718e3744 825
d62a17ae 826 /* Check ICMP message type. */
827 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
828 rtadv_process_solicit(ifp);
829 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
830 rtadv_process_advert(buf, len, ifp, from);
718e3744 831
d62a17ae 832 return;
718e3744 833}
834
cc9f21da 835static void rtadv_read(struct thread *thread)
718e3744 836{
d62a17ae 837 int sock;
838 int len;
d7c0a89a 839 uint8_t buf[RTADV_MSG_SIZE];
d62a17ae 840 struct sockaddr_in6 from;
841 ifindex_t ifindex = 0;
842 int hoplimit = -1;
df9c8c57 843 struct zebra_vrf *zvrf = THREAD_ARG(thread);
d62a17ae 844
845 sock = THREAD_FD(thread);
df9c8c57 846 zvrf->rtadv.ra_read = NULL;
d62a17ae 847
848 /* Register myself. */
7c2ddfb9 849 rtadv_event(zvrf, RTADV_READ, 0);
d62a17ae 850
df9c8c57 851 len = rtadv_recv_packet(zvrf, sock, buf, sizeof(buf), &from, &ifindex,
d62a17ae 852 &hoplimit);
853
854 if (len < 0) {
450971aa 855 flog_err_sys(EC_LIB_SOCKET,
9df414fe
QY
856 "RA/RS recv failed, socket %u error %s", sock,
857 safe_strerror(errno));
cc9f21da 858 return;
d62a17ae 859 }
860
df9c8c57 861 rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zvrf);
718e3744 862}
6b0655a2 863
fe533c56 864static int rtadv_make_socket(ns_id_t ns_id)
718e3744 865{
8d2dcc85 866 int sock = -1;
d62a17ae 867 int ret = 0;
868 struct icmp6_filter filter;
e05506b8 869 int error;
d62a17ae 870
0cf6db21 871 frr_with_privs(&zserv_privs) {
d62a17ae 872
01b9e3fd 873 sock = ns_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, ns_id);
e05506b8
DS
874 /*
875 * with privs might set errno too if it fails save
876 * to the side
877 */
878 error = errno;
01b9e3fd 879 }
d62a17ae 880
881 if (sock < 0) {
e05506b8
DS
882 zlog_warn("RTADV socket for ns: %u failure to create: %s(%u)",
883 ns_id, safe_strerror(error), error);
d62a17ae 884 return -1;
885 }
886
887 ret = setsockopt_ipv6_pktinfo(sock, 1);
888 if (ret < 0) {
e05506b8 889 zlog_warn("RTADV failure to set Packet Information");
d62a17ae 890 close(sock);
891 return ret;
892 }
893 ret = setsockopt_ipv6_multicast_loop(sock, 0);
894 if (ret < 0) {
e05506b8 895 zlog_warn("RTADV failure to set multicast Loop detection");
d62a17ae 896 close(sock);
897 return ret;
898 }
899 ret = setsockopt_ipv6_unicast_hops(sock, 255);
900 if (ret < 0) {
e05506b8 901 zlog_warn("RTADV failure to set maximum unicast hops");
d62a17ae 902 close(sock);
903 return ret;
904 }
905 ret = setsockopt_ipv6_multicast_hops(sock, 255);
906 if (ret < 0) {
e05506b8 907 zlog_warn("RTADV failure to set maximum multicast hops");
d62a17ae 908 close(sock);
909 return ret;
910 }
911 ret = setsockopt_ipv6_hoplimit(sock, 1);
912 if (ret < 0) {
e05506b8 913 zlog_warn("RTADV failure to set maximum incoming hop limit");
d62a17ae 914 close(sock);
915 return ret;
916 }
917
918 ICMP6_FILTER_SETBLOCKALL(&filter);
919 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
920 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
921
922 ret = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
923 sizeof(struct icmp6_filter));
924 if (ret < 0) {
925 zlog_info("ICMP6_FILTER set fail: %s", safe_strerror(errno));
44f12f20 926 close(sock);
d62a17ae 927 return ret;
928 }
929
930 return sock;
718e3744 931}
932
7c2ddfb9
SW
933static struct adv_if *adv_if_new(const char *name)
934{
935 struct adv_if *new;
936
937 new = XCALLOC(MTYPE_ADV_IF, sizeof(struct adv_if));
938
939 strlcpy(new->name, name, sizeof(new->name));
940
941 return new;
942}
943
944static void adv_if_free(struct adv_if *adv_if)
945{
946 XFREE(MTYPE_ADV_IF, adv_if);
947}
948
2a356cee 949static bool adv_if_is_empty_internal(const struct adv_if_list_head *adv_if_head)
7c2ddfb9
SW
950{
951 return adv_if_list_count(adv_if_head) ? false : true;
952}
953
954static struct adv_if *adv_if_add_internal(struct adv_if_list_head *adv_if_head,
955 const char *name)
956{
957 struct adv_if adv_if_lookup = {};
958 struct adv_if *adv_if = NULL;
959
960 strlcpy(adv_if_lookup.name, name, sizeof(adv_if_lookup.name));
961 adv_if = adv_if_list_find(adv_if_head, &adv_if_lookup);
962
963 if (adv_if != NULL)
964 return adv_if;
965
966 adv_if = adv_if_new(adv_if_lookup.name);
967 adv_if_list_add(adv_if_head, adv_if);
968
969 return NULL;
970}
971
972static struct adv_if *adv_if_del_internal(struct adv_if_list_head *adv_if_head,
973 const char *name)
974{
975 struct adv_if adv_if_lookup = {};
976 struct adv_if *adv_if = NULL;
977
978 strlcpy(adv_if_lookup.name, name, sizeof(adv_if_lookup.name));
979 adv_if = adv_if_list_find(adv_if_head, &adv_if_lookup);
980
981 if (adv_if == NULL)
982 return NULL;
983
984 adv_if_list_del(adv_if_head, adv_if);
985
986 return adv_if;
987}
988
989static void adv_if_clean_internal(struct adv_if_list_head *adv_if_head)
990{
991 struct adv_if *node = NULL;
992
993 if (!adv_if_is_empty_internal(adv_if_head)) {
994 frr_each_safe (adv_if_list, adv_if_head, node) {
995 adv_if_list_del(adv_if_head, node);
996 adv_if_free(node);
997 }
998 }
999
1000 adv_if_list_fini(adv_if_head);
1001}
1002
1003
1004/*
1005 * Add to list. On Success, return NULL, otherwise return already existing
1006 * adv_if.
1007 */
1008static struct adv_if *adv_if_add(struct zebra_vrf *zvrf, const char *name)
1009{
1010 struct adv_if *adv_if = NULL;
1011
1012 adv_if = adv_if_add_internal(&zvrf->rtadv.adv_if, name);
1013
1014 if (adv_if != NULL)
1015 return adv_if;
1016
1017 if (IS_ZEBRA_DEBUG_EVENT) {
1018 struct vrf *vrf = zvrf->vrf;
1019
0bcf7589 1020 zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
7c2ddfb9
SW
1021 VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
1022 adv_if_list_count(&zvrf->rtadv.adv_if));
1023 }
1024
1025 return NULL;
1026}
1027
1028/*
1029 * Del from list. On Success, return the adv_if, otherwise return NULL. Caller
1030 * frees.
1031 */
1032static struct adv_if *adv_if_del(struct zebra_vrf *zvrf, const char *name)
1033{
1034 struct adv_if *adv_if = NULL;
1035
1036 adv_if = adv_if_del_internal(&zvrf->rtadv.adv_if, name);
1037
1038 if (adv_if == NULL)
1039 return NULL;
1040
1041 if (IS_ZEBRA_DEBUG_EVENT) {
1042 struct vrf *vrf = zvrf->vrf;
1043
0bcf7589 1044 zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
7c2ddfb9
SW
1045 VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
1046 adv_if_list_count(&zvrf->rtadv.adv_if));
1047 }
1048
1049 return adv_if;
1050}
1051
1052/*
1053 * Add to list. On Success, return NULL, otherwise return already existing
1054 * adv_if.
1055 */
1056static struct adv_if *adv_msec_if_add(struct zebra_vrf *zvrf, const char *name)
1057{
1058 struct adv_if *adv_if = NULL;
1059
1060 adv_if = adv_if_add_internal(&zvrf->rtadv.adv_msec_if, name);
1061
1062 if (adv_if != NULL)
1063 return adv_if;
1064
1065 if (IS_ZEBRA_DEBUG_EVENT) {
1066 struct vrf *vrf = zvrf->vrf;
1067
0bcf7589 1068 zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
7c2ddfb9
SW
1069 VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
1070 adv_if_list_count(&zvrf->rtadv.adv_msec_if));
1071 }
1072
1073 return NULL;
1074}
1075
1076/*
1077 * Del from list. On Success, return the adv_if, otherwise return NULL. Caller
1078 * frees.
1079 */
1080static struct adv_if *adv_msec_if_del(struct zebra_vrf *zvrf, const char *name)
1081{
1082 struct adv_if *adv_if = NULL;
1083
1084 adv_if = adv_if_del_internal(&zvrf->rtadv.adv_msec_if, name);
1085
1086 if (adv_if == NULL)
1087 return NULL;
1088
1089 if (IS_ZEBRA_DEBUG_EVENT) {
1090 struct vrf *vrf = zvrf->vrf;
1091
0bcf7589 1092 zlog_debug("%s: %s:%u IF %s count: %zu", __func__,
7c2ddfb9
SW
1093 VRF_LOGNAME(vrf), zvrf_id(zvrf), name,
1094 adv_if_list_count(&zvrf->rtadv.adv_msec_if));
1095 }
1096
1097 return adv_if;
1098}
1099
1100/* Clean adv_if list, called on vrf terminate */
1101static void adv_if_clean(struct zebra_vrf *zvrf)
1102{
1103 if (IS_ZEBRA_DEBUG_EVENT) {
1104 struct vrf *vrf = zvrf->vrf;
1105
0bcf7589 1106 zlog_debug("%s: %s:%u count: %zu -> 0", __func__,
7c2ddfb9
SW
1107 VRF_LOGNAME(vrf), zvrf_id(zvrf),
1108 adv_if_list_count(&zvrf->rtadv.adv_if));
1109 }
1110
1111 adv_if_clean_internal(&zvrf->rtadv.adv_if);
1112}
1113
1114/* Clean adv_msec_if list, called on vrf terminate */
1115static void adv_msec_if_clean(struct zebra_vrf *zvrf)
1116{
1117 if (IS_ZEBRA_DEBUG_EVENT) {
1118 struct vrf *vrf = zvrf->vrf;
1119
0bcf7589 1120 zlog_debug("%s: %s:%u count: %zu -> 0", __func__,
7c2ddfb9
SW
1121 VRF_LOGNAME(vrf), zvrf_id(zvrf),
1122 adv_if_list_count(&zvrf->rtadv.adv_msec_if));
1123 }
1124
1125 adv_if_clean_internal(&zvrf->rtadv.adv_msec_if);
1126}
1127
d62a17ae 1128static struct rtadv_prefix *rtadv_prefix_new(void)
718e3744 1129{
d62a17ae 1130 return XCALLOC(MTYPE_RTADV_PREFIX, sizeof(struct rtadv_prefix));
718e3744 1131}
1132
d62a17ae 1133static void rtadv_prefix_free(struct rtadv_prefix *rtadv_prefix)
718e3744 1134{
d62a17ae 1135 XFREE(MTYPE_RTADV_PREFIX, rtadv_prefix);
1136}
718e3744 1137
7ca9c407 1138static struct rtadv_prefix *rtadv_prefix_get(struct rtadv_prefixes_head *list,
d62a17ae 1139 struct prefix_ipv6 *p)
718e3744 1140{
7ca9c407
DL
1141 struct rtadv_prefix *rprefix, ref;
1142
1143 ref.prefix = *p;
d62a17ae 1144
7ca9c407 1145 rprefix = rtadv_prefixes_find(list, &ref);
d62a17ae 1146 if (rprefix)
1147 return rprefix;
718e3744 1148
d62a17ae 1149 rprefix = rtadv_prefix_new();
1150 memcpy(&rprefix->prefix, p, sizeof(struct prefix_ipv6));
7ca9c407 1151 rtadv_prefixes_add(list, rprefix);
718e3744 1152
d62a17ae 1153 return rprefix;
718e3744 1154}
1155
2a855763
DS
1156static void rtadv_prefix_set_defaults(struct rtadv_prefix *rp)
1157{
1158 rp->AdvAutonomousFlag = 1;
1159 rp->AdvOnLinkFlag = 1;
1160 rp->AdvRouterAddressFlag = 0;
1161 rp->AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
1162 rp->AdvValidLifetime = RTADV_VALID_LIFETIME;
1163}
1164
d62a17ae 1165static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp)
718e3744 1166{
d62a17ae 1167 struct rtadv_prefix *rprefix;
1168
7ca9c407 1169 rprefix = rtadv_prefix_get(zif->rtadv.prefixes, &rp->prefix);
d62a17ae 1170
2a855763
DS
1171 /*
1172 * Set parameters based on where the prefix is created.
1173 * If auto-created based on kernel address addition, set the
1174 * default values. If created from a manual "ipv6 nd prefix"
1175 * command, take the parameters from the manual command. Note
1176 * that if the manual command exists, the default values will
1177 * not overwrite the manual values.
1178 */
1179 if (rp->AdvPrefixCreate == PREFIX_SRC_MANUAL) {
1180 if (rprefix->AdvPrefixCreate == PREFIX_SRC_AUTO)
1181 rprefix->AdvPrefixCreate = PREFIX_SRC_BOTH;
1182 else
1183 rprefix->AdvPrefixCreate = PREFIX_SRC_MANUAL;
1184
1185 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
1186 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
1187 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
1188 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
1189 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
1190 } else if (rp->AdvPrefixCreate == PREFIX_SRC_AUTO) {
1191 if (rprefix->AdvPrefixCreate == PREFIX_SRC_MANUAL)
1192 rprefix->AdvPrefixCreate = PREFIX_SRC_BOTH;
1193 else {
1194 rprefix->AdvPrefixCreate = PREFIX_SRC_AUTO;
1195 rtadv_prefix_set_defaults(rprefix);
1196 }
1197 }
718e3744 1198}
1199
d62a17ae 1200static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp)
718e3744 1201{
d62a17ae 1202 struct rtadv_prefix *rprefix;
1203
7ca9c407 1204 rprefix = rtadv_prefixes_find(zif->rtadv.prefixes, rp);
d62a17ae 1205 if (rprefix != NULL) {
2a855763
DS
1206
1207 /*
1208 * When deleting an address from the list, need to take care
1209 * it wasn't defined both automatically via kernel
1210 * address addition as well as manually by vtysh cli. If both,
1211 * we don't actually delete but may change the parameters
1212 * back to default if a manually defined entry is deleted.
1213 */
1214 if (rp->AdvPrefixCreate == PREFIX_SRC_MANUAL) {
1215 if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) {
1216 rprefix->AdvPrefixCreate = PREFIX_SRC_AUTO;
1217 rtadv_prefix_set_defaults(rprefix);
1218 return 1;
1219 }
1220 } else if (rp->AdvPrefixCreate == PREFIX_SRC_AUTO) {
1221 if (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH) {
1222 rprefix->AdvPrefixCreate = PREFIX_SRC_MANUAL;
1223 return 1;
1224 }
1225 }
1226
7ca9c407 1227 rtadv_prefixes_del(zif->rtadv.prefixes, rprefix);
d62a17ae 1228 rtadv_prefix_free(rprefix);
1229 return 1;
1230 } else
1231 return 0;
718e3744 1232}
1233
2a855763
DS
1234/* Add IPv6 prefixes learned from the kernel to the RA prefix list */
1235void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p)
1236{
1237 struct rtadv_prefix rp;
1238
1239 rp.prefix = *p;
1240 apply_mask_ipv6(&rp.prefix);
1241 rp.AdvPrefixCreate = PREFIX_SRC_AUTO;
1242 rtadv_prefix_set(zif, &rp);
1243}
1244
1245/* Delete IPv6 prefixes removed by the kernel from the RA prefix list */
1246void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p)
1247{
1248 struct rtadv_prefix rp;
1249
1250 rp.prefix = *((struct prefix_ipv6 *)p);
1251 apply_mask_ipv6(&rp.prefix);
1252 rp.AdvPrefixCreate = PREFIX_SRC_AUTO;
1253 rtadv_prefix_reset(zif, &rp);
1254}
1255
7937058b
DS
1256static void rtadv_start_interface_events(struct zebra_vrf *zvrf,
1257 struct zebra_if *zif)
1258{
1259 struct adv_if *adv_if = NULL;
1260
1261 if (zif->ifp->ifindex == IFINDEX_INTERNAL) {
1262 if (IS_ZEBRA_DEBUG_EVENT)
1263 zlog_debug(
1264 "%s(%s) has not configured an ifindex yet, delaying until we have one",
1265 zif->ifp->name, zvrf->vrf->name);
1266 return;
1267 }
1268
1269 adv_if = adv_if_add(zvrf, zif->ifp->name);
1270 if (adv_if != NULL)
1271 return; /* Already added */
1272
1273 if_join_all_router(zvrf->rtadv.sock, zif->ifp);
1274
1275 if (adv_if_list_count(&zvrf->rtadv.adv_if) == 1)
1276 rtadv_event(zvrf, RTADV_START, 0);
1277}
1278
d62a17ae 1279static void ipv6_nd_suppress_ra_set(struct interface *ifp,
57dd8642 1280 enum ipv6_nd_suppress_ra_status status)
b6120505 1281{
d62a17ae 1282 struct zebra_if *zif;
1283 struct zebra_vrf *zvrf;
7c2ddfb9 1284 struct adv_if *adv_if = NULL;
d62a17ae 1285
1286 zif = ifp->info;
7c2ddfb9
SW
1287
1288 zvrf = rtadv_interface_get_zvrf(ifp);
d62a17ae 1289
1290 if (status == RA_SUPPRESS) {
1291 /* RA is currently enabled */
1292 if (zif->rtadv.AdvSendAdvertisements) {
7c2ddfb9 1293 rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_SUPPRESS);
d62a17ae 1294 zif->rtadv.AdvSendAdvertisements = 0;
1295 zif->rtadv.AdvIntervalTimer = 0;
d62a17ae 1296
7c2ddfb9
SW
1297 adv_if = adv_if_del(zvrf, ifp->name);
1298 if (adv_if == NULL)
1299 return; /* Nothing to delete */
1300
1301 adv_if_free(adv_if);
d62a17ae 1302
7c2ddfb9
SW
1303 if_leave_all_router(zvrf->rtadv.sock, ifp);
1304
1305 if (adv_if_list_count(&zvrf->rtadv.adv_if) == 0)
df9c8c57 1306 rtadv_event(zvrf, RTADV_STOP, 0);
d62a17ae 1307 }
1308 } else {
1309 if (!zif->rtadv.AdvSendAdvertisements) {
1310 zif->rtadv.AdvSendAdvertisements = 1;
1311 zif->rtadv.AdvIntervalTimer = 0;
adee8f21
DS
1312 if ((zif->rtadv.MaxRtrAdvInterval >= 1000)
1313 && zif->rtadv.UseFastRexmit) {
1314 /*
1315 * Enable Fast RA only when RA interval is in
1316 * secs and Fast RA retransmit is enabled
1317 */
d62a17ae 1318 zif->rtadv.inFastRexmit = 1;
1319 zif->rtadv.NumFastReXmitsRemain =
1320 RTADV_NUM_FAST_REXMITS;
1321 }
1322
7937058b 1323 rtadv_start_interface_events(zvrf, zif);
d62a17ae 1324 }
1325 }
b6120505
DW
1326}
1327
4a04e5f7 1328/*
1329 * Handle client (BGP) message to enable or disable IPv6 RA on an interface.
1330 * Note that while the client could request RA on an interface on which the
1331 * operator has not enabled RA, RA won't be disabled upon client request
5c81b96a 1332 * if the operator has explicitly enabled RA. The enable request can also
1333 * specify a RA interval (in seconds).
4a04e5f7 1334 */
1002497a 1335static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
4a04e5f7 1336{
d62a17ae 1337 struct stream *s;
ec93aa12 1338 ifindex_t ifindex;
d62a17ae 1339 struct interface *ifp;
1340 struct zebra_if *zif;
bbad0276 1341 uint32_t ra_interval;
d62a17ae 1342
1002497a 1343 s = msg;
d62a17ae 1344
1345 /* Get interface index and RA interval. */
ec93aa12 1346 STREAM_GETL(s, ifindex);
bbad0276 1347 STREAM_GETL(s, ra_interval);
d62a17ae 1348
60077146
DS
1349 if (IS_ZEBRA_DEBUG_EVENT) {
1350 struct vrf *vrf = zvrf->vrf;
1351
1352 zlog_debug("%s:%u: IF %u RA %s from client %s, interval %ums",
1353 VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
1002497a 1354 enable ? "enable" : "disable",
d62a17ae 1355 zebra_route_string(client->proto), ra_interval);
60077146 1356 }
d62a17ae 1357
1358 /* Locate interface and check VRF match. */
df9c8c57 1359 ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
d62a17ae 1360 if (!ifp) {
60077146
DS
1361 struct vrf *vrf = zvrf->vrf;
1362
e914ccbe 1363 flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
60077146
DS
1364 "%s:%u: IF %u RA %s client %s - interface unknown",
1365 VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex,
1366 enable ? "enable" : "disable",
d62a17ae 1367 zebra_route_string(client->proto));
1368 return;
1369 }
096f7609 1370 if (vrf_is_backend_netns() && ifp->vrf->vrf_id != zvrf_id(zvrf)) {
9df414fe 1371 zlog_debug(
60077146 1372 "%s:%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
096f7609 1373 ifp->vrf->name, zvrf_id(zvrf), ifindex,
60077146 1374 enable ? "enable" : "disable",
096f7609 1375 zebra_route_string(client->proto), ifp->vrf->vrf_id);
d62a17ae 1376 return;
1377 }
1378
1379 zif = ifp->info;
1002497a 1380 if (enable) {
954e1a2b
DS
1381 if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1382 interfaces_configured_for_ra_from_bgp++;
1383
3ea48364 1384 SET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
d62a17ae 1385 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
1386 if (ra_interval
40441c3d 1387 && (ra_interval * 1000) < (unsigned int) zif->rtadv.MaxRtrAdvInterval
996c9314
LB
1388 && !CHECK_FLAG(zif->rtadv.ra_configured,
1389 VTY_RA_INTERVAL_CONFIGURED))
d62a17ae 1390 zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000;
1391 } else {
954e1a2b
DS
1392 if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1393 interfaces_configured_for_ra_from_bgp--;
1394
3ea48364
DS
1395 UNSET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
1396 if (!CHECK_FLAG(zif->rtadv.ra_configured,
1397 VTY_RA_INTERVAL_CONFIGURED))
d62a17ae 1398 zif->rtadv.MaxRtrAdvInterval =
1399 RTADV_MAX_RTR_ADV_INTERVAL;
3ea48364 1400 if (!CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
d62a17ae 1401 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
d62a17ae 1402 }
ec93aa12
DS
1403stream_failure:
1404 return;
4a04e5f7 1405}
1406
d7fc0e67
DS
1407/*
1408 * send router lifetime value of zero in RAs on this interface since we're
1409 * ceasing to advertise and want to let our neighbors know.
1410 * RFC 4861 secion 6.2.5
1411 */
1412void rtadv_stop_ra(struct interface *ifp)
1413{
1414 struct zebra_if *zif;
1415 struct zebra_vrf *zvrf;
1416
1417 zif = ifp->info;
7c2ddfb9 1418 zvrf = rtadv_interface_get_zvrf(ifp);
d7fc0e67
DS
1419
1420 if (zif->rtadv.AdvSendAdvertisements)
7c2ddfb9 1421 rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_SUPPRESS);
d7fc0e67
DS
1422}
1423
1424/*
5a7aea85 1425 * Send router lifetime value of zero in RAs on all interfaces since we're
d7fc0e67
DS
1426 * ceasing to advertise globally and want to let all of our neighbors know
1427 * RFC 4861 secion 6.2.5
5a7aea85
DS
1428 *
1429 * Delete all ipv6 global prefixes added to the router advertisement prefix
1430 * lists prior to ceasing.
d7fc0e67
DS
1431 */
1432void rtadv_stop_ra_all(void)
1433{
1434 struct vrf *vrf;
1435 struct interface *ifp;
5a7aea85
DS
1436 struct zebra_if *zif;
1437 struct rtadv_prefix *rprefix;
d7fc0e67
DS
1438
1439 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
5a7aea85
DS
1440 FOR_ALL_INTERFACES (vrf, ifp) {
1441 zif = ifp->info;
1442
7ca9c407
DL
1443 frr_each_safe (rtadv_prefixes, zif->rtadv.prefixes,
1444 rprefix)
5a7aea85
DS
1445 rtadv_prefix_reset(zif, rprefix);
1446
d7fc0e67 1447 rtadv_stop_ra(ifp);
5a7aea85 1448 }
d7fc0e67
DS
1449}
1450
89f4e507
QY
1451void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS)
1452{
1002497a 1453 zebra_interface_radv_set(client, hdr, msg, zvrf, 0);
89f4e507 1454}
89f4e507
QY
1455void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS)
1456{
1002497a 1457 zebra_interface_radv_set(client, hdr, msg, zvrf, 1);
89f4e507
QY
1458}
1459
2a356cee
SW
1460static void show_zvrf_rtadv_adv_if_helper(struct vty *vty,
1461 struct adv_if_list_head *adv_if_head)
1462{
1463 struct adv_if *node = NULL;
1464
1465 if (!adv_if_is_empty_internal(adv_if_head)) {
1466 frr_each (adv_if_list, adv_if_head, node) {
1467 vty_out(vty, " %s\n", node->name);
1468 }
1469 }
1470
1471 vty_out(vty, "\n");
1472}
1473
1474static void show_zvrf_rtadv_helper(struct vty *vty, struct zebra_vrf *zvrf)
1475{
1476 vty_out(vty, "VRF: %s\n", zvrf_name(zvrf));
1477 vty_out(vty, " Interfaces:\n");
1478 show_zvrf_rtadv_adv_if_helper(vty, &zvrf->rtadv.adv_if);
1479
1480 vty_out(vty, " Interfaces(msec):\n");
1481 show_zvrf_rtadv_adv_if_helper(vty, &zvrf->rtadv.adv_msec_if);
1482}
1483
1484DEFPY(show_ipv6_nd_ra_if, show_ipv6_nd_ra_if_cmd,
1485 "show ipv6 nd ra-interfaces [vrf<NAME$vrf_name|all$vrf_all>]",
1486 SHOW_STR IP6_STR
1487 "Neighbor discovery\n"
1488 "Route Advertisement Interfaces\n" VRF_FULL_CMD_HELP_STR)
1489{
1490 struct zebra_vrf *zvrf = NULL;
1491
1492 if (!vrf_is_backend_netns() && (vrf_name || vrf_all)) {
1493 vty_out(vty,
1494 "%% VRF subcommand only applicable for netns-based vrfs.\n");
1495 return CMD_WARNING;
1496 }
1497
1498 if (vrf_all) {
1499 struct vrf *vrf;
1500
1501 RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
1502 struct zebra_vrf *zvrf;
1503
1504 zvrf = vrf->info;
1505 if (!zvrf)
1506 continue;
1507
1508 show_zvrf_rtadv_helper(vty, zvrf);
1509 }
1510
1511 return CMD_SUCCESS;
1512 }
1513
1514 if (vrf_name)
1515 zvrf = zebra_vrf_lookup_by_name(vrf_name);
1516 else
1517 zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
1518
1519 if (!zvrf) {
1520 vty_out(vty, "%% VRF '%s' specified does not exist\n",
1521 vrf_name);
1522 return CMD_WARNING;
1523 }
1524
1525 show_zvrf_rtadv_helper(vty, zvrf);
1526
1527 return CMD_SUCCESS;
1528}
1529
adee8f21
DS
1530DEFUN (ipv6_nd_ra_fast_retrans,
1531 ipv6_nd_ra_fast_retrans_cmd,
1532 "ipv6 nd ra-fast-retrans",
1533 "Interface IPv6 config commands\n"
1534 "Neighbor discovery\n"
1535 "Fast retransmit of RA packets\n")
1536{
1537 VTY_DECLVAR_CONTEXT(interface, ifp);
1538 struct zebra_if *zif = ifp->info;
1539
608c8870 1540 if (if_is_loopback(ifp)) {
adee8f21
DS
1541 vty_out(vty,
1542 "Cannot configure IPv6 Router Advertisements on this interface\n");
1543 return CMD_WARNING_CONFIG_FAILED;
1544 }
1545
1546 zif->rtadv.UseFastRexmit = true;
1547
1548 return CMD_SUCCESS;
1549}
1550
1551DEFUN (no_ipv6_nd_ra_fast_retrans,
1552 no_ipv6_nd_ra_fast_retrans_cmd,
1553 "no ipv6 nd ra-fast-retrans",
1554 NO_STR
1555 "Interface IPv6 config commands\n"
1556 "Neighbor discovery\n"
1557 "Fast retransmit of RA packets\n")
1558{
1559 VTY_DECLVAR_CONTEXT(interface, ifp);
1560 struct zebra_if *zif = ifp->info;
1561
608c8870 1562 if (if_is_loopback(ifp)) {
adee8f21
DS
1563 vty_out(vty,
1564 "Cannot configure IPv6 Router Advertisements on this interface\n");
1565 return CMD_WARNING_CONFIG_FAILED;
1566 }
1567
1568 zif->rtadv.UseFastRexmit = false;
1569
1570 return CMD_SUCCESS;
1571}
1572
fae01935
DS
1573DEFPY (ipv6_nd_ra_hop_limit,
1574 ipv6_nd_ra_hop_limit_cmd,
1575 "ipv6 nd ra-hop-limit (0-255)$hopcount",
1576 "Interface IPv6 config commands\n"
1577 "Neighbor discovery\n"
1578 "Advertisement Hop Limit\n"
1579 "Advertisement Hop Limit in hops (default:64)\n")
1580{
1581 VTY_DECLVAR_CONTEXT(interface, ifp);
1582 struct zebra_if *zif = ifp->info;
1583
608c8870 1584 if (if_is_loopback(ifp)) {
fae01935
DS
1585 vty_out(vty,
1586 "Cannot configure IPv6 Router Advertisements on this interface\n");
1587 return CMD_WARNING_CONFIG_FAILED;
1588 }
1589
1590 zif->rtadv.AdvCurHopLimit = hopcount;
1591
1592 return CMD_SUCCESS;
1593}
1594
1595DEFPY (no_ipv6_nd_ra_hop_limit,
1596 no_ipv6_nd_ra_hop_limit_cmd,
1597 "no ipv6 nd ra-hop-limit [(0-255)]",
1598 NO_STR
1599 "Interface IPv6 config commands\n"
1600 "Neighbor discovery\n"
1601 "Advertisement Hop Limit\n"
1602 "Advertisement Hop Limit in hops\n")
1603{
1604 VTY_DECLVAR_CONTEXT(interface, ifp);
1605 struct zebra_if *zif = ifp->info;
1606
608c8870 1607 if (if_is_loopback(ifp)) {
fae01935
DS
1608 vty_out(vty,
1609 "Cannot configure IPv6 Router Advertisements on this interface\n");
1610 return CMD_WARNING_CONFIG_FAILED;
1611 }
1612
1613 zif->rtadv.AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT;
1614
1615 return CMD_SUCCESS;
1616}
1617
b19ac878
DS
1618DEFPY (ipv6_nd_ra_retrans_interval,
1619 ipv6_nd_ra_retrans_interval_cmd,
1620 "ipv6 nd ra-retrans-interval (0-4294967295)$interval",
1621 "Interface IPv6 config commands\n"
1622 "Neighbor discovery\n"
1623 "Advertisement Retransmit Interval\n"
1624 "Advertisement Retransmit Interval in msec\n")
1625{
1626 VTY_DECLVAR_CONTEXT(interface, ifp);
1627 struct zebra_if *zif = ifp->info;
1628
608c8870 1629 if (if_is_loopback(ifp)) {
b19ac878
DS
1630 vty_out(vty,
1631 "Cannot configure IPv6 Router Advertisements on loopback interface\n");
1632 return CMD_WARNING_CONFIG_FAILED;
1633 }
1634
1635 zif->rtadv.AdvRetransTimer = interval;
1636
1637 return CMD_SUCCESS;
1638}
1639
1640DEFPY (no_ipv6_nd_ra_retrans_interval,
1641 no_ipv6_nd_ra_retrans_interval_cmd,
1642 "no ipv6 nd ra-retrans-interval [(0-4294967295)]",
1643 NO_STR
1644 "Interface IPv6 config commands\n"
1645 "Neighbor discovery\n"
1646 "Advertisement Retransmit Interval\n"
1647 "Advertisement Retransmit Interval in msec\n")
1648{
1649 VTY_DECLVAR_CONTEXT(interface, ifp);
1650 struct zebra_if *zif = ifp->info;
1651
608c8870 1652 if (if_is_loopback(ifp)) {
b19ac878
DS
1653 vty_out(vty,
1654 "Cannot remove IPv6 Router Advertisements on loopback interface\n");
1655 return CMD_WARNING_CONFIG_FAILED;
1656 }
1657
1658 zif->rtadv.AdvRetransTimer = 0;
1659
1660 return CMD_SUCCESS;
1661}
1662
718e3744 1663DEFUN (ipv6_nd_suppress_ra,
1664 ipv6_nd_suppress_ra_cmd,
1665 "ipv6 nd suppress-ra",
3e31cded 1666 "Interface IPv6 config commands\n"
718e3744 1667 "Neighbor discovery\n"
1668 "Suppress Router Advertisement\n")
1669{
d62a17ae 1670 VTY_DECLVAR_CONTEXT(interface, ifp);
1671 struct zebra_if *zif = ifp->info;
1672
608c8870 1673 if (if_is_loopback(ifp)) {
d62a17ae 1674 vty_out(vty,
1675 "Cannot configure IPv6 Router Advertisements on this interface\n");
1676 return CMD_WARNING_CONFIG_FAILED;
1677 }
1678
3ea48364
DS
1679 if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1680 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
1681
1682 UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
d62a17ae 1683 return CMD_SUCCESS;
718e3744 1684}
1685
718e3744 1686DEFUN (no_ipv6_nd_suppress_ra,
1687 no_ipv6_nd_suppress_ra_cmd,
1688 "no ipv6 nd suppress-ra",
1689 NO_STR
3e31cded 1690 "Interface IPv6 config commands\n"
718e3744 1691 "Neighbor discovery\n"
1692 "Suppress Router Advertisement\n")
1693{
d62a17ae 1694 VTY_DECLVAR_CONTEXT(interface, ifp);
1695 struct zebra_if *zif = ifp->info;
1696
608c8870 1697 if (if_is_loopback(ifp)) {
d62a17ae 1698 vty_out(vty,
1699 "Cannot configure IPv6 Router Advertisements on this interface\n");
1700 return CMD_WARNING_CONFIG_FAILED;
1701 }
1702
1703 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
3ea48364 1704 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
d62a17ae 1705 return CMD_SUCCESS;
718e3744 1706}
1707
7cee1bb1 1708DEFUN (ipv6_nd_ra_interval_msec,
1709 ipv6_nd_ra_interval_msec_cmd,
6147e2c6 1710 "ipv6 nd ra-interval msec (70-1800000)",
7cee1bb1 1711 "Interface IPv6 config commands\n"
1712 "Neighbor discovery\n"
1713 "Router Advertisement interval\n"
3a2d747c 1714 "Router Advertisement interval in milliseconds\n"
7cee1bb1 1715 "Router Advertisement interval in milliseconds\n")
1716{
d62a17ae 1717 int idx_number = 4;
1718 VTY_DECLVAR_CONTEXT(interface, ifp);
1719 unsigned interval;
1720 struct zebra_if *zif = ifp->info;
df9c8c57 1721 struct zebra_vrf *zvrf;
7c2ddfb9 1722 struct adv_if *adv_if;
df9c8c57 1723
7c2ddfb9 1724 zvrf = rtadv_interface_get_zvrf(ifp);
d62a17ae 1725
d62a17ae 1726 interval = strtoul(argv[idx_number]->arg, NULL, 10);
1727 if ((zif->rtadv.AdvDefaultLifetime != -1
1728 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) {
1729 vty_out(vty,
1730 "This ra-interval would conflict with configured ra-lifetime!\n");
1731 return CMD_WARNING_CONFIG_FAILED;
1732 }
1733
7c2ddfb9
SW
1734 if (zif->rtadv.MaxRtrAdvInterval % 1000) {
1735 adv_if = adv_msec_if_del(zvrf, ifp->name);
1736 if (adv_if != NULL)
1737 adv_if_free(adv_if);
1738 }
d62a17ae 1739
1740 if (interval % 1000)
7c2ddfb9 1741 (void)adv_msec_if_add(zvrf, ifp->name);
d62a17ae 1742
3ea48364 1743 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
d62a17ae 1744 zif->rtadv.MaxRtrAdvInterval = interval;
1745 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
1746 zif->rtadv.AdvIntervalTimer = 0;
1747
1748 return CMD_SUCCESS;
7cee1bb1 1749}
1750
718e3744 1751DEFUN (ipv6_nd_ra_interval,
1752 ipv6_nd_ra_interval_cmd,
6147e2c6 1753 "ipv6 nd ra-interval (1-1800)",
3e31cded 1754 "Interface IPv6 config commands\n"
718e3744 1755 "Neighbor discovery\n"
1756 "Router Advertisement interval\n"
1757 "Router Advertisement interval in seconds\n")
1758{
d62a17ae 1759 int idx_number = 3;
1760 VTY_DECLVAR_CONTEXT(interface, ifp);
1761 unsigned interval;
1762 struct zebra_if *zif = ifp->info;
df9c8c57 1763 struct zebra_vrf *zvrf;
7c2ddfb9 1764 struct adv_if *adv_if;
df9c8c57 1765
7c2ddfb9 1766 zvrf = rtadv_interface_get_zvrf(ifp);
d62a17ae 1767
d62a17ae 1768 interval = strtoul(argv[idx_number]->arg, NULL, 10);
1769 if ((zif->rtadv.AdvDefaultLifetime != -1
1770 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) {
1771 vty_out(vty,
1772 "This ra-interval would conflict with configured ra-lifetime!\n");
1773 return CMD_WARNING_CONFIG_FAILED;
1774 }
1775
7c2ddfb9
SW
1776 if (zif->rtadv.MaxRtrAdvInterval % 1000) {
1777 adv_if = adv_msec_if_del(zvrf, ifp->name);
1778 if (adv_if != NULL)
1779 adv_if_free(adv_if);
1780 }
d62a17ae 1781
1782 /* convert to milliseconds */
1783 interval = interval * 1000;
1784
3ea48364 1785 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
d62a17ae 1786 zif->rtadv.MaxRtrAdvInterval = interval;
1787 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
1788 zif->rtadv.AdvIntervalTimer = 0;
1789
1790 return CMD_SUCCESS;
718e3744 1791}
1792
1793DEFUN (no_ipv6_nd_ra_interval,
1794 no_ipv6_nd_ra_interval_cmd,
34ccea1e 1795 "no ipv6 nd ra-interval [<(1-1800)|msec (1-1800000)>]",
718e3744 1796 NO_STR
3e31cded 1797 "Interface IPv6 config commands\n"
718e3744 1798 "Neighbor discovery\n"
34ccea1e
QY
1799 "Router Advertisement interval\n"
1800 "Router Advertisement interval in seconds\n"
1801 "Specify millisecond router advertisement interval\n"
1802 "Router Advertisement interval in milliseconds\n")
718e3744 1803{
d62a17ae 1804 VTY_DECLVAR_CONTEXT(interface, ifp);
1805 struct zebra_if *zif = ifp->info;
df9c8c57 1806 struct zebra_vrf *zvrf = NULL;
7c2ddfb9 1807 struct adv_if *adv_if;
df9c8c57 1808
7c2ddfb9 1809 zvrf = rtadv_interface_get_zvrf(ifp);
d62a17ae 1810
7c2ddfb9
SW
1811 if (zif->rtadv.MaxRtrAdvInterval % 1000) {
1812 adv_if = adv_msec_if_del(zvrf, ifp->name);
1813 if (adv_if != NULL)
1814 adv_if_free(adv_if);
1815 }
d62a17ae 1816
3ea48364
DS
1817 UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
1818
1819 if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1820 zif->rtadv.MaxRtrAdvInterval = 10000;
1821 else
1822 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
1823
d62a17ae 1824 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
3ea48364 1825 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
d62a17ae 1826
1827 return CMD_SUCCESS;
718e3744 1828}
1829
1830DEFUN (ipv6_nd_ra_lifetime,
1831 ipv6_nd_ra_lifetime_cmd,
6147e2c6 1832 "ipv6 nd ra-lifetime (0-9000)",
3e31cded 1833 "Interface IPv6 config commands\n"
718e3744 1834 "Neighbor discovery\n"
1835 "Router lifetime\n"
4afa50b3 1836 "Router lifetime in seconds (0 stands for a non-default gw)\n")
718e3744 1837{
d62a17ae 1838 int idx_number = 3;
1839 VTY_DECLVAR_CONTEXT(interface, ifp);
1840 struct zebra_if *zif = ifp->info;
1841 int lifetime;
1842
1843 lifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1844
1845 /* The value to be placed in the Router Lifetime field
1846 * of Router Advertisements sent from the interface,
1847 * in seconds. MUST be either zero or between
1848 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
1849 if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) {
1850 vty_out(vty,
1851 "This ra-lifetime would conflict with configured ra-interval\n");
1852 return CMD_WARNING_CONFIG_FAILED;
1853 }
1854
1855 zif->rtadv.AdvDefaultLifetime = lifetime;
1856
1857 return CMD_SUCCESS;
718e3744 1858}
1859
1860DEFUN (no_ipv6_nd_ra_lifetime,
1861 no_ipv6_nd_ra_lifetime_cmd,
34ccea1e 1862 "no ipv6 nd ra-lifetime [(0-9000)]",
718e3744 1863 NO_STR
3e31cded 1864 "Interface IPv6 config commands\n"
718e3744 1865 "Neighbor discovery\n"
34ccea1e
QY
1866 "Router lifetime\n"
1867 "Router lifetime in seconds (0 stands for a non-default gw)\n")
718e3744 1868{
d62a17ae 1869 VTY_DECLVAR_CONTEXT(interface, ifp);
1870 struct zebra_if *zif = ifp->info;
718e3744 1871
d62a17ae 1872 zif->rtadv.AdvDefaultLifetime = -1;
718e3744 1873
d62a17ae 1874 return CMD_SUCCESS;
718e3744 1875}
1876
1877DEFUN (ipv6_nd_reachable_time,
1878 ipv6_nd_reachable_time_cmd,
6147e2c6 1879 "ipv6 nd reachable-time (1-3600000)",
3e31cded 1880 "Interface IPv6 config commands\n"
718e3744 1881 "Neighbor discovery\n"
1882 "Reachable time\n"
1883 "Reachable time in milliseconds\n")
1884{
d62a17ae 1885 int idx_number = 3;
1886 VTY_DECLVAR_CONTEXT(interface, ifp);
1887 struct zebra_if *zif = ifp->info;
1888 zif->rtadv.AdvReachableTime = strtoul(argv[idx_number]->arg, NULL, 10);
1889 return CMD_SUCCESS;
718e3744 1890}
1891
1892DEFUN (no_ipv6_nd_reachable_time,
1893 no_ipv6_nd_reachable_time_cmd,
34ccea1e 1894 "no ipv6 nd reachable-time [(1-3600000)]",
718e3744 1895 NO_STR
3e31cded 1896 "Interface IPv6 config commands\n"
718e3744 1897 "Neighbor discovery\n"
34ccea1e
QY
1898 "Reachable time\n"
1899 "Reachable time in milliseconds\n")
718e3744 1900{
d62a17ae 1901 VTY_DECLVAR_CONTEXT(interface, ifp);
1902 struct zebra_if *zif = ifp->info;
718e3744 1903
d62a17ae 1904 zif->rtadv.AdvReachableTime = 0;
718e3744 1905
d62a17ae 1906 return CMD_SUCCESS;
718e3744 1907}
1908
7cee1bb1 1909DEFUN (ipv6_nd_homeagent_preference,
1910 ipv6_nd_homeagent_preference_cmd,
6147e2c6 1911 "ipv6 nd home-agent-preference (0-65535)",
7cee1bb1 1912 "Interface IPv6 config commands\n"
1913 "Neighbor discovery\n"
1914 "Home Agent preference\n"
4afa50b3 1915 "preference value (default is 0, least preferred)\n")
7cee1bb1 1916{
d62a17ae 1917 int idx_number = 3;
1918 VTY_DECLVAR_CONTEXT(interface, ifp);
1919 struct zebra_if *zif = ifp->info;
1920 zif->rtadv.HomeAgentPreference =
1921 strtoul(argv[idx_number]->arg, NULL, 10);
1922 return CMD_SUCCESS;
7cee1bb1 1923}
1924
1925DEFUN (no_ipv6_nd_homeagent_preference,
1926 no_ipv6_nd_homeagent_preference_cmd,
34ccea1e 1927 "no ipv6 nd home-agent-preference [(0-65535)]",
7cee1bb1 1928 NO_STR
1929 "Interface IPv6 config commands\n"
1930 "Neighbor discovery\n"
34ccea1e
QY
1931 "Home Agent preference\n"
1932 "preference value (default is 0, least preferred)\n")
7cee1bb1 1933{
d62a17ae 1934 VTY_DECLVAR_CONTEXT(interface, ifp);
1935 struct zebra_if *zif = ifp->info;
7cee1bb1 1936
d62a17ae 1937 zif->rtadv.HomeAgentPreference = 0;
7cee1bb1 1938
d62a17ae 1939 return CMD_SUCCESS;
7cee1bb1 1940}
1941
1942DEFUN (ipv6_nd_homeagent_lifetime,
1943 ipv6_nd_homeagent_lifetime_cmd,
6147e2c6 1944 "ipv6 nd home-agent-lifetime (0-65520)",
7cee1bb1 1945 "Interface IPv6 config commands\n"
1946 "Neighbor discovery\n"
1947 "Home Agent lifetime\n"
4afa50b3 1948 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
7cee1bb1 1949{
d62a17ae 1950 int idx_number = 3;
1951 VTY_DECLVAR_CONTEXT(interface, ifp);
1952 struct zebra_if *zif = ifp->info;
1953 zif->rtadv.HomeAgentLifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1954 return CMD_SUCCESS;
7cee1bb1 1955}
1956
1957DEFUN (no_ipv6_nd_homeagent_lifetime,
1958 no_ipv6_nd_homeagent_lifetime_cmd,
34ccea1e 1959 "no ipv6 nd home-agent-lifetime [(0-65520)]",
7cee1bb1 1960 NO_STR
1961 "Interface IPv6 config commands\n"
1962 "Neighbor discovery\n"
34ccea1e
QY
1963 "Home Agent lifetime\n"
1964 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
7cee1bb1 1965{
d62a17ae 1966 VTY_DECLVAR_CONTEXT(interface, ifp);
1967 struct zebra_if *zif = ifp->info;
7cee1bb1 1968
d62a17ae 1969 zif->rtadv.HomeAgentLifetime = -1;
7cee1bb1 1970
d62a17ae 1971 return CMD_SUCCESS;
7cee1bb1 1972}
1973
718e3744 1974DEFUN (ipv6_nd_managed_config_flag,
1975 ipv6_nd_managed_config_flag_cmd,
1976 "ipv6 nd managed-config-flag",
3e31cded 1977 "Interface IPv6 config commands\n"
718e3744 1978 "Neighbor discovery\n"
1979 "Managed address configuration flag\n")
1980{
d62a17ae 1981 VTY_DECLVAR_CONTEXT(interface, ifp);
1982 struct zebra_if *zif = ifp->info;
718e3744 1983
d62a17ae 1984 zif->rtadv.AdvManagedFlag = 1;
718e3744 1985
d62a17ae 1986 return CMD_SUCCESS;
718e3744 1987}
1988
1989DEFUN (no_ipv6_nd_managed_config_flag,
1990 no_ipv6_nd_managed_config_flag_cmd,
1991 "no ipv6 nd managed-config-flag",
1992 NO_STR
3e31cded 1993 "Interface IPv6 config commands\n"
718e3744 1994 "Neighbor discovery\n"
1995 "Managed address configuration flag\n")
1996{
d62a17ae 1997 VTY_DECLVAR_CONTEXT(interface, ifp);
1998 struct zebra_if *zif = ifp->info;
718e3744 1999
d62a17ae 2000 zif->rtadv.AdvManagedFlag = 0;
718e3744 2001
d62a17ae 2002 return CMD_SUCCESS;
718e3744 2003}
2004
7cee1bb1 2005DEFUN (ipv6_nd_homeagent_config_flag,
2006 ipv6_nd_homeagent_config_flag_cmd,
2007 "ipv6 nd home-agent-config-flag",
2008 "Interface IPv6 config commands\n"
2009 "Neighbor discovery\n"
2010 "Home Agent configuration flag\n")
2011{
d62a17ae 2012 VTY_DECLVAR_CONTEXT(interface, ifp);
2013 struct zebra_if *zif = ifp->info;
7cee1bb1 2014
d62a17ae 2015 zif->rtadv.AdvHomeAgentFlag = 1;
7cee1bb1 2016
d62a17ae 2017 return CMD_SUCCESS;
7cee1bb1 2018}
2019
2020DEFUN (no_ipv6_nd_homeagent_config_flag,
2021 no_ipv6_nd_homeagent_config_flag_cmd,
2022 "no ipv6 nd home-agent-config-flag",
2023 NO_STR
2024 "Interface IPv6 config commands\n"
2025 "Neighbor discovery\n"
2026 "Home Agent configuration flag\n")
2027{
d62a17ae 2028 VTY_DECLVAR_CONTEXT(interface, ifp);
2029 struct zebra_if *zif = ifp->info;
7cee1bb1 2030
d62a17ae 2031 zif->rtadv.AdvHomeAgentFlag = 0;
7cee1bb1 2032
d62a17ae 2033 return CMD_SUCCESS;
7cee1bb1 2034}
2035
2036DEFUN (ipv6_nd_adv_interval_config_option,
2037 ipv6_nd_adv_interval_config_option_cmd,
2038 "ipv6 nd adv-interval-option",
2039 "Interface IPv6 config commands\n"
2040 "Neighbor discovery\n"
2041 "Advertisement Interval Option\n")
2042{
d62a17ae 2043 VTY_DECLVAR_CONTEXT(interface, ifp);
2044 struct zebra_if *zif = ifp->info;
7cee1bb1 2045
d62a17ae 2046 zif->rtadv.AdvIntervalOption = 1;
7cee1bb1 2047
d62a17ae 2048 return CMD_SUCCESS;
7cee1bb1 2049}
2050
2051DEFUN (no_ipv6_nd_adv_interval_config_option,
2052 no_ipv6_nd_adv_interval_config_option_cmd,
2053 "no ipv6 nd adv-interval-option",
2054 NO_STR
2055 "Interface IPv6 config commands\n"
2056 "Neighbor discovery\n"
2057 "Advertisement Interval Option\n")
2058{
d62a17ae 2059 VTY_DECLVAR_CONTEXT(interface, ifp);
2060 struct zebra_if *zif = ifp->info;
7cee1bb1 2061
d62a17ae 2062 zif->rtadv.AdvIntervalOption = 0;
7cee1bb1 2063
d62a17ae 2064 return CMD_SUCCESS;
7cee1bb1 2065}
2066
718e3744 2067DEFUN (ipv6_nd_other_config_flag,
2068 ipv6_nd_other_config_flag_cmd,
2069 "ipv6 nd other-config-flag",
3e31cded 2070 "Interface IPv6 config commands\n"
718e3744 2071 "Neighbor discovery\n"
2072 "Other statefull configuration flag\n")
2073{
d62a17ae 2074 VTY_DECLVAR_CONTEXT(interface, ifp);
2075 struct zebra_if *zif = ifp->info;
718e3744 2076
d62a17ae 2077 zif->rtadv.AdvOtherConfigFlag = 1;
718e3744 2078
d62a17ae 2079 return CMD_SUCCESS;
718e3744 2080}
2081
2082DEFUN (no_ipv6_nd_other_config_flag,
2083 no_ipv6_nd_other_config_flag_cmd,
2084 "no ipv6 nd other-config-flag",
2085 NO_STR
3e31cded 2086 "Interface IPv6 config commands\n"
718e3744 2087 "Neighbor discovery\n"
2088 "Other statefull configuration flag\n")
2089{
d62a17ae 2090 VTY_DECLVAR_CONTEXT(interface, ifp);
2091 struct zebra_if *zif = ifp->info;
718e3744 2092
d62a17ae 2093 zif->rtadv.AdvOtherConfigFlag = 0;
718e3744 2094
d62a17ae 2095 return CMD_SUCCESS;
718e3744 2096}
2097
3e31cded 2098DEFUN (ipv6_nd_prefix,
2099 ipv6_nd_prefix_cmd,
34ccea1e 2100 "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 2101 "Interface IPv6 config commands\n"
718e3744 2102 "Neighbor discovery\n"
2103 "Prefix information\n"
2104 "IPv6 prefix\n"
2105 "Valid lifetime in seconds\n"
3e31cded 2106 "Infinite valid lifetime\n"
718e3744 2107 "Preferred lifetime in seconds\n"
3e31cded 2108 "Infinite preferred lifetime\n"
34ccea1e 2109 "Set Router Address flag\n"
3e31cded 2110 "Do not use prefix for onlink determination\n"
7cee1bb1 2111 "Do not use prefix for autoconfiguration\n"
34ccea1e
QY
2112 "Do not use prefix for autoconfiguration\n"
2113 "Do not use prefix for onlink determination\n")
718e3744 2114{
d62a17ae 2115 /* prelude */
2116 char *prefix = argv[3]->arg;
9d303b37
DL
2117 int lifetimes = (argc > 4) && (argv[4]->type == RANGE_TKN
2118 || strmatch(argv[4]->text, "infinite"));
d62a17ae 2119 int routeropts = lifetimes ? argc > 6 : argc > 4;
2120
2121 int idx_routeropts = routeropts ? (lifetimes ? 6 : 4) : 0;
2122
2123 char *lifetime = NULL, *preflifetime = NULL;
2124 int routeraddr = 0, offlink = 0, noautoconf = 0;
2125 if (lifetimes) {
2126 lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
2127 : argv[4]->text;
2128 preflifetime = argv[5]->type == RANGE_TKN ? argv[5]->arg
2129 : argv[5]->text;
2130 }
2131 if (routeropts) {
2132 routeraddr =
2133 strmatch(argv[idx_routeropts]->text, "router-address");
2134 if (!routeraddr) {
2135 offlink = (argc > idx_routeropts + 1
2136 || strmatch(argv[idx_routeropts]->text,
2137 "off-link"));
2138 noautoconf = (argc > idx_routeropts + 1
2139 || strmatch(argv[idx_routeropts]->text,
2140 "no-autoconfig"));
2141 }
2142 }
2143
2144 /* business */
2145 VTY_DECLVAR_CONTEXT(interface, ifp);
2146 struct zebra_if *zebra_if = ifp->info;
2147 int ret;
2148 struct rtadv_prefix rp;
2149
2150 ret = str2prefix_ipv6(prefix, &rp.prefix);
2151 if (!ret) {
2152 vty_out(vty, "Malformed IPv6 prefix\n");
2153 return CMD_WARNING_CONFIG_FAILED;
2154 }
2155 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
2156 rp.AdvOnLinkFlag = !offlink;
2157 rp.AdvAutonomousFlag = !noautoconf;
2158 rp.AdvRouterAddressFlag = routeraddr;
2159 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
2160 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
2a855763 2161 rp.AdvPrefixCreate = PREFIX_SRC_MANUAL;
d62a17ae 2162
2163 if (lifetimes) {
2164 rp.AdvValidLifetime = strmatch(lifetime, "infinite")
2165 ? UINT32_MAX
2166 : strtoll(lifetime, NULL, 10);
2167 rp.AdvPreferredLifetime =
2168 strmatch(preflifetime, "infinite")
2169 ? UINT32_MAX
2170 : strtoll(preflifetime, NULL, 10);
2171 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) {
2172 vty_out(vty, "Invalid preferred lifetime\n");
2173 return CMD_WARNING_CONFIG_FAILED;
2174 }
2175 }
2176
2177 rtadv_prefix_set(zebra_if, &rp);
2178
2179 return CMD_SUCCESS;
718e3744 2180}
2181
3e31cded 2182DEFUN (no_ipv6_nd_prefix,
2183 no_ipv6_nd_prefix_cmd,
34ccea1e
QY
2184 "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]>]",
2185 NO_STR
3e31cded 2186 "Interface IPv6 config commands\n"
718e3744 2187 "Neighbor discovery\n"
2188 "Prefix information\n"
34ccea1e
QY
2189 "IPv6 prefix\n"
2190 "Valid lifetime in seconds\n"
2191 "Infinite valid lifetime\n"
2192 "Preferred lifetime in seconds\n"
2193 "Infinite preferred lifetime\n"
2194 "Set Router Address flag\n"
2195 "Do not use prefix for onlink determination\n"
2196 "Do not use prefix for autoconfiguration\n"
2197 "Do not use prefix for autoconfiguration\n"
2198 "Do not use prefix for onlink determination\n")
718e3744 2199{
d62a17ae 2200 VTY_DECLVAR_CONTEXT(interface, ifp);
2201 struct zebra_if *zebra_if = ifp->info;
2202 int ret;
2203 struct rtadv_prefix rp;
2204 char *prefix = argv[4]->arg;
2205
2206 ret = str2prefix_ipv6(prefix, &rp.prefix);
2207 if (!ret) {
2208 vty_out(vty, "Malformed IPv6 prefix\n");
2209 return CMD_WARNING_CONFIG_FAILED;
2210 }
2211 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
2a855763 2212 rp.AdvPrefixCreate = PREFIX_SRC_MANUAL;
d62a17ae 2213
2214 ret = rtadv_prefix_reset(zebra_if, &rp);
2215 if (!ret) {
2216 vty_out(vty, "Non-existant IPv6 prefix\n");
2217 return CMD_WARNING_CONFIG_FAILED;
2218 }
2219
2220 return CMD_SUCCESS;
718e3744 2221}
b60668d0
CC
2222
2223DEFUN (ipv6_nd_router_preference,
2224 ipv6_nd_router_preference_cmd,
6147e2c6 2225 "ipv6 nd router-preference <high|medium|low>",
b60668d0
CC
2226 "Interface IPv6 config commands\n"
2227 "Neighbor discovery\n"
2228 "Default router preference\n"
2229 "High default router preference\n"
58f1b7cc
DS
2230 "Medium default router preference (default)\n"
2231 "Low default router preference\n")
b60668d0 2232{
d62a17ae 2233 int idx_high_medium_low = 3;
2234 VTY_DECLVAR_CONTEXT(interface, ifp);
2235 struct zebra_if *zif = ifp->info;
2236 int i = 0;
2237
2238 while (0 != rtadv_pref_strs[i]) {
2239 if (strncmp(argv[idx_high_medium_low]->arg, rtadv_pref_strs[i],
2240 1)
2241 == 0) {
2242 zif->rtadv.DefaultPreference = i;
2243 return CMD_SUCCESS;
2244 }
2245 i++;
b60668d0 2246 }
b60668d0 2247
d62a17ae 2248 return CMD_ERR_NO_MATCH;
b60668d0
CC
2249}
2250
2251DEFUN (no_ipv6_nd_router_preference,
2252 no_ipv6_nd_router_preference_cmd,
34ccea1e 2253 "no ipv6 nd router-preference [<high|medium|low>]",
b60668d0
CC
2254 NO_STR
2255 "Interface IPv6 config commands\n"
2256 "Neighbor discovery\n"
34ccea1e
QY
2257 "Default router preference\n"
2258 "High default router preference\n"
2259 "Medium default router preference (default)\n"
2260 "Low default router preference\n")
b60668d0 2261{
d62a17ae 2262 VTY_DECLVAR_CONTEXT(interface, ifp);
2263 struct zebra_if *zif = ifp->info;
b60668d0 2264
d62a17ae 2265 zif->rtadv.DefaultPreference =
2266 RTADV_PREF_MEDIUM; /* Default per RFC4191. */
b60668d0 2267
d62a17ae 2268 return CMD_SUCCESS;
b60668d0
CC
2269}
2270
6ae93c05
DO
2271DEFUN (ipv6_nd_mtu,
2272 ipv6_nd_mtu_cmd,
6147e2c6 2273 "ipv6 nd mtu (1-65535)",
6ae93c05
DO
2274 "Interface IPv6 config commands\n"
2275 "Neighbor discovery\n"
2276 "Advertised MTU\n"
2277 "MTU in bytes\n")
2278{
d62a17ae 2279 int idx_number = 3;
2280 VTY_DECLVAR_CONTEXT(interface, ifp);
2281 struct zebra_if *zif = ifp->info;
2282 zif->rtadv.AdvLinkMTU = strtoul(argv[idx_number]->arg, NULL, 10);
2283 return CMD_SUCCESS;
6ae93c05
DO
2284}
2285
2286DEFUN (no_ipv6_nd_mtu,
2287 no_ipv6_nd_mtu_cmd,
34ccea1e 2288 "no ipv6 nd mtu [(1-65535)]",
6ae93c05
DO
2289 NO_STR
2290 "Interface IPv6 config commands\n"
2291 "Neighbor discovery\n"
34ccea1e
QY
2292 "Advertised MTU\n"
2293 "MTU in bytes\n")
6ae93c05 2294{
d62a17ae 2295 VTY_DECLVAR_CONTEXT(interface, ifp);
2296 struct zebra_if *zif = ifp->info;
2297 zif->rtadv.AdvLinkMTU = 0;
2298 return CMD_SUCCESS;
6ae93c05
DO
2299}
2300
3eb4fbb0
LS
2301static struct rtadv_rdnss *rtadv_rdnss_new(void)
2302{
2303 return XCALLOC(MTYPE_RTADV_RDNSS, sizeof(struct rtadv_rdnss));
2304}
2305
2306static void rtadv_rdnss_free(struct rtadv_rdnss *rdnss)
2307{
2308 XFREE(MTYPE_RTADV_RDNSS, rdnss);
2309}
2310
2311static struct rtadv_rdnss *rtadv_rdnss_lookup(struct list *list,
2312 struct rtadv_rdnss *rdnss)
2313{
2314 struct listnode *node;
2315 struct rtadv_rdnss *p;
2316
2317 for (ALL_LIST_ELEMENTS_RO(list, node, p))
2318 if (IPV6_ADDR_SAME(&p->addr, &rdnss->addr))
2319 return p;
2320 return NULL;
2321}
2322
2323static struct rtadv_rdnss *rtadv_rdnss_get(struct list *list,
2324 struct rtadv_rdnss *rdnss)
2325{
2326 struct rtadv_rdnss *p;
2327
2328 p = rtadv_rdnss_lookup(list, rdnss);
2329 if (p)
2330 return p;
2331
2332 p = rtadv_rdnss_new();
2333 memcpy(p, rdnss, sizeof(struct rtadv_rdnss));
2334 listnode_add(list, p);
2335
2336 return p;
2337}
2338
2339static void rtadv_rdnss_set(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
2340{
2341 struct rtadv_rdnss *p;
2342
2343 p = rtadv_rdnss_get(zif->rtadv.AdvRDNSSList, rdnss);
2344 p->lifetime = rdnss->lifetime;
2345 p->lifetime_set = rdnss->lifetime_set;
2346}
2347
2348static int rtadv_rdnss_reset(struct zebra_if *zif, struct rtadv_rdnss *rdnss)
2349{
2350 struct rtadv_rdnss *p;
2351
2352 p = rtadv_rdnss_lookup(zif->rtadv.AdvRDNSSList, rdnss);
2353 if (p) {
2354 listnode_delete(zif->rtadv.AdvRDNSSList, p);
2355 rtadv_rdnss_free(p);
2356 return 1;
2357 }
2358
2359 return 0;
2360}
2361
2362static struct rtadv_dnssl *rtadv_dnssl_new(void)
2363{
2364 return XCALLOC(MTYPE_RTADV_DNSSL, sizeof(struct rtadv_dnssl));
2365}
2366
2367static void rtadv_dnssl_free(struct rtadv_dnssl *dnssl)
2368{
2369 XFREE(MTYPE_RTADV_DNSSL, dnssl);
2370}
2371
2372static struct rtadv_dnssl *rtadv_dnssl_lookup(struct list *list,
2373 struct rtadv_dnssl *dnssl)
2374{
2375 struct listnode *node;
2376 struct rtadv_dnssl *p;
2377
2378 for (ALL_LIST_ELEMENTS_RO(list, node, p))
2379 if (!strcasecmp(p->name, dnssl->name))
2380 return p;
2381 return NULL;
2382}
2383
2384static struct rtadv_dnssl *rtadv_dnssl_get(struct list *list,
2385 struct rtadv_dnssl *dnssl)
2386{
2387 struct rtadv_dnssl *p;
2388
2389 p = rtadv_dnssl_lookup(list, dnssl);
2390 if (p)
2391 return p;
2392
2393 p = rtadv_dnssl_new();
2394 memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
2395 listnode_add(list, p);
2396
2397 return p;
2398}
2399
2400static void rtadv_dnssl_set(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
2401{
2402 struct rtadv_dnssl *p;
2403
2404 p = rtadv_dnssl_get(zif->rtadv.AdvDNSSLList, dnssl);
2405 memcpy(p, dnssl, sizeof(struct rtadv_dnssl));
2406}
2407
2408static int rtadv_dnssl_reset(struct zebra_if *zif, struct rtadv_dnssl *dnssl)
2409{
2410 struct rtadv_dnssl *p;
2411
2412 p = rtadv_dnssl_lookup(zif->rtadv.AdvDNSSLList, dnssl);
2413 if (p) {
2414 listnode_delete(zif->rtadv.AdvDNSSLList, p);
2415 rtadv_dnssl_free(p);
2416 return 1;
2417 }
2418
2419 return 0;
2420}
2421
2422/*
2423 * Convert dotted domain name (with or without trailing root zone dot) to
2424 * sequence of length-prefixed labels, as described in [RFC1035 3.1]. Write up
2425 * to strlen(in) + 2 octets to out.
2426 *
2427 * Returns the number of octets written to out or -1 if in does not constitute
2428 * a valid domain name.
2429 */
2430static int rtadv_dnssl_encode(uint8_t *out, const char *in)
2431{
2432 const char *label_start, *label_end;
2433 size_t outp;
2434
2435 outp = 0;
2436 label_start = in;
2437
2438 while (*label_start) {
2439 size_t label_len;
2440
2441 label_end = strchr(label_start, '.');
2442 if (label_end == NULL)
2443 label_end = label_start + strlen(label_start);
2444
2445 label_len = label_end - label_start;
2446 if (label_len >= 64)
2447 return -1; /* labels must be 63 octets or less */
2448
2449 out[outp++] = (uint8_t)label_len;
2450 memcpy(out + outp, label_start, label_len);
2451 outp += label_len;
2452 label_start += label_len;
2453 if (*label_start == '.')
2454 label_start++;
2455 }
2456
2457 out[outp++] = '\0';
2458 return outp;
2459}
2460
2461DEFUN(ipv6_nd_rdnss,
2462 ipv6_nd_rdnss_cmd,
2463 "ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
2464 "Interface IPv6 config commands\n"
2465 "Neighbor discovery\n"
2466 "Recursive DNS server information\n"
2467 "IPv6 address\n"
2468 "Valid lifetime in seconds\n"
2469 "Infinite valid lifetime\n")
2470{
2471 VTY_DECLVAR_CONTEXT(interface, ifp);
2472 struct zebra_if *zif = ifp->info;
844e9180 2473 struct rtadv_rdnss rdnss = {};
3eb4fbb0
LS
2474
2475 if (inet_pton(AF_INET6, argv[3]->arg, &rdnss.addr) != 1) {
2476 vty_out(vty, "Malformed IPv6 address\n");
2477 return CMD_WARNING_CONFIG_FAILED;
2478 }
2479 if (argc > 4) {
2480 char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
2481 : argv[4]->text;
2482 rdnss.lifetime = strmatch(lifetime, "infinite")
2483 ? UINT32_MAX
2484 : strtoll(lifetime, NULL, 10);
2485 rdnss.lifetime_set = 1;
2486 }
2487
2488 rtadv_rdnss_set(zif, &rdnss);
2489
2490 return CMD_SUCCESS;
2491}
2492
2493DEFUN(no_ipv6_nd_rdnss,
2494 no_ipv6_nd_rdnss_cmd,
2495 "no ipv6 nd rdnss X:X::X:X [<(0-4294967295)|infinite>]",
2496 NO_STR
2497 "Interface IPv6 config commands\n"
2498 "Neighbor discovery\n"
2499 "Recursive DNS server information\n"
2500 "IPv6 address\n"
2501 "Valid lifetime in seconds\n"
2502 "Infinite valid lifetime\n")
2503{
2504 VTY_DECLVAR_CONTEXT(interface, ifp);
2505 struct zebra_if *zif = ifp->info;
844e9180 2506 struct rtadv_rdnss rdnss = {};
3eb4fbb0
LS
2507
2508 if (inet_pton(AF_INET6, argv[4]->arg, &rdnss.addr) != 1) {
2509 vty_out(vty, "Malformed IPv6 address\n");
2510 return CMD_WARNING_CONFIG_FAILED;
2511 }
2512 if (rtadv_rdnss_reset(zif, &rdnss) != 1) {
2513 vty_out(vty, "Non-existant RDNSS address\n");
2514 return CMD_WARNING_CONFIG_FAILED;
2515 }
2516
2517 return CMD_SUCCESS;
2518}
2519
2520DEFUN(ipv6_nd_dnssl,
2521 ipv6_nd_dnssl_cmd,
2522 "ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
2523 "Interface IPv6 config commands\n"
2524 "Neighbor discovery\n"
2525 "DNS search list information\n"
2526 "Domain name suffix\n"
2527 "Valid lifetime in seconds\n"
2528 "Infinite valid lifetime\n")
2529{
2530 VTY_DECLVAR_CONTEXT(interface, ifp);
2531 struct zebra_if *zif = ifp->info;
844e9180 2532 struct rtadv_dnssl dnssl = {};
3eb4fbb0
LS
2533 size_t len;
2534 int ret;
2535
2536 len = strlcpy(dnssl.name, argv[3]->arg, sizeof(dnssl.name));
2537 if (len == 0 || len >= sizeof(dnssl.name)) {
2538 vty_out(vty, "Malformed DNS search domain\n");
2539 return CMD_WARNING_CONFIG_FAILED;
2540 }
2541 if (dnssl.name[len - 1] == '.') {
2542 /*
2543 * Allow, but don't require, a trailing dot signifying the root
2544 * zone. Canonicalize by cutting it off if present.
2545 */
2546 dnssl.name[len - 1] = '\0';
2547 len--;
2548 }
2549 if (argc > 4) {
2550 char *lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
2551 : argv[4]->text;
2552 dnssl.lifetime = strmatch(lifetime, "infinite")
2553 ? UINT32_MAX
2554 : strtoll(lifetime, NULL, 10);
2555 dnssl.lifetime_set = 1;
2556 }
2557
2558 ret = rtadv_dnssl_encode(dnssl.encoded_name, dnssl.name);
2559 if (ret < 0) {
2560 vty_out(vty, "Malformed DNS search domain\n");
2561 return CMD_WARNING_CONFIG_FAILED;
2562 }
2563 dnssl.encoded_len = ret;
2564 rtadv_dnssl_set(zif, &dnssl);
2565
2566 return CMD_SUCCESS;
2567}
2568
2569DEFUN(no_ipv6_nd_dnssl,
2570 no_ipv6_nd_dnssl_cmd,
2571 "no ipv6 nd dnssl SUFFIX [<(0-4294967295)|infinite>]",
2572 NO_STR
2573 "Interface IPv6 config commands\n"
2574 "Neighbor discovery\n"
2575 "DNS search list information\n"
2576 "Domain name suffix\n"
2577 "Valid lifetime in seconds\n"
2578 "Infinite valid lifetime\n")
2579{
2580 VTY_DECLVAR_CONTEXT(interface, ifp);
2581 struct zebra_if *zif = ifp->info;
844e9180 2582 struct rtadv_dnssl dnssl = {};
3eb4fbb0
LS
2583 size_t len;
2584
2585 len = strlcpy(dnssl.name, argv[4]->arg, sizeof(dnssl.name));
2586 if (len == 0 || len >= sizeof(dnssl.name)) {
2587 vty_out(vty, "Malformed DNS search domain\n");
2588 return CMD_WARNING_CONFIG_FAILED;
2589 }
2590 if (dnssl.name[len - 1] == '.') {
2591 dnssl.name[len - 1] = '\0';
2592 len--;
2593 }
2594 if (rtadv_dnssl_reset(zif, &dnssl) != 1) {
2595 vty_out(vty, "Non-existant DNS search domain\n");
2596 return CMD_WARNING_CONFIG_FAILED;
2597 }
2598
2599 return CMD_SUCCESS;
2600}
2601
2602
2eb27eec
DL
2603/* Dump interface ND information to vty. */
2604static int nd_dump_vty(struct vty *vty, struct interface *ifp)
2605{
2606 struct zebra_if *zif;
2607 struct rtadvconf *rtadv;
2608 int interval;
2609
2610 zif = (struct zebra_if *)ifp->info;
2611 rtadv = &zif->rtadv;
2612
2613 if (rtadv->AdvSendAdvertisements) {
2614 vty_out(vty,
2615 " ND advertised reachable time is %d milliseconds\n",
2616 rtadv->AdvReachableTime);
2617 vty_out(vty,
b19ac878 2618 " ND advertised retransmit interval is %u milliseconds\n",
2eb27eec 2619 rtadv->AdvRetransTimer);
fae01935
DS
2620 vty_out(vty, " ND advertised hop-count limit is %d hops\n",
2621 rtadv->AdvCurHopLimit);
2eb27eec
DL
2622 vty_out(vty, " ND router advertisements sent: %d rcvd: %d\n",
2623 zif->ra_sent, zif->ra_rcvd);
2624 interval = rtadv->MaxRtrAdvInterval;
2625 if (interval % 1000)
2626 vty_out(vty,
3efd0893 2627 " ND router advertisements are sent every %d milliseconds\n",
2eb27eec
DL
2628 interval);
2629 else
2630 vty_out(vty,
3efd0893 2631 " ND router advertisements are sent every %d seconds\n",
2eb27eec 2632 interval / 1000);
adee8f21
DS
2633 if (!rtadv->UseFastRexmit)
2634 vty_out(vty,
2635 " ND router advertisements do not use fast retransmit\n");
2636
2eb27eec
DL
2637 if (rtadv->AdvDefaultLifetime != -1)
2638 vty_out(vty,
2639 " ND router advertisements live for %d seconds\n",
2640 rtadv->AdvDefaultLifetime);
2641 else
2642 vty_out(vty,
2643 " ND router advertisements lifetime tracks ra-interval\n");
2644 vty_out(vty,
3efd0893 2645 " ND router advertisement default router preference is %s\n",
2eb27eec
DL
2646 rtadv_pref_strs[rtadv->DefaultPreference]);
2647 if (rtadv->AdvManagedFlag)
2648 vty_out(vty,
2649 " Hosts use DHCP to obtain routable addresses.\n");
2650 else
2651 vty_out(vty,
2652 " Hosts use stateless autoconfig for addresses.\n");
2653 if (rtadv->AdvHomeAgentFlag) {
2654 vty_out(vty,
2655 " ND router advertisements with Home Agent flag bit set.\n");
2656 if (rtadv->HomeAgentLifetime != -1)
2657 vty_out(vty,
2658 " Home Agent lifetime is %u seconds\n",
2659 rtadv->HomeAgentLifetime);
2660 else
2661 vty_out(vty,
2662 " Home Agent lifetime tracks ra-lifetime\n");
2663 vty_out(vty, " Home Agent preference is %u\n",
2664 rtadv->HomeAgentPreference);
2665 }
2666 if (rtadv->AdvIntervalOption)
2667 vty_out(vty,
2668 " ND router advertisements with Adv. Interval option.\n");
2669 }
2670 return 0;
2671}
2672
6ae93c05 2673
718e3744 2674/* Write configuration about router advertisement. */
2eb27eec 2675static int rtadv_config_write(struct vty *vty, struct interface *ifp)
718e3744 2676{
d62a17ae 2677 struct zebra_if *zif;
2678 struct listnode *node;
2679 struct rtadv_prefix *rprefix;
3eb4fbb0
LS
2680 struct rtadv_rdnss *rdnss;
2681 struct rtadv_dnssl *dnssl;
d62a17ae 2682 int interval;
2683
2684 zif = ifp->info;
2685
608c8870 2686 if (!if_is_loopback(ifp)) {
3ea48364
DS
2687 if (zif->rtadv.AdvSendAdvertisements
2688 && CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
d62a17ae 2689 vty_out(vty, " no ipv6 nd suppress-ra\n");
2690 }
2691
2692 interval = zif->rtadv.MaxRtrAdvInterval;
3ea48364
DS
2693 if (CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED)) {
2694 if (interval % 1000)
2695 vty_out(vty, " ipv6 nd ra-interval msec %d\n",
2696 interval);
2697 else if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
2698 vty_out(vty, " ipv6 nd ra-interval %d\n",
2699 interval / 1000);
2700 }
d62a17ae 2701
2702 if (zif->rtadv.AdvIntervalOption)
2703 vty_out(vty, " ipv6 nd adv-interval-option\n");
2704
adee8f21
DS
2705 if (!zif->rtadv.UseFastRexmit)
2706 vty_out(vty, " no ipv6 nd ra-fast-retrans\n");
2707
b19ac878
DS
2708 if (zif->rtadv.AdvRetransTimer != 0)
2709 vty_out(vty, " ipv6 nd ra-retrans-interval %u\n",
2710 zif->rtadv.AdvRetransTimer);
2711
fae01935
DS
2712 if (zif->rtadv.AdvCurHopLimit != RTADV_DEFAULT_HOPLIMIT)
2713 vty_out(vty, " ipv6 nd ra-hop-limit %d\n",
2714 zif->rtadv.AdvCurHopLimit);
2715
d62a17ae 2716 if (zif->rtadv.AdvDefaultLifetime != -1)
2717 vty_out(vty, " ipv6 nd ra-lifetime %d\n",
2718 zif->rtadv.AdvDefaultLifetime);
2719
2720 if (zif->rtadv.HomeAgentPreference)
2721 vty_out(vty, " ipv6 nd home-agent-preference %u\n",
2722 zif->rtadv.HomeAgentPreference);
2723
2724 if (zif->rtadv.HomeAgentLifetime != -1)
2725 vty_out(vty, " ipv6 nd home-agent-lifetime %u\n",
2726 zif->rtadv.HomeAgentLifetime);
2727
2728 if (zif->rtadv.AdvHomeAgentFlag)
2729 vty_out(vty, " ipv6 nd home-agent-config-flag\n");
2730
2731 if (zif->rtadv.AdvReachableTime)
2732 vty_out(vty, " ipv6 nd reachable-time %d\n",
2733 zif->rtadv.AdvReachableTime);
2734
2735 if (zif->rtadv.AdvManagedFlag)
2736 vty_out(vty, " ipv6 nd managed-config-flag\n");
2737
2738 if (zif->rtadv.AdvOtherConfigFlag)
2739 vty_out(vty, " ipv6 nd other-config-flag\n");
2740
2741 if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
2742 vty_out(vty, " ipv6 nd router-preference %s\n",
2743 rtadv_pref_strs[zif->rtadv.DefaultPreference]);
2744
2745 if (zif->rtadv.AdvLinkMTU)
2746 vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU);
2747
7ca9c407 2748 frr_each (rtadv_prefixes, zif->rtadv.prefixes, rprefix) {
2a855763
DS
2749 if ((rprefix->AdvPrefixCreate == PREFIX_SRC_MANUAL)
2750 || (rprefix->AdvPrefixCreate == PREFIX_SRC_BOTH)) {
2dbe669b 2751 vty_out(vty, " ipv6 nd prefix %pFX", &rprefix->prefix);
2a855763
DS
2752 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME)
2753 || (rprefix->AdvPreferredLifetime
2754 != RTADV_PREFERRED_LIFETIME)) {
2755 if (rprefix->AdvValidLifetime == UINT32_MAX)
2756 vty_out(vty, " infinite");
2757 else
2758 vty_out(vty, " %u",
2759 rprefix->AdvValidLifetime);
2760 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
2761 vty_out(vty, " infinite");
2762 else
2763 vty_out(vty, " %u",
2764 rprefix->AdvPreferredLifetime);
2765 }
2766 if (!rprefix->AdvOnLinkFlag)
2767 vty_out(vty, " off-link");
2768 if (!rprefix->AdvAutonomousFlag)
2769 vty_out(vty, " no-autoconfig");
2770 if (rprefix->AdvRouterAddressFlag)
2771 vty_out(vty, " router-address");
2772 vty_out(vty, "\n");
d62a17ae 2773 }
3e31cded 2774 }
2a855763 2775
3eb4fbb0
LS
2776 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvRDNSSList, node, rdnss)) {
2777 char buf[INET6_ADDRSTRLEN];
2778
2779 vty_out(vty, " ipv6 nd rdnss %s",
2780 inet_ntop(AF_INET6, &rdnss->addr, buf, sizeof(buf)));
2781 if (rdnss->lifetime_set) {
2782 if (rdnss->lifetime == UINT32_MAX)
2783 vty_out(vty, " infinite");
2784 else
2785 vty_out(vty, " %u", rdnss->lifetime);
2786 }
2787 vty_out(vty, "\n");
2788 }
2789 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvDNSSLList, node, dnssl)) {
2790 vty_out(vty, " ipv6 nd dnssl %s", dnssl->name);
2791 if (dnssl->lifetime_set) {
2792 if (dnssl->lifetime == UINT32_MAX)
2793 vty_out(vty, " infinite");
2794 else
2795 vty_out(vty, " %u", dnssl->lifetime);
2796 }
2797 vty_out(vty, "\n");
2798 }
2eb27eec 2799 return 0;
718e3744 2800}
2801
718e3744 2802
df9c8c57 2803static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
718e3744 2804{
7c2ddfb9 2805 struct rtadv *rtadv;
d62a17ae 2806
60077146
DS
2807 if (IS_ZEBRA_DEBUG_EVENT) {
2808 struct vrf *vrf = zvrf->vrf;
2809
2810 zlog_debug("%s(%s) with event: %d and val: %d", __func__,
2811 VRF_LOGNAME(vrf), event, val);
2812 }
2813
7c2ddfb9
SW
2814 rtadv = &zvrf->rtadv;
2815
d62a17ae 2816 switch (event) {
2817 case RTADV_START:
7c2ddfb9 2818 thread_add_read(zrouter.master, rtadv_read, zvrf, rtadv->sock,
d62a17ae 2819 &rtadv->ra_read);
df9c8c57 2820 thread_add_event(zrouter.master, rtadv_timer, zvrf, 0,
d62a17ae 2821 &rtadv->ra_timer);
2822 break;
2823 case RTADV_STOP:
311c15ee
DS
2824 THREAD_OFF(rtadv->ra_timer);
2825 THREAD_OFF(rtadv->ra_read);
d62a17ae 2826 break;
2827 case RTADV_TIMER:
df9c8c57 2828 thread_add_timer(zrouter.master, rtadv_timer, zvrf, val,
d62a17ae 2829 &rtadv->ra_timer);
2830 break;
2831 case RTADV_TIMER_MSEC:
df9c8c57 2832 thread_add_timer_msec(zrouter.master, rtadv_timer, zvrf, val,
d62a17ae 2833 &rtadv->ra_timer);
2834 break;
2835 case RTADV_READ:
7c2ddfb9 2836 thread_add_read(zrouter.master, rtadv_read, zvrf, rtadv->sock,
d62a17ae 2837 &rtadv->ra_read);
2838 break;
2839 default:
2840 break;
718e3744 2841 }
d62a17ae 2842 return;
718e3744 2843}
2844
7ca9c407
DL
2845void rtadv_if_up(struct zebra_if *zif)
2846{
7937058b
DS
2847 struct zebra_vrf *zvrf = rtadv_interface_get_zvrf(zif->ifp);
2848
7ca9c407
DL
2849 /* Enable fast tx of RA if enabled && RA interval is not in msecs */
2850 if (zif->rtadv.AdvSendAdvertisements &&
2851 (zif->rtadv.MaxRtrAdvInterval >= 1000) &&
2852 zif->rtadv.UseFastRexmit) {
2853 zif->rtadv.inFastRexmit = 1;
2854 zif->rtadv.NumFastReXmitsRemain = RTADV_NUM_FAST_REXMITS;
2855 }
7937058b
DS
2856
2857 /*
2858 * startup the state machine, if it hasn't been already
2859 * due to a delayed ifindex on startup ordering
2860 */
2861 if (zif->rtadv.AdvSendAdvertisements)
2862 rtadv_start_interface_events(zvrf, zif);
7ca9c407
DL
2863}
2864
2865void rtadv_if_init(struct zebra_if *zif)
2866{
2867 /* Set default router advertise values. */
2868 struct rtadvconf *rtadv;
2869
2870 rtadv = &zif->rtadv;
2871
2872 rtadv->AdvSendAdvertisements = 0;
2873 rtadv->MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
2874 rtadv->MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
2875 rtadv->AdvIntervalTimer = 0;
2876 rtadv->AdvManagedFlag = 0;
2877 rtadv->AdvOtherConfigFlag = 0;
2878 rtadv->AdvHomeAgentFlag = 0;
2879 rtadv->AdvLinkMTU = 0;
2880 rtadv->AdvReachableTime = 0;
2881 rtadv->AdvRetransTimer = 0;
2882 rtadv->AdvCurHopLimit = RTADV_DEFAULT_HOPLIMIT;
2883 memset(&rtadv->lastadvcurhoplimit, 0,
2884 sizeof(rtadv->lastadvcurhoplimit));
2885 memset(&rtadv->lastadvmanagedflag, 0,
2886 sizeof(rtadv->lastadvmanagedflag));
2887 memset(&rtadv->lastadvotherconfigflag, 0,
2888 sizeof(rtadv->lastadvotherconfigflag));
2889 memset(&rtadv->lastadvreachabletime, 0,
2890 sizeof(rtadv->lastadvreachabletime));
2891 memset(&rtadv->lastadvretranstimer, 0,
2892 sizeof(rtadv->lastadvretranstimer));
2893 rtadv->AdvDefaultLifetime = -1; /* derive from MaxRtrAdvInterval */
2894 rtadv->HomeAgentPreference = 0;
2895 rtadv->HomeAgentLifetime = -1; /* derive from AdvDefaultLifetime */
2896 rtadv->AdvIntervalOption = 0;
2897 rtadv->UseFastRexmit = true;
2898 rtadv->DefaultPreference = RTADV_PREF_MEDIUM;
2899
2900 rtadv_prefixes_init(rtadv->prefixes);
2901
2902 rtadv->AdvRDNSSList = list_new();
2903 rtadv->AdvDNSSLList = list_new();
2904}
2905
2906void rtadv_if_fini(struct zebra_if *zif)
2907{
2908 struct rtadvconf *rtadv;
2909 struct rtadv_prefix *rp;
2910
2911 rtadv = &zif->rtadv;
2912
2913 while ((rp = rtadv_prefixes_pop(rtadv->prefixes)))
2914 rtadv_prefix_free(rp);
2915
2916 list_delete(&rtadv->AdvRDNSSList);
2917 list_delete(&rtadv->AdvDNSSLList);
2918}
2919
7c2ddfb9 2920void rtadv_vrf_init(struct zebra_vrf *zvrf)
718e3744 2921{
7c2ddfb9
SW
2922 if (!vrf_is_backend_netns() && (zvrf_id(zvrf) != VRF_DEFAULT))
2923 return;
2924
2925 zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id);
cd80d74f 2926}
718e3744 2927
aab5893a 2928void rtadv_vrf_terminate(struct zebra_vrf *zvrf)
cd80d74f 2929{
7c2ddfb9
SW
2930 if (!vrf_is_backend_netns() && (zvrf_id(zvrf) != VRF_DEFAULT))
2931 return;
2932
df9c8c57
PG
2933 rtadv_event(zvrf, RTADV_STOP, 0);
2934 if (zvrf->rtadv.sock >= 0) {
2935 close(zvrf->rtadv.sock);
2936 zvrf->rtadv.sock = -1;
d62a17ae 2937 }
aab5893a 2938
7c2ddfb9
SW
2939 adv_if_clean(zvrf);
2940 adv_msec_if_clean(zvrf);
aab5893a
DS
2941}
2942
d62a17ae 2943void rtadv_cmd_init(void)
cd80d74f 2944{
954e1a2b
DS
2945 interfaces_configured_for_ra_from_bgp = 0;
2946
2eb27eec
DL
2947 hook_register(zebra_if_extra_info, nd_dump_vty);
2948 hook_register(zebra_if_config_wr, rtadv_config_write);
2949
2a356cee
SW
2950 install_element(VIEW_NODE, &show_ipv6_nd_ra_if_cmd);
2951
adee8f21
DS
2952 install_element(INTERFACE_NODE, &ipv6_nd_ra_fast_retrans_cmd);
2953 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_fast_retrans_cmd);
b19ac878
DS
2954 install_element(INTERFACE_NODE, &ipv6_nd_ra_retrans_interval_cmd);
2955 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_retrans_interval_cmd);
fae01935
DS
2956 install_element(INTERFACE_NODE, &ipv6_nd_ra_hop_limit_cmd);
2957 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_hop_limit_cmd);
d62a17ae 2958 install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
2959 install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
2960 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
2961 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
2962 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
2963 install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
2964 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
2965 install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
2966 install_element(INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
2967 install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
2968 install_element(INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
2969 install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
2970 install_element(INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
2971 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
2972 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
2973 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
2974 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
2975 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
2976 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
2977 install_element(INTERFACE_NODE,
2978 &ipv6_nd_adv_interval_config_option_cmd);
2979 install_element(INTERFACE_NODE,
2980 &no_ipv6_nd_adv_interval_config_option_cmd);
2981 install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd);
2982 install_element(INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
2983 install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
2984 install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
2985 install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd);
2986 install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
3eb4fbb0
LS
2987 install_element(INTERFACE_NODE, &ipv6_nd_rdnss_cmd);
2988 install_element(INTERFACE_NODE, &no_ipv6_nd_rdnss_cmd);
2989 install_element(INTERFACE_NODE, &ipv6_nd_dnssl_cmd);
2990 install_element(INTERFACE_NODE, &no_ipv6_nd_dnssl_cmd);
718e3744 2991}
2992
d62a17ae 2993static int if_join_all_router(int sock, struct interface *ifp)
718e3744 2994{
d62a17ae 2995 int ret;
718e3744 2996
d62a17ae 2997 struct ipv6_mreq mreq;
718e3744 2998
6006b807 2999 memset(&mreq, 0, sizeof(mreq));
d62a17ae 3000 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
3001 mreq.ipv6mr_interface = ifp->ifindex;
718e3744 3002
d62a17ae 3003 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq,
0d6f7fd6 3004 sizeof(mreq));
d62a17ae 3005 if (ret < 0)
450971aa 3006 flog_err_sys(EC_LIB_SOCKET,
9df414fe
QY
3007 "%s(%u): Failed to join group, socket %u error %s",
3008 ifp->name, ifp->ifindex, sock,
3009 safe_strerror(errno));
718e3744 3010
096f7609 3011 if (IS_ZEBRA_DEBUG_EVENT)
d62a17ae 3012 zlog_debug(
60077146 3013 "%s(%s:%u): Join All-Routers multicast group, socket %u",
096f7609 3014 ifp->name, ifp->vrf->name, ifp->ifindex, sock);
718e3744 3015
d62a17ae 3016 return 0;
718e3744 3017}
3018
d62a17ae 3019static int if_leave_all_router(int sock, struct interface *ifp)
718e3744 3020{
d62a17ae 3021 int ret;
718e3744 3022
d62a17ae 3023 struct ipv6_mreq mreq;
718e3744 3024
6006b807 3025 memset(&mreq, 0, sizeof(mreq));
d62a17ae 3026 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
3027 mreq.ipv6mr_interface = ifp->ifindex;
718e3744 3028
d62a17ae 3029 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq,
0d6f7fd6 3030 sizeof(mreq));
096f7609 3031 if (ret < 0)
9df414fe 3032 flog_err_sys(
450971aa 3033 EC_LIB_SOCKET,
60077146 3034 "%s(%s:%u): Failed to leave group, socket %u error %s",
096f7609 3035 ifp->name, ifp->vrf->name, ifp->ifindex, sock,
60077146 3036 safe_strerror(errno));
718e3744 3037
096f7609 3038 if (IS_ZEBRA_DEBUG_EVENT)
d62a17ae 3039 zlog_debug(
60077146 3040 "%s(%s:%u): Leave All-Routers multicast group, socket %u",
096f7609
IR
3041 ifp->name, ifp->vrf->name, ifp->ifindex, sock);
3042
d62a17ae 3043 return 0;
718e3744 3044}
3045
954e1a2b
DS
3046bool rtadv_compiled_in(void)
3047{
3048 return true;
3049}
3050
7ca9c407 3051#else /* !HAVE_RTADV */
e748c7a4
DS
3052/*
3053 * If the end user does not have RADV enabled we should
3054 * handle this better
3055 */
3056void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS)
3057{
3058 if (IS_ZEBRA_DEBUG_PACKET)
3059 zlog_debug(
3060 "Received %s command, but ZEBRA is not compiled with Router Advertisements on",
3061 zserv_command_string(hdr->command));
3062
3063 return;
3064}
3065
3066void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS)
3067{
3068 if (IS_ZEBRA_DEBUG_PACKET)
3069 zlog_debug(
3070 "Received %s command, but ZEBRA is not compiled with Router Advertisements on",
3071 zserv_command_string(hdr->command));
3072
3073 return;
3074}
3075
954e1a2b
DS
3076bool rtadv_compiled_in(void)
3077{
3078 return false;
3079}
3080
56c1f7d8 3081#endif /* HAVE_RTADV */
954e1a2b
DS
3082
3083uint32_t rtadv_get_interfaces_configured_from_bgp(void)
3084{
3085 return interfaces_configured_for_ra_from_bgp;
3086}