]> git.proxmox.com Git - mirror_frr.git/blame - zebra/rtadv.c
Merge pull request #3069 from donaldsharp/bgp_nexthop_address
[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
71974bf5
DS
458/*
459 * This function processes optional attributes off of
460 * end of a RA packet received. At this point in
461 * time we only care about this in one situation
462 * which is when a interface does not have a LL
463 * v6 address. We still need to be able to install
464 * the mac address for v4 to v6 resolution
465 */
466static void rtadv_process_optional(uint8_t *optional, unsigned int len,
467 struct interface *ifp,
468 struct sockaddr_in6 *addr)
469{
470 char *mac;
471
472 while (len > 0) {
473 struct nd_opt_hdr *opt_hdr = (struct nd_opt_hdr *)optional;
474
475 switch(opt_hdr->nd_opt_type) {
476 case ND_OPT_SOURCE_LINKADDR:
477 mac = (char *)(optional+2);
478 if_nbr_mac_to_ipv4ll_neigh_update(ifp, mac,
479 &addr->sin6_addr, 1);
480 break;
481 default:
482 break;
483 }
484
485 len -= 8 * opt_hdr->nd_opt_len;
486 optional += 8 * opt_hdr->nd_opt_len;
487 }
488}
489
d7c0a89a 490static void rtadv_process_advert(uint8_t *msg, unsigned int len,
d62a17ae 491 struct interface *ifp,
492 struct sockaddr_in6 *addr)
718e3744 493{
d62a17ae 494 struct nd_router_advert *radvert;
495 char addr_str[INET6_ADDRSTRLEN];
496 struct zebra_if *zif;
497 struct prefix p;
718e3744 498
d62a17ae 499 zif = ifp->info;
a80beece 500
d62a17ae 501 inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN);
502
503 if (len < sizeof(struct nd_router_advert)) {
71974bf5
DS
504 if (IS_ZEBRA_DEBUG_PACKET)
505 zlog_debug("%s(%u): Rx RA with invalid length %d from %s",
506 ifp->name, ifp->ifindex, len, addr_str);
d62a17ae 507 return;
508 }
71974bf5 509
d62a17ae 510 if (!IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
71974bf5
DS
511 rtadv_process_optional(msg + sizeof(struct nd_router_advert),
512 len - sizeof(struct nd_router_advert),
513 ifp, addr);
514 if (IS_ZEBRA_DEBUG_PACKET)
515 zlog_debug("%s(%u): Rx RA with non-linklocal source address from %s",
516 ifp->name, ifp->ifindex, addr_str);
d62a17ae 517 return;
518 }
519
520 radvert = (struct nd_router_advert *)msg;
521
522 if ((radvert->nd_ra_curhoplimit && zif->rtadv.AdvCurHopLimit)
523 && (radvert->nd_ra_curhoplimit != zif->rtadv.AdvCurHopLimit)) {
9df414fe 524 flog_warn(
e914ccbe 525 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 526 "%s(%u): Rx RA - our AdvCurHopLimit doesn't agree with %s",
527 ifp->name, ifp->ifindex, addr_str);
528 }
529
530 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED)
531 && !zif->rtadv.AdvManagedFlag) {
9df414fe 532 flog_warn(
e914ccbe 533 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 534 "%s(%u): Rx RA - our AdvManagedFlag doesn't agree with %s",
535 ifp->name, ifp->ifindex, addr_str);
536 }
537
538 if ((radvert->nd_ra_flags_reserved & ND_RA_FLAG_OTHER)
539 && !zif->rtadv.AdvOtherConfigFlag) {
9df414fe 540 flog_warn(
e914ccbe 541 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 542 "%s(%u): Rx RA - our AdvOtherConfigFlag doesn't agree with %s",
543 ifp->name, ifp->ifindex, addr_str);
544 }
545
546 if ((radvert->nd_ra_reachable && zif->rtadv.AdvReachableTime)
547 && (ntohl(radvert->nd_ra_reachable)
548 != zif->rtadv.AdvReachableTime)) {
9df414fe 549 flog_warn(
e914ccbe 550 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 551 "%s(%u): Rx RA - our AdvReachableTime doesn't agree with %s",
552 ifp->name, ifp->ifindex, addr_str);
553 }
554
555 if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer)
556 && (ntohl(radvert->nd_ra_retransmit)
557 != (unsigned int)zif->rtadv.AdvRetransTimer)) {
9df414fe 558 flog_warn(
e914ccbe 559 EC_ZEBRA_RA_PARAM_MISMATCH,
d62a17ae 560 "%s(%u): Rx RA - our AdvRetransTimer doesn't agree with %s",
561 ifp->name, ifp->ifindex, addr_str);
562 }
563
564 /* Create entry for neighbor if not known. */
565 p.family = AF_INET6;
a85297a7 566 IPV6_ADDR_COPY(&p.u.prefix6, &addr->sin6_addr);
d62a17ae 567 p.prefixlen = IPV6_MAX_PREFIXLEN;
568
569 if (!nbr_connected_check(ifp, &p))
570 nbr_connected_add_ipv6(ifp, &addr->sin6_addr);
718e3744 571}
572
d62a17ae 573
d7c0a89a 574static void rtadv_process_packet(uint8_t *buf, unsigned int len,
d62a17ae 575 ifindex_t ifindex, int hoplimit,
576 struct sockaddr_in6 *from,
577 struct zebra_ns *zns)
718e3744 578{
d62a17ae 579 struct icmp6_hdr *icmph;
580 struct interface *ifp;
581 struct zebra_if *zif;
582 char addr_str[INET6_ADDRSTRLEN];
583
584 inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN);
585
586 /* Interface search. */
587 ifp = if_lookup_by_index_per_ns(zns, ifindex);
588 if (ifp == NULL) {
e914ccbe 589 flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
9df414fe 590 "RA/RS received on unknown IF %u from %s", ifindex,
d62a17ae 591 addr_str);
592 return;
593 }
594
595 if (IS_ZEBRA_DEBUG_PACKET)
596 zlog_debug("%s(%u): Rx RA/RS len %d from %s", ifp->name,
597 ifp->ifindex, len, addr_str);
598
599 if (if_is_loopback(ifp)
600 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))
601 return;
718e3744 602
d62a17ae 603 /* Check interface configuration. */
604 zif = ifp->info;
605 if (!zif->rtadv.AdvSendAdvertisements)
606 return;
718e3744 607
d62a17ae 608 /* ICMP message length check. */
609 if (len < sizeof(struct icmp6_hdr)) {
9df414fe
QY
610 zlog_debug("%s(%u): Rx RA with Invalid ICMPV6 packet length %d",
611 ifp->name, ifp->ifindex, len);
d62a17ae 612 return;
613 }
614
615 icmph = (struct icmp6_hdr *)buf;
718e3744 616
d62a17ae 617 /* ICMP message type check. */
618 if (icmph->icmp6_type != ND_ROUTER_SOLICIT
619 && icmph->icmp6_type != ND_ROUTER_ADVERT) {
9df414fe
QY
620 zlog_debug("%s(%u): Rx RA - Unwanted ICMPV6 message type %d",
621 ifp->name, ifp->ifindex, icmph->icmp6_type);
d62a17ae 622 return;
623 }
718e3744 624
d62a17ae 625 /* Hoplimit check. */
626 if (hoplimit >= 0 && hoplimit != 255) {
9df414fe
QY
627 zlog_debug("%s(%u): Rx RA - Invalid hoplimit %d", ifp->name,
628 ifp->ifindex, hoplimit);
d62a17ae 629 return;
630 }
718e3744 631
d62a17ae 632 /* Check ICMP message type. */
633 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
634 rtadv_process_solicit(ifp);
635 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
636 rtadv_process_advert(buf, len, ifp, from);
718e3744 637
d62a17ae 638 return;
718e3744 639}
640
d62a17ae 641static int rtadv_read(struct thread *thread)
718e3744 642{
d62a17ae 643 int sock;
644 int len;
d7c0a89a 645 uint8_t buf[RTADV_MSG_SIZE];
d62a17ae 646 struct sockaddr_in6 from;
647 ifindex_t ifindex = 0;
648 int hoplimit = -1;
649 struct zebra_ns *zns = THREAD_ARG(thread);
650
651 sock = THREAD_FD(thread);
652 zns->rtadv.ra_read = NULL;
653
654 /* Register myself. */
655 rtadv_event(zns, RTADV_READ, sock);
656
657 len = rtadv_recv_packet(zns, sock, buf, sizeof(buf), &from, &ifindex,
658 &hoplimit);
659
660 if (len < 0) {
450971aa 661 flog_err_sys(EC_LIB_SOCKET,
9df414fe
QY
662 "RA/RS recv failed, socket %u error %s", sock,
663 safe_strerror(errno));
d62a17ae 664 return len;
665 }
666
667 rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zns);
668
669 return 0;
718e3744 670}
6b0655a2 671
fe533c56 672static int rtadv_make_socket(ns_id_t ns_id)
718e3744 673{
8d2dcc85 674 int sock = -1;
d62a17ae 675 int ret = 0;
676 struct icmp6_filter filter;
677
01b9e3fd 678 frr_elevate_privs(&zserv_privs) {
d62a17ae 679
01b9e3fd 680 sock = ns_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, ns_id);
d62a17ae 681
01b9e3fd 682 }
d62a17ae 683
684 if (sock < 0) {
d62a17ae 685 return -1;
686 }
687
688 ret = setsockopt_ipv6_pktinfo(sock, 1);
689 if (ret < 0) {
690 close(sock);
691 return ret;
692 }
693 ret = setsockopt_ipv6_multicast_loop(sock, 0);
694 if (ret < 0) {
695 close(sock);
696 return ret;
697 }
698 ret = setsockopt_ipv6_unicast_hops(sock, 255);
699 if (ret < 0) {
700 close(sock);
701 return ret;
702 }
703 ret = setsockopt_ipv6_multicast_hops(sock, 255);
704 if (ret < 0) {
705 close(sock);
706 return ret;
707 }
708 ret = setsockopt_ipv6_hoplimit(sock, 1);
709 if (ret < 0) {
710 close(sock);
711 return ret;
712 }
713
714 ICMP6_FILTER_SETBLOCKALL(&filter);
715 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &filter);
716 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter);
717
718 ret = setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
719 sizeof(struct icmp6_filter));
720 if (ret < 0) {
721 zlog_info("ICMP6_FILTER set fail: %s", safe_strerror(errno));
44f12f20 722 close(sock);
d62a17ae 723 return ret;
724 }
725
726 return sock;
718e3744 727}
728
d62a17ae 729static struct rtadv_prefix *rtadv_prefix_new(void)
718e3744 730{
d62a17ae 731 return XCALLOC(MTYPE_RTADV_PREFIX, sizeof(struct rtadv_prefix));
718e3744 732}
733
d62a17ae 734static void rtadv_prefix_free(struct rtadv_prefix *rtadv_prefix)
718e3744 735{
d62a17ae 736 XFREE(MTYPE_RTADV_PREFIX, rtadv_prefix);
737}
718e3744 738
d62a17ae 739static struct rtadv_prefix *rtadv_prefix_lookup(struct list *rplist,
740 struct prefix_ipv6 *p)
741{
742 struct listnode *node;
743 struct rtadv_prefix *rprefix;
744
745 for (ALL_LIST_ELEMENTS_RO(rplist, node, rprefix))
746 if (prefix_same((struct prefix *)&rprefix->prefix,
747 (struct prefix *)p))
748 return rprefix;
749 return NULL;
718e3744 750}
751
d62a17ae 752static struct rtadv_prefix *rtadv_prefix_get(struct list *rplist,
753 struct prefix_ipv6 *p)
718e3744 754{
d62a17ae 755 struct rtadv_prefix *rprefix;
756
757 rprefix = rtadv_prefix_lookup(rplist, p);
758 if (rprefix)
759 return rprefix;
718e3744 760
d62a17ae 761 rprefix = rtadv_prefix_new();
762 memcpy(&rprefix->prefix, p, sizeof(struct prefix_ipv6));
763 listnode_add(rplist, rprefix);
718e3744 764
d62a17ae 765 return rprefix;
718e3744 766}
767
d62a17ae 768static void rtadv_prefix_set(struct zebra_if *zif, struct rtadv_prefix *rp)
718e3744 769{
d62a17ae 770 struct rtadv_prefix *rprefix;
771
772 rprefix = rtadv_prefix_get(zif->rtadv.AdvPrefixList, &rp->prefix);
773
774 /* Set parameters. */
775 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
776 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
777 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
778 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
779 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
718e3744 780}
781
d62a17ae 782static int rtadv_prefix_reset(struct zebra_if *zif, struct rtadv_prefix *rp)
718e3744 783{
d62a17ae 784 struct rtadv_prefix *rprefix;
785
786 rprefix = rtadv_prefix_lookup(zif->rtadv.AdvPrefixList, &rp->prefix);
787 if (rprefix != NULL) {
788 listnode_delete(zif->rtadv.AdvPrefixList, (void *)rprefix);
789 rtadv_prefix_free(rprefix);
790 return 1;
791 } else
792 return 0;
718e3744 793}
794
d62a17ae 795static void ipv6_nd_suppress_ra_set(struct interface *ifp,
796 ipv6_nd_suppress_ra_status status)
b6120505 797{
d62a17ae 798 struct zebra_if *zif;
799 struct zebra_vrf *zvrf;
800 struct zebra_ns *zns;
801
802 zif = ifp->info;
803 zvrf = vrf_info_lookup(ifp->vrf_id);
804 zns = zvrf->zns;
805
806 if (status == RA_SUPPRESS) {
807 /* RA is currently enabled */
808 if (zif->rtadv.AdvSendAdvertisements) {
809 zif->rtadv.AdvSendAdvertisements = 0;
810 zif->rtadv.AdvIntervalTimer = 0;
811 zns->rtadv.adv_if_count--;
812
813 if_leave_all_router(zns->rtadv.sock, ifp);
814
815 if (zns->rtadv.adv_if_count == 0)
816 rtadv_event(zns, RTADV_STOP, 0);
817 }
818 } else {
819 if (!zif->rtadv.AdvSendAdvertisements) {
820 zif->rtadv.AdvSendAdvertisements = 1;
821 zif->rtadv.AdvIntervalTimer = 0;
822 zns->rtadv.adv_if_count++;
823
824 if (zif->rtadv.MaxRtrAdvInterval >= 1000) {
825 /* Enable Fast RA only when RA interval is in
826 * secs */
827 zif->rtadv.inFastRexmit = 1;
828 zif->rtadv.NumFastReXmitsRemain =
829 RTADV_NUM_FAST_REXMITS;
830 }
831
832 if_join_all_router(zns->rtadv.sock, ifp);
833
834 if (zns->rtadv.adv_if_count == 1)
835 rtadv_event(zns, RTADV_START, zns->rtadv.sock);
836 }
837 }
b6120505
DW
838}
839
4a04e5f7 840/*
841 * Handle client (BGP) message to enable or disable IPv6 RA on an interface.
842 * Note that while the client could request RA on an interface on which the
843 * operator has not enabled RA, RA won't be disabled upon client request
5c81b96a 844 * if the operator has explicitly enabled RA. The enable request can also
845 * specify a RA interval (in seconds).
4a04e5f7 846 */
1002497a 847static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
4a04e5f7 848{
d62a17ae 849 struct stream *s;
ec93aa12 850 ifindex_t ifindex;
d62a17ae 851 struct interface *ifp;
852 struct zebra_if *zif;
853 int ra_interval;
854
1002497a 855 s = msg;
d62a17ae 856
857 /* Get interface index and RA interval. */
ec93aa12
DS
858 STREAM_GETL(s, ifindex);
859 STREAM_GETL(s, ra_interval);
d62a17ae 860
861 if (IS_ZEBRA_DEBUG_EVENT)
862 zlog_debug("%u: IF %u RA %s from client %s, interval %ds",
1002497a
QY
863 zvrf_id(zvrf), ifindex,
864 enable ? "enable" : "disable",
d62a17ae 865 zebra_route_string(client->proto), ra_interval);
866
867 /* Locate interface and check VRF match. */
868 ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex);
869 if (!ifp) {
e914ccbe 870 flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
9df414fe 871 "%u: IF %u RA %s client %s - interface unknown",
1002497a 872 zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
d62a17ae 873 zebra_route_string(client->proto));
874 return;
875 }
876 if (ifp->vrf_id != zvrf_id(zvrf)) {
9df414fe
QY
877 zlog_debug(
878 "%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
879 zvrf_id(zvrf), ifindex, enable ? "enable" : "disable",
880 zebra_route_string(client->proto), ifp->vrf_id);
d62a17ae 881 return;
882 }
883
884 zif = ifp->info;
1002497a 885 if (enable) {
3ea48364 886 SET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
d62a17ae 887 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
888 if (ra_interval
996c9314
LB
889 && (ra_interval * 1000) < zif->rtadv.MaxRtrAdvInterval
890 && !CHECK_FLAG(zif->rtadv.ra_configured,
891 VTY_RA_INTERVAL_CONFIGURED))
d62a17ae 892 zif->rtadv.MaxRtrAdvInterval = ra_interval * 1000;
893 } else {
3ea48364
DS
894 UNSET_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED);
895 if (!CHECK_FLAG(zif->rtadv.ra_configured,
896 VTY_RA_INTERVAL_CONFIGURED))
d62a17ae 897 zif->rtadv.MaxRtrAdvInterval =
898 RTADV_MAX_RTR_ADV_INTERVAL;
3ea48364 899 if (!CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
d62a17ae 900 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
d62a17ae 901 }
ec93aa12
DS
902stream_failure:
903 return;
4a04e5f7 904}
905
89f4e507
QY
906void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS)
907{
1002497a 908 zebra_interface_radv_set(client, hdr, msg, zvrf, 0);
89f4e507 909}
89f4e507
QY
910void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS)
911{
1002497a 912 zebra_interface_radv_set(client, hdr, msg, zvrf, 1);
89f4e507
QY
913}
914
718e3744 915DEFUN (ipv6_nd_suppress_ra,
916 ipv6_nd_suppress_ra_cmd,
917 "ipv6 nd suppress-ra",
3e31cded 918 "Interface IPv6 config commands\n"
718e3744 919 "Neighbor discovery\n"
920 "Suppress Router Advertisement\n")
921{
d62a17ae 922 VTY_DECLVAR_CONTEXT(interface, ifp);
923 struct zebra_if *zif = ifp->info;
924
925 if (if_is_loopback(ifp)
926 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
927 vty_out(vty,
928 "Cannot configure IPv6 Router Advertisements on this interface\n");
929 return CMD_WARNING_CONFIG_FAILED;
930 }
931
3ea48364
DS
932 if (!CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
933 ipv6_nd_suppress_ra_set(ifp, RA_SUPPRESS);
934
935 UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
d62a17ae 936 return CMD_SUCCESS;
718e3744 937}
938
718e3744 939DEFUN (no_ipv6_nd_suppress_ra,
940 no_ipv6_nd_suppress_ra_cmd,
941 "no ipv6 nd suppress-ra",
942 NO_STR
3e31cded 943 "Interface IPv6 config commands\n"
718e3744 944 "Neighbor discovery\n"
945 "Suppress Router Advertisement\n")
946{
d62a17ae 947 VTY_DECLVAR_CONTEXT(interface, ifp);
948 struct zebra_if *zif = ifp->info;
949
950 if (if_is_loopback(ifp)
951 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK)) {
952 vty_out(vty,
953 "Cannot configure IPv6 Router Advertisements on this interface\n");
954 return CMD_WARNING_CONFIG_FAILED;
955 }
956
957 ipv6_nd_suppress_ra_set(ifp, RA_ENABLE);
3ea48364 958 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED);
d62a17ae 959 return CMD_SUCCESS;
718e3744 960}
961
7cee1bb1 962DEFUN (ipv6_nd_ra_interval_msec,
963 ipv6_nd_ra_interval_msec_cmd,
6147e2c6 964 "ipv6 nd ra-interval msec (70-1800000)",
7cee1bb1 965 "Interface IPv6 config commands\n"
966 "Neighbor discovery\n"
967 "Router Advertisement interval\n"
3a2d747c 968 "Router Advertisement interval in milliseconds\n"
7cee1bb1 969 "Router Advertisement interval in milliseconds\n")
970{
d62a17ae 971 int idx_number = 4;
972 VTY_DECLVAR_CONTEXT(interface, ifp);
973 unsigned interval;
974 struct zebra_if *zif = ifp->info;
975 struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
976 struct zebra_ns *zns;
977
978 zns = zvrf->zns;
979 interval = strtoul(argv[idx_number]->arg, NULL, 10);
980 if ((zif->rtadv.AdvDefaultLifetime != -1
981 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000)) {
982 vty_out(vty,
983 "This ra-interval would conflict with configured ra-lifetime!\n");
984 return CMD_WARNING_CONFIG_FAILED;
985 }
986
987 if (zif->rtadv.MaxRtrAdvInterval % 1000)
988 zns->rtadv.adv_msec_if_count--;
989
990 if (interval % 1000)
991 zns->rtadv.adv_msec_if_count++;
992
3ea48364 993 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
d62a17ae 994 zif->rtadv.MaxRtrAdvInterval = interval;
995 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
996 zif->rtadv.AdvIntervalTimer = 0;
997
998 return CMD_SUCCESS;
7cee1bb1 999}
1000
718e3744 1001DEFUN (ipv6_nd_ra_interval,
1002 ipv6_nd_ra_interval_cmd,
6147e2c6 1003 "ipv6 nd ra-interval (1-1800)",
3e31cded 1004 "Interface IPv6 config commands\n"
718e3744 1005 "Neighbor discovery\n"
1006 "Router Advertisement interval\n"
1007 "Router Advertisement interval in seconds\n")
1008{
d62a17ae 1009 int idx_number = 3;
1010 VTY_DECLVAR_CONTEXT(interface, ifp);
1011 unsigned interval;
1012 struct zebra_if *zif = ifp->info;
1013 struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
1014 struct zebra_ns *zns;
1015
1016 zns = zvrf->zns;
1017 interval = strtoul(argv[idx_number]->arg, NULL, 10);
1018 if ((zif->rtadv.AdvDefaultLifetime != -1
1019 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime)) {
1020 vty_out(vty,
1021 "This ra-interval would conflict with configured ra-lifetime!\n");
1022 return CMD_WARNING_CONFIG_FAILED;
1023 }
1024
1025 if (zif->rtadv.MaxRtrAdvInterval % 1000)
1026 zns->rtadv.adv_msec_if_count--;
1027
1028 /* convert to milliseconds */
1029 interval = interval * 1000;
1030
3ea48364 1031 SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
d62a17ae 1032 zif->rtadv.MaxRtrAdvInterval = interval;
1033 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
1034 zif->rtadv.AdvIntervalTimer = 0;
1035
1036 return CMD_SUCCESS;
718e3744 1037}
1038
1039DEFUN (no_ipv6_nd_ra_interval,
1040 no_ipv6_nd_ra_interval_cmd,
34ccea1e 1041 "no ipv6 nd ra-interval [<(1-1800)|msec (1-1800000)>]",
718e3744 1042 NO_STR
3e31cded 1043 "Interface IPv6 config commands\n"
718e3744 1044 "Neighbor discovery\n"
34ccea1e
QY
1045 "Router Advertisement interval\n"
1046 "Router Advertisement interval in seconds\n"
1047 "Specify millisecond router advertisement interval\n"
1048 "Router Advertisement interval in milliseconds\n")
718e3744 1049{
d62a17ae 1050 VTY_DECLVAR_CONTEXT(interface, ifp);
1051 struct zebra_if *zif = ifp->info;
1052 struct zebra_vrf *zvrf;
1053 struct zebra_ns *zns;
1054
1055 zvrf = vrf_info_lookup(ifp->vrf_id);
1056 zns = zvrf->zns;
1057
1058 if (zif->rtadv.MaxRtrAdvInterval % 1000)
1059 zns->rtadv.adv_msec_if_count--;
1060
3ea48364
DS
1061 UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
1062
1063 if (CHECK_FLAG(zif->rtadv.ra_configured, BGP_RA_CONFIGURED))
1064 zif->rtadv.MaxRtrAdvInterval = 10000;
1065 else
1066 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
1067
d62a17ae 1068 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
3ea48364 1069 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
d62a17ae 1070
1071 return CMD_SUCCESS;
718e3744 1072}
1073
1074DEFUN (ipv6_nd_ra_lifetime,
1075 ipv6_nd_ra_lifetime_cmd,
6147e2c6 1076 "ipv6 nd ra-lifetime (0-9000)",
3e31cded 1077 "Interface IPv6 config commands\n"
718e3744 1078 "Neighbor discovery\n"
1079 "Router lifetime\n"
4afa50b3 1080 "Router lifetime in seconds (0 stands for a non-default gw)\n")
718e3744 1081{
d62a17ae 1082 int idx_number = 3;
1083 VTY_DECLVAR_CONTEXT(interface, ifp);
1084 struct zebra_if *zif = ifp->info;
1085 int lifetime;
1086
1087 lifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1088
1089 /* The value to be placed in the Router Lifetime field
1090 * of Router Advertisements sent from the interface,
1091 * in seconds. MUST be either zero or between
1092 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
1093 if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)) {
1094 vty_out(vty,
1095 "This ra-lifetime would conflict with configured ra-interval\n");
1096 return CMD_WARNING_CONFIG_FAILED;
1097 }
1098
1099 zif->rtadv.AdvDefaultLifetime = lifetime;
1100
1101 return CMD_SUCCESS;
718e3744 1102}
1103
1104DEFUN (no_ipv6_nd_ra_lifetime,
1105 no_ipv6_nd_ra_lifetime_cmd,
34ccea1e 1106 "no ipv6 nd ra-lifetime [(0-9000)]",
718e3744 1107 NO_STR
3e31cded 1108 "Interface IPv6 config commands\n"
718e3744 1109 "Neighbor discovery\n"
34ccea1e
QY
1110 "Router lifetime\n"
1111 "Router lifetime in seconds (0 stands for a non-default gw)\n")
718e3744 1112{
d62a17ae 1113 VTY_DECLVAR_CONTEXT(interface, ifp);
1114 struct zebra_if *zif = ifp->info;
718e3744 1115
d62a17ae 1116 zif->rtadv.AdvDefaultLifetime = -1;
718e3744 1117
d62a17ae 1118 return CMD_SUCCESS;
718e3744 1119}
1120
1121DEFUN (ipv6_nd_reachable_time,
1122 ipv6_nd_reachable_time_cmd,
6147e2c6 1123 "ipv6 nd reachable-time (1-3600000)",
3e31cded 1124 "Interface IPv6 config commands\n"
718e3744 1125 "Neighbor discovery\n"
1126 "Reachable time\n"
1127 "Reachable time in milliseconds\n")
1128{
d62a17ae 1129 int idx_number = 3;
1130 VTY_DECLVAR_CONTEXT(interface, ifp);
1131 struct zebra_if *zif = ifp->info;
1132 zif->rtadv.AdvReachableTime = strtoul(argv[idx_number]->arg, NULL, 10);
1133 return CMD_SUCCESS;
718e3744 1134}
1135
1136DEFUN (no_ipv6_nd_reachable_time,
1137 no_ipv6_nd_reachable_time_cmd,
34ccea1e 1138 "no ipv6 nd reachable-time [(1-3600000)]",
718e3744 1139 NO_STR
3e31cded 1140 "Interface IPv6 config commands\n"
718e3744 1141 "Neighbor discovery\n"
34ccea1e
QY
1142 "Reachable time\n"
1143 "Reachable time in milliseconds\n")
718e3744 1144{
d62a17ae 1145 VTY_DECLVAR_CONTEXT(interface, ifp);
1146 struct zebra_if *zif = ifp->info;
718e3744 1147
d62a17ae 1148 zif->rtadv.AdvReachableTime = 0;
718e3744 1149
d62a17ae 1150 return CMD_SUCCESS;
718e3744 1151}
1152
7cee1bb1 1153DEFUN (ipv6_nd_homeagent_preference,
1154 ipv6_nd_homeagent_preference_cmd,
6147e2c6 1155 "ipv6 nd home-agent-preference (0-65535)",
7cee1bb1 1156 "Interface IPv6 config commands\n"
1157 "Neighbor discovery\n"
1158 "Home Agent preference\n"
4afa50b3 1159 "preference value (default is 0, least preferred)\n")
7cee1bb1 1160{
d62a17ae 1161 int idx_number = 3;
1162 VTY_DECLVAR_CONTEXT(interface, ifp);
1163 struct zebra_if *zif = ifp->info;
1164 zif->rtadv.HomeAgentPreference =
1165 strtoul(argv[idx_number]->arg, NULL, 10);
1166 return CMD_SUCCESS;
7cee1bb1 1167}
1168
1169DEFUN (no_ipv6_nd_homeagent_preference,
1170 no_ipv6_nd_homeagent_preference_cmd,
34ccea1e 1171 "no ipv6 nd home-agent-preference [(0-65535)]",
7cee1bb1 1172 NO_STR
1173 "Interface IPv6 config commands\n"
1174 "Neighbor discovery\n"
34ccea1e
QY
1175 "Home Agent preference\n"
1176 "preference value (default is 0, least preferred)\n")
7cee1bb1 1177{
d62a17ae 1178 VTY_DECLVAR_CONTEXT(interface, ifp);
1179 struct zebra_if *zif = ifp->info;
7cee1bb1 1180
d62a17ae 1181 zif->rtadv.HomeAgentPreference = 0;
7cee1bb1 1182
d62a17ae 1183 return CMD_SUCCESS;
7cee1bb1 1184}
1185
1186DEFUN (ipv6_nd_homeagent_lifetime,
1187 ipv6_nd_homeagent_lifetime_cmd,
6147e2c6 1188 "ipv6 nd home-agent-lifetime (0-65520)",
7cee1bb1 1189 "Interface IPv6 config commands\n"
1190 "Neighbor discovery\n"
1191 "Home Agent lifetime\n"
4afa50b3 1192 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
7cee1bb1 1193{
d62a17ae 1194 int idx_number = 3;
1195 VTY_DECLVAR_CONTEXT(interface, ifp);
1196 struct zebra_if *zif = ifp->info;
1197 zif->rtadv.HomeAgentLifetime = strtoul(argv[idx_number]->arg, NULL, 10);
1198 return CMD_SUCCESS;
7cee1bb1 1199}
1200
1201DEFUN (no_ipv6_nd_homeagent_lifetime,
1202 no_ipv6_nd_homeagent_lifetime_cmd,
34ccea1e 1203 "no ipv6 nd home-agent-lifetime [(0-65520)]",
7cee1bb1 1204 NO_STR
1205 "Interface IPv6 config commands\n"
1206 "Neighbor discovery\n"
34ccea1e
QY
1207 "Home Agent lifetime\n"
1208 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
7cee1bb1 1209{
d62a17ae 1210 VTY_DECLVAR_CONTEXT(interface, ifp);
1211 struct zebra_if *zif = ifp->info;
7cee1bb1 1212
d62a17ae 1213 zif->rtadv.HomeAgentLifetime = -1;
7cee1bb1 1214
d62a17ae 1215 return CMD_SUCCESS;
7cee1bb1 1216}
1217
718e3744 1218DEFUN (ipv6_nd_managed_config_flag,
1219 ipv6_nd_managed_config_flag_cmd,
1220 "ipv6 nd managed-config-flag",
3e31cded 1221 "Interface IPv6 config commands\n"
718e3744 1222 "Neighbor discovery\n"
1223 "Managed address configuration flag\n")
1224{
d62a17ae 1225 VTY_DECLVAR_CONTEXT(interface, ifp);
1226 struct zebra_if *zif = ifp->info;
718e3744 1227
d62a17ae 1228 zif->rtadv.AdvManagedFlag = 1;
718e3744 1229
d62a17ae 1230 return CMD_SUCCESS;
718e3744 1231}
1232
1233DEFUN (no_ipv6_nd_managed_config_flag,
1234 no_ipv6_nd_managed_config_flag_cmd,
1235 "no ipv6 nd managed-config-flag",
1236 NO_STR
3e31cded 1237 "Interface IPv6 config commands\n"
718e3744 1238 "Neighbor discovery\n"
1239 "Managed address configuration flag\n")
1240{
d62a17ae 1241 VTY_DECLVAR_CONTEXT(interface, ifp);
1242 struct zebra_if *zif = ifp->info;
718e3744 1243
d62a17ae 1244 zif->rtadv.AdvManagedFlag = 0;
718e3744 1245
d62a17ae 1246 return CMD_SUCCESS;
718e3744 1247}
1248
7cee1bb1 1249DEFUN (ipv6_nd_homeagent_config_flag,
1250 ipv6_nd_homeagent_config_flag_cmd,
1251 "ipv6 nd home-agent-config-flag",
1252 "Interface IPv6 config commands\n"
1253 "Neighbor discovery\n"
1254 "Home Agent configuration flag\n")
1255{
d62a17ae 1256 VTY_DECLVAR_CONTEXT(interface, ifp);
1257 struct zebra_if *zif = ifp->info;
7cee1bb1 1258
d62a17ae 1259 zif->rtadv.AdvHomeAgentFlag = 1;
7cee1bb1 1260
d62a17ae 1261 return CMD_SUCCESS;
7cee1bb1 1262}
1263
1264DEFUN (no_ipv6_nd_homeagent_config_flag,
1265 no_ipv6_nd_homeagent_config_flag_cmd,
1266 "no ipv6 nd home-agent-config-flag",
1267 NO_STR
1268 "Interface IPv6 config commands\n"
1269 "Neighbor discovery\n"
1270 "Home Agent configuration flag\n")
1271{
d62a17ae 1272 VTY_DECLVAR_CONTEXT(interface, ifp);
1273 struct zebra_if *zif = ifp->info;
7cee1bb1 1274
d62a17ae 1275 zif->rtadv.AdvHomeAgentFlag = 0;
7cee1bb1 1276
d62a17ae 1277 return CMD_SUCCESS;
7cee1bb1 1278}
1279
1280DEFUN (ipv6_nd_adv_interval_config_option,
1281 ipv6_nd_adv_interval_config_option_cmd,
1282 "ipv6 nd adv-interval-option",
1283 "Interface IPv6 config commands\n"
1284 "Neighbor discovery\n"
1285 "Advertisement Interval Option\n")
1286{
d62a17ae 1287 VTY_DECLVAR_CONTEXT(interface, ifp);
1288 struct zebra_if *zif = ifp->info;
7cee1bb1 1289
d62a17ae 1290 zif->rtadv.AdvIntervalOption = 1;
7cee1bb1 1291
d62a17ae 1292 return CMD_SUCCESS;
7cee1bb1 1293}
1294
1295DEFUN (no_ipv6_nd_adv_interval_config_option,
1296 no_ipv6_nd_adv_interval_config_option_cmd,
1297 "no ipv6 nd adv-interval-option",
1298 NO_STR
1299 "Interface IPv6 config commands\n"
1300 "Neighbor discovery\n"
1301 "Advertisement Interval Option\n")
1302{
d62a17ae 1303 VTY_DECLVAR_CONTEXT(interface, ifp);
1304 struct zebra_if *zif = ifp->info;
7cee1bb1 1305
d62a17ae 1306 zif->rtadv.AdvIntervalOption = 0;
7cee1bb1 1307
d62a17ae 1308 return CMD_SUCCESS;
7cee1bb1 1309}
1310
718e3744 1311DEFUN (ipv6_nd_other_config_flag,
1312 ipv6_nd_other_config_flag_cmd,
1313 "ipv6 nd other-config-flag",
3e31cded 1314 "Interface IPv6 config commands\n"
718e3744 1315 "Neighbor discovery\n"
1316 "Other statefull configuration flag\n")
1317{
d62a17ae 1318 VTY_DECLVAR_CONTEXT(interface, ifp);
1319 struct zebra_if *zif = ifp->info;
718e3744 1320
d62a17ae 1321 zif->rtadv.AdvOtherConfigFlag = 1;
718e3744 1322
d62a17ae 1323 return CMD_SUCCESS;
718e3744 1324}
1325
1326DEFUN (no_ipv6_nd_other_config_flag,
1327 no_ipv6_nd_other_config_flag_cmd,
1328 "no ipv6 nd other-config-flag",
1329 NO_STR
3e31cded 1330 "Interface IPv6 config commands\n"
718e3744 1331 "Neighbor discovery\n"
1332 "Other statefull configuration flag\n")
1333{
d62a17ae 1334 VTY_DECLVAR_CONTEXT(interface, ifp);
1335 struct zebra_if *zif = ifp->info;
718e3744 1336
d62a17ae 1337 zif->rtadv.AdvOtherConfigFlag = 0;
718e3744 1338
d62a17ae 1339 return CMD_SUCCESS;
718e3744 1340}
1341
3e31cded 1342DEFUN (ipv6_nd_prefix,
1343 ipv6_nd_prefix_cmd,
34ccea1e 1344 "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 1345 "Interface IPv6 config commands\n"
718e3744 1346 "Neighbor discovery\n"
1347 "Prefix information\n"
1348 "IPv6 prefix\n"
1349 "Valid lifetime in seconds\n"
3e31cded 1350 "Infinite valid lifetime\n"
718e3744 1351 "Preferred lifetime in seconds\n"
3e31cded 1352 "Infinite preferred lifetime\n"
34ccea1e 1353 "Set Router Address flag\n"
3e31cded 1354 "Do not use prefix for onlink determination\n"
7cee1bb1 1355 "Do not use prefix for autoconfiguration\n"
34ccea1e
QY
1356 "Do not use prefix for autoconfiguration\n"
1357 "Do not use prefix for onlink determination\n")
718e3744 1358{
d62a17ae 1359 /* prelude */
1360 char *prefix = argv[3]->arg;
9d303b37
DL
1361 int lifetimes = (argc > 4) && (argv[4]->type == RANGE_TKN
1362 || strmatch(argv[4]->text, "infinite"));
d62a17ae 1363 int routeropts = lifetimes ? argc > 6 : argc > 4;
1364
1365 int idx_routeropts = routeropts ? (lifetimes ? 6 : 4) : 0;
1366
1367 char *lifetime = NULL, *preflifetime = NULL;
1368 int routeraddr = 0, offlink = 0, noautoconf = 0;
1369 if (lifetimes) {
1370 lifetime = argv[4]->type == RANGE_TKN ? argv[4]->arg
1371 : argv[4]->text;
1372 preflifetime = argv[5]->type == RANGE_TKN ? argv[5]->arg
1373 : argv[5]->text;
1374 }
1375 if (routeropts) {
1376 routeraddr =
1377 strmatch(argv[idx_routeropts]->text, "router-address");
1378 if (!routeraddr) {
1379 offlink = (argc > idx_routeropts + 1
1380 || strmatch(argv[idx_routeropts]->text,
1381 "off-link"));
1382 noautoconf = (argc > idx_routeropts + 1
1383 || strmatch(argv[idx_routeropts]->text,
1384 "no-autoconfig"));
1385 }
1386 }
1387
1388 /* business */
1389 VTY_DECLVAR_CONTEXT(interface, ifp);
1390 struct zebra_if *zebra_if = ifp->info;
1391 int ret;
1392 struct rtadv_prefix rp;
1393
1394 ret = str2prefix_ipv6(prefix, &rp.prefix);
1395 if (!ret) {
1396 vty_out(vty, "Malformed IPv6 prefix\n");
1397 return CMD_WARNING_CONFIG_FAILED;
1398 }
1399 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
1400 rp.AdvOnLinkFlag = !offlink;
1401 rp.AdvAutonomousFlag = !noautoconf;
1402 rp.AdvRouterAddressFlag = routeraddr;
1403 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1404 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
1405
1406 if (lifetimes) {
1407 rp.AdvValidLifetime = strmatch(lifetime, "infinite")
1408 ? UINT32_MAX
1409 : strtoll(lifetime, NULL, 10);
1410 rp.AdvPreferredLifetime =
1411 strmatch(preflifetime, "infinite")
1412 ? UINT32_MAX
1413 : strtoll(preflifetime, NULL, 10);
1414 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime) {
1415 vty_out(vty, "Invalid preferred lifetime\n");
1416 return CMD_WARNING_CONFIG_FAILED;
1417 }
1418 }
1419
1420 rtadv_prefix_set(zebra_if, &rp);
1421
1422 return CMD_SUCCESS;
718e3744 1423}
1424
3e31cded 1425DEFUN (no_ipv6_nd_prefix,
1426 no_ipv6_nd_prefix_cmd,
34ccea1e
QY
1427 "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]>]",
1428 NO_STR
3e31cded 1429 "Interface IPv6 config commands\n"
718e3744 1430 "Neighbor discovery\n"
1431 "Prefix information\n"
34ccea1e
QY
1432 "IPv6 prefix\n"
1433 "Valid lifetime in seconds\n"
1434 "Infinite valid lifetime\n"
1435 "Preferred lifetime in seconds\n"
1436 "Infinite preferred lifetime\n"
1437 "Set Router Address flag\n"
1438 "Do not use prefix for onlink determination\n"
1439 "Do not use prefix for autoconfiguration\n"
1440 "Do not use prefix for autoconfiguration\n"
1441 "Do not use prefix for onlink determination\n")
718e3744 1442{
d62a17ae 1443 VTY_DECLVAR_CONTEXT(interface, ifp);
1444 struct zebra_if *zebra_if = ifp->info;
1445 int ret;
1446 struct rtadv_prefix rp;
1447 char *prefix = argv[4]->arg;
1448
1449 ret = str2prefix_ipv6(prefix, &rp.prefix);
1450 if (!ret) {
1451 vty_out(vty, "Malformed IPv6 prefix\n");
1452 return CMD_WARNING_CONFIG_FAILED;
1453 }
1454 apply_mask_ipv6(&rp.prefix); /* RFC4861 4.6.2 */
1455
1456 ret = rtadv_prefix_reset(zebra_if, &rp);
1457 if (!ret) {
1458 vty_out(vty, "Non-existant IPv6 prefix\n");
1459 return CMD_WARNING_CONFIG_FAILED;
1460 }
1461
1462 return CMD_SUCCESS;
718e3744 1463}
b60668d0
CC
1464
1465DEFUN (ipv6_nd_router_preference,
1466 ipv6_nd_router_preference_cmd,
6147e2c6 1467 "ipv6 nd router-preference <high|medium|low>",
b60668d0
CC
1468 "Interface IPv6 config commands\n"
1469 "Neighbor discovery\n"
1470 "Default router preference\n"
1471 "High default router preference\n"
58f1b7cc
DS
1472 "Medium default router preference (default)\n"
1473 "Low default router preference\n")
b60668d0 1474{
d62a17ae 1475 int idx_high_medium_low = 3;
1476 VTY_DECLVAR_CONTEXT(interface, ifp);
1477 struct zebra_if *zif = ifp->info;
1478 int i = 0;
1479
1480 while (0 != rtadv_pref_strs[i]) {
1481 if (strncmp(argv[idx_high_medium_low]->arg, rtadv_pref_strs[i],
1482 1)
1483 == 0) {
1484 zif->rtadv.DefaultPreference = i;
1485 return CMD_SUCCESS;
1486 }
1487 i++;
b60668d0 1488 }
b60668d0 1489
d62a17ae 1490 return CMD_ERR_NO_MATCH;
b60668d0
CC
1491}
1492
1493DEFUN (no_ipv6_nd_router_preference,
1494 no_ipv6_nd_router_preference_cmd,
34ccea1e 1495 "no ipv6 nd router-preference [<high|medium|low>]",
b60668d0
CC
1496 NO_STR
1497 "Interface IPv6 config commands\n"
1498 "Neighbor discovery\n"
34ccea1e
QY
1499 "Default router preference\n"
1500 "High default router preference\n"
1501 "Medium default router preference (default)\n"
1502 "Low default router preference\n")
b60668d0 1503{
d62a17ae 1504 VTY_DECLVAR_CONTEXT(interface, ifp);
1505 struct zebra_if *zif = ifp->info;
b60668d0 1506
d62a17ae 1507 zif->rtadv.DefaultPreference =
1508 RTADV_PREF_MEDIUM; /* Default per RFC4191. */
b60668d0 1509
d62a17ae 1510 return CMD_SUCCESS;
b60668d0
CC
1511}
1512
6ae93c05
DO
1513DEFUN (ipv6_nd_mtu,
1514 ipv6_nd_mtu_cmd,
6147e2c6 1515 "ipv6 nd mtu (1-65535)",
6ae93c05
DO
1516 "Interface IPv6 config commands\n"
1517 "Neighbor discovery\n"
1518 "Advertised MTU\n"
1519 "MTU in bytes\n")
1520{
d62a17ae 1521 int idx_number = 3;
1522 VTY_DECLVAR_CONTEXT(interface, ifp);
1523 struct zebra_if *zif = ifp->info;
1524 zif->rtadv.AdvLinkMTU = strtoul(argv[idx_number]->arg, NULL, 10);
1525 return CMD_SUCCESS;
6ae93c05
DO
1526}
1527
1528DEFUN (no_ipv6_nd_mtu,
1529 no_ipv6_nd_mtu_cmd,
34ccea1e 1530 "no ipv6 nd mtu [(1-65535)]",
6ae93c05
DO
1531 NO_STR
1532 "Interface IPv6 config commands\n"
1533 "Neighbor discovery\n"
34ccea1e
QY
1534 "Advertised MTU\n"
1535 "MTU in bytes\n")
6ae93c05 1536{
d62a17ae 1537 VTY_DECLVAR_CONTEXT(interface, ifp);
1538 struct zebra_if *zif = ifp->info;
1539 zif->rtadv.AdvLinkMTU = 0;
1540 return CMD_SUCCESS;
6ae93c05
DO
1541}
1542
2eb27eec
DL
1543/* Dump interface ND information to vty. */
1544static int nd_dump_vty(struct vty *vty, struct interface *ifp)
1545{
1546 struct zebra_if *zif;
1547 struct rtadvconf *rtadv;
1548 int interval;
1549
1550 zif = (struct zebra_if *)ifp->info;
1551 rtadv = &zif->rtadv;
1552
1553 if (rtadv->AdvSendAdvertisements) {
1554 vty_out(vty,
1555 " ND advertised reachable time is %d milliseconds\n",
1556 rtadv->AdvReachableTime);
1557 vty_out(vty,
1558 " ND advertised retransmit interval is %d milliseconds\n",
1559 rtadv->AdvRetransTimer);
1560 vty_out(vty, " ND router advertisements sent: %d rcvd: %d\n",
1561 zif->ra_sent, zif->ra_rcvd);
1562 interval = rtadv->MaxRtrAdvInterval;
1563 if (interval % 1000)
1564 vty_out(vty,
1565 " ND router advertisements are sent every "
1566 "%d milliseconds\n",
1567 interval);
1568 else
1569 vty_out(vty,
1570 " ND router advertisements are sent every "
1571 "%d seconds\n",
1572 interval / 1000);
1573 if (rtadv->AdvDefaultLifetime != -1)
1574 vty_out(vty,
1575 " ND router advertisements live for %d seconds\n",
1576 rtadv->AdvDefaultLifetime);
1577 else
1578 vty_out(vty,
1579 " ND router advertisements lifetime tracks ra-interval\n");
1580 vty_out(vty,
1581 " ND router advertisement default router preference is "
1582 "%s\n",
1583 rtadv_pref_strs[rtadv->DefaultPreference]);
1584 if (rtadv->AdvManagedFlag)
1585 vty_out(vty,
1586 " Hosts use DHCP to obtain routable addresses.\n");
1587 else
1588 vty_out(vty,
1589 " Hosts use stateless autoconfig for addresses.\n");
1590 if (rtadv->AdvHomeAgentFlag) {
1591 vty_out(vty,
1592 " ND router advertisements with Home Agent flag bit set.\n");
1593 if (rtadv->HomeAgentLifetime != -1)
1594 vty_out(vty,
1595 " Home Agent lifetime is %u seconds\n",
1596 rtadv->HomeAgentLifetime);
1597 else
1598 vty_out(vty,
1599 " Home Agent lifetime tracks ra-lifetime\n");
1600 vty_out(vty, " Home Agent preference is %u\n",
1601 rtadv->HomeAgentPreference);
1602 }
1603 if (rtadv->AdvIntervalOption)
1604 vty_out(vty,
1605 " ND router advertisements with Adv. Interval option.\n");
1606 }
1607 return 0;
1608}
1609
6ae93c05 1610
718e3744 1611/* Write configuration about router advertisement. */
2eb27eec 1612static int rtadv_config_write(struct vty *vty, struct interface *ifp)
718e3744 1613{
d62a17ae 1614 struct zebra_if *zif;
1615 struct listnode *node;
1616 struct rtadv_prefix *rprefix;
1617 char buf[PREFIX_STRLEN];
1618 int interval;
1619
1620 zif = ifp->info;
1621
1622 if (!(if_is_loopback(ifp)
1623 || CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK))) {
3ea48364
DS
1624 if (zif->rtadv.AdvSendAdvertisements
1625 && CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED))
d62a17ae 1626 vty_out(vty, " no ipv6 nd suppress-ra\n");
1627 }
1628
1629 interval = zif->rtadv.MaxRtrAdvInterval;
3ea48364
DS
1630 if (CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED)) {
1631 if (interval % 1000)
1632 vty_out(vty, " ipv6 nd ra-interval msec %d\n",
1633 interval);
1634 else if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
1635 vty_out(vty, " ipv6 nd ra-interval %d\n",
1636 interval / 1000);
1637 }
d62a17ae 1638
1639 if (zif->rtadv.AdvIntervalOption)
1640 vty_out(vty, " ipv6 nd adv-interval-option\n");
1641
1642 if (zif->rtadv.AdvDefaultLifetime != -1)
1643 vty_out(vty, " ipv6 nd ra-lifetime %d\n",
1644 zif->rtadv.AdvDefaultLifetime);
1645
1646 if (zif->rtadv.HomeAgentPreference)
1647 vty_out(vty, " ipv6 nd home-agent-preference %u\n",
1648 zif->rtadv.HomeAgentPreference);
1649
1650 if (zif->rtadv.HomeAgentLifetime != -1)
1651 vty_out(vty, " ipv6 nd home-agent-lifetime %u\n",
1652 zif->rtadv.HomeAgentLifetime);
1653
1654 if (zif->rtadv.AdvHomeAgentFlag)
1655 vty_out(vty, " ipv6 nd home-agent-config-flag\n");
1656
1657 if (zif->rtadv.AdvReachableTime)
1658 vty_out(vty, " ipv6 nd reachable-time %d\n",
1659 zif->rtadv.AdvReachableTime);
1660
1661 if (zif->rtadv.AdvManagedFlag)
1662 vty_out(vty, " ipv6 nd managed-config-flag\n");
1663
1664 if (zif->rtadv.AdvOtherConfigFlag)
1665 vty_out(vty, " ipv6 nd other-config-flag\n");
1666
1667 if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
1668 vty_out(vty, " ipv6 nd router-preference %s\n",
1669 rtadv_pref_strs[zif->rtadv.DefaultPreference]);
1670
1671 if (zif->rtadv.AdvLinkMTU)
1672 vty_out(vty, " ipv6 nd mtu %d\n", zif->rtadv.AdvLinkMTU);
1673
1674 for (ALL_LIST_ELEMENTS_RO(zif->rtadv.AdvPrefixList, node, rprefix)) {
1675 vty_out(vty, " ipv6 nd prefix %s",
1676 prefix2str(&rprefix->prefix, buf, sizeof(buf)));
1677 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME)
1678 || (rprefix->AdvPreferredLifetime
1679 != RTADV_PREFERRED_LIFETIME)) {
1680 if (rprefix->AdvValidLifetime == UINT32_MAX)
1681 vty_out(vty, " infinite");
1682 else
1683 vty_out(vty, " %u", rprefix->AdvValidLifetime);
1684 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1685 vty_out(vty, " infinite");
1686 else
1687 vty_out(vty, " %u",
1688 rprefix->AdvPreferredLifetime);
1689 }
1690 if (!rprefix->AdvOnLinkFlag)
1691 vty_out(vty, " off-link");
1692 if (!rprefix->AdvAutonomousFlag)
1693 vty_out(vty, " no-autoconfig");
1694 if (rprefix->AdvRouterAddressFlag)
1695 vty_out(vty, " router-address");
1696 vty_out(vty, "\n");
3e31cded 1697 }
2eb27eec 1698 return 0;
718e3744 1699}
1700
718e3744 1701
d62a17ae 1702static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
718e3744 1703{
d62a17ae 1704 struct rtadv *rtadv = &zns->rtadv;
1705
1706 switch (event) {
1707 case RTADV_START:
1708 thread_add_read(zebrad.master, rtadv_read, zns, val,
1709 &rtadv->ra_read);
1710 thread_add_event(zebrad.master, rtadv_timer, zns, 0,
1711 &rtadv->ra_timer);
1712 break;
1713 case RTADV_STOP:
1714 if (rtadv->ra_timer) {
1715 thread_cancel(rtadv->ra_timer);
1716 rtadv->ra_timer = NULL;
1717 }
1718 if (rtadv->ra_read) {
1719 thread_cancel(rtadv->ra_read);
1720 rtadv->ra_read = NULL;
1721 }
1722 break;
1723 case RTADV_TIMER:
1724 thread_add_timer(zebrad.master, rtadv_timer, zns, val,
1725 &rtadv->ra_timer);
1726 break;
1727 case RTADV_TIMER_MSEC:
1728 thread_add_timer_msec(zebrad.master, rtadv_timer, zns, val,
1729 &rtadv->ra_timer);
1730 break;
1731 case RTADV_READ:
1732 thread_add_read(zebrad.master, rtadv_read, zns, val,
1733 &rtadv->ra_read);
1734 break;
1735 default:
1736 break;
718e3744 1737 }
d62a17ae 1738 return;
718e3744 1739}
1740
d62a17ae 1741void rtadv_init(struct zebra_ns *zns)
718e3744 1742{
fe533c56 1743 zns->rtadv.sock = rtadv_make_socket(zns->ns_id);
cd80d74f 1744}
718e3744 1745
d62a17ae 1746void rtadv_terminate(struct zebra_ns *zns)
cd80d74f 1747{
d62a17ae 1748 rtadv_event(zns, RTADV_STOP, 0);
1749 if (zns->rtadv.sock >= 0) {
1750 close(zns->rtadv.sock);
1751 zns->rtadv.sock = -1;
1752 }
1753
1754 zns->rtadv.adv_if_count = 0;
1755 zns->rtadv.adv_msec_if_count = 0;
cd80d74f 1756}
718e3744 1757
d62a17ae 1758void rtadv_cmd_init(void)
cd80d74f 1759{
2eb27eec
DL
1760 hook_register(zebra_if_extra_info, nd_dump_vty);
1761 hook_register(zebra_if_config_wr, rtadv_config_write);
1762
d62a17ae 1763 install_element(INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1764 install_element(INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
1765 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
1766 install_element(INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
1767 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1768 install_element(INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1769 install_element(INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1770 install_element(INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1771 install_element(INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1772 install_element(INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1773 install_element(INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1774 install_element(INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1775 install_element(INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
1776 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
1777 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
1778 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
1779 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
1780 install_element(INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
1781 install_element(INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
1782 install_element(INTERFACE_NODE,
1783 &ipv6_nd_adv_interval_config_option_cmd);
1784 install_element(INTERFACE_NODE,
1785 &no_ipv6_nd_adv_interval_config_option_cmd);
1786 install_element(INTERFACE_NODE, &ipv6_nd_prefix_cmd);
1787 install_element(INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
1788 install_element(INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
1789 install_element(INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
1790 install_element(INTERFACE_NODE, &ipv6_nd_mtu_cmd);
1791 install_element(INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
718e3744 1792}
1793
d62a17ae 1794static int if_join_all_router(int sock, struct interface *ifp)
718e3744 1795{
d62a17ae 1796 int ret;
718e3744 1797
d62a17ae 1798 struct ipv6_mreq mreq;
718e3744 1799
d62a17ae 1800 memset(&mreq, 0, sizeof(struct ipv6_mreq));
1801 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1802 mreq.ipv6mr_interface = ifp->ifindex;
718e3744 1803
d62a17ae 1804 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq,
1805 sizeof mreq);
1806 if (ret < 0)
450971aa 1807 flog_err_sys(EC_LIB_SOCKET,
9df414fe
QY
1808 "%s(%u): Failed to join group, socket %u error %s",
1809 ifp->name, ifp->ifindex, sock,
1810 safe_strerror(errno));
718e3744 1811
d62a17ae 1812 if (IS_ZEBRA_DEBUG_EVENT)
1813 zlog_debug(
1814 "%s(%u): Join All-Routers multicast group, socket %u",
1815 ifp->name, ifp->ifindex, sock);
718e3744 1816
d62a17ae 1817 return 0;
718e3744 1818}
1819
d62a17ae 1820static int if_leave_all_router(int sock, struct interface *ifp)
718e3744 1821{
d62a17ae 1822 int ret;
718e3744 1823
d62a17ae 1824 struct ipv6_mreq mreq;
718e3744 1825
d62a17ae 1826 memset(&mreq, 0, sizeof(struct ipv6_mreq));
1827 inet_pton(AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1828 mreq.ipv6mr_interface = ifp->ifindex;
718e3744 1829
d62a17ae 1830 ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq,
1831 sizeof mreq);
1832 if (ret < 0)
9df414fe 1833 flog_err_sys(
450971aa 1834 EC_LIB_SOCKET,
9df414fe
QY
1835 "%s(%u): Failed to leave group, socket %u error %s",
1836 ifp->name, ifp->ifindex, sock, safe_strerror(errno));
718e3744 1837
d62a17ae 1838 if (IS_ZEBRA_DEBUG_EVENT)
1839 zlog_debug(
1840 "%s(%u): Leave All-Routers multicast group, socket %u",
1841 ifp->name, ifp->ifindex, sock);
718e3744 1842
d62a17ae 1843 return 0;
718e3744 1844}
1845
1846#else
d62a17ae 1847void rtadv_init(struct zebra_ns *zns)
cd80d74f 1848{
d62a17ae 1849 /* Empty.*/;
cd80d74f 1850}
d62a17ae 1851void rtadv_terminate(struct zebra_ns *zns)
cd80d74f 1852{
d62a17ae 1853 /* Empty.*/;
cd80d74f 1854}
d62a17ae 1855void rtadv_cmd_init(void)
718e3744 1856{
d62a17ae 1857 /* Empty.*/;
718e3744 1858}
56c1f7d8 1859#endif /* HAVE_RTADV */