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