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