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