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