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