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