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