1 /* Router advertisement
2 * Copyright (C) 2016 Cumulus Networks
3 * Copyright (C) 2005 6WIND <jean-mickael.guerin@6wind.com>
4 * Copyright (C) 1999 Kunihiro Ishiguro
6 * This file is part of GNU Zebra.
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
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.
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
26 #include "zebra_memory.h"
38 #include "zebra/interface.h"
39 #include "zebra/rtadv.h"
40 #include "zebra/debug.h"
41 #include "zebra/rib.h"
42 #include "zebra/zserv.h"
43 #include "zebra/zebra_ns.h"
44 #include "zebra/zebra_vrf.h"
46 extern struct zebra_privs_t zserv_privs
;
48 #if defined(HAVE_RTADV)
51 #include <netinet/icmp6.h>
54 /* If RFC2133 definition is used. */
55 #ifndef IPV6_JOIN_GROUP
56 #define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
58 #ifndef IPV6_LEAVE_GROUP
59 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
62 #define ALLNODE "ff02::1"
63 #define ALLROUTER "ff02::2"
73 static void rtadv_event(struct zebra_ns
*, enum rtadv_event
, int);
75 static int if_join_all_router(int, struct interface
*);
76 static int if_leave_all_router(int, struct interface
*);
78 static int rtadv_increment_received(struct zebra_ns
*zns
, ifindex_t
*ifindex
)
81 struct interface
*iface
;
84 iface
= if_lookup_by_index_per_ns(zns
, *ifindex
);
85 if (iface
&& iface
->info
) {
93 static int rtadv_recv_packet(struct zebra_ns
*zns
, int sock
, u_char
*buf
,
94 int buflen
, struct sockaddr_in6
*from
,
95 ifindex_t
*ifindex
, int *hoplimit
)
100 struct cmsghdr
*cmsgptr
;
105 /* Fill in message and iovec. */
106 msg
.msg_name
= (void *)from
;
107 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
110 msg
.msg_control
= (void *)adata
;
111 msg
.msg_controllen
= sizeof adata
;
113 iov
.iov_len
= buflen
;
115 /* If recvmsg fail return minus value. */
116 ret
= recvmsg(sock
, &msg
, 0);
120 for (cmsgptr
= ZCMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
;
121 cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
122 /* I want interface index which this packet comes from. */
123 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
124 && cmsgptr
->cmsg_type
== IPV6_PKTINFO
) {
125 struct in6_pktinfo
*ptr
;
127 ptr
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
128 *ifindex
= ptr
->ipi6_ifindex
;
129 memcpy(&dst
, &ptr
->ipi6_addr
, sizeof(ptr
->ipi6_addr
));
132 /* Incoming packet's hop limit. */
133 if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
134 && cmsgptr
->cmsg_type
== IPV6_HOPLIMIT
) {
135 int *hoptr
= (int *)CMSG_DATA(cmsgptr
);
140 rtadv_increment_received(zns
, ifindex
);
144 #define RTADV_MSG_SIZE 4096
146 /* Send router advertisement packet. */
147 static void rtadv_send_packet(int sock
, struct interface
*ifp
)
151 struct cmsghdr
*cmsgptr
;
152 struct in6_pktinfo
*pkt
;
153 struct sockaddr_in6 addr
;
154 static void *adata
= NULL
;
155 unsigned char buf
[RTADV_MSG_SIZE
];
156 struct nd_router_advert
*rtadv
;
159 struct zebra_if
*zif
;
160 struct rtadv_prefix
*rprefix
;
161 u_char all_nodes_addr
[] = {0xff, 0x02, 0, 0, 0, 0, 0, 0,
162 0, 0, 0, 0, 0, 0, 0, 1};
163 struct listnode
*node
;
164 u_int16_t pkt_RouterLifetime
;
167 * Allocate control message bufffer. This is dynamic because
168 * CMSG_SPACE is not guaranteed not to call a function. Note that
169 * the size will be different on different architectures due to
170 * differing alignment rules.
173 /* XXX Free on shutdown. */
174 adata
= malloc(CMSG_SPACE(sizeof(struct in6_pktinfo
)));
178 "rtadv_send_packet: can't malloc control data");
181 /* Logging of packet. */
182 if (IS_ZEBRA_DEBUG_PACKET
)
183 zlog_debug("%s(%u): Tx RA, socket %u", ifp
->name
, ifp
->ifindex
,
186 /* Fill in sockaddr_in6. */
187 memset(&addr
, 0, sizeof(struct sockaddr_in6
));
188 addr
.sin6_family
= AF_INET6
;
190 addr
.sin6_len
= sizeof(struct sockaddr_in6
);
191 #endif /* SIN6_LEN */
192 addr
.sin6_port
= htons(IPPROTO_ICMPV6
);
193 IPV6_ADDR_COPY(&addr
.sin6_addr
, all_nodes_addr
);
195 /* Fetch interface information. */
198 /* Make router advertisement message. */
199 rtadv
= (struct nd_router_advert
*)buf
;
201 rtadv
->nd_ra_type
= ND_ROUTER_ADVERT
;
202 rtadv
->nd_ra_code
= 0;
203 rtadv
->nd_ra_cksum
= 0;
205 rtadv
->nd_ra_curhoplimit
= 64;
207 /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
208 rtadv
->nd_ra_flags_reserved
= zif
->rtadv
.AdvDefaultLifetime
== 0
210 : zif
->rtadv
.DefaultPreference
;
211 rtadv
->nd_ra_flags_reserved
<<= 3;
213 if (zif
->rtadv
.AdvManagedFlag
)
214 rtadv
->nd_ra_flags_reserved
|= ND_RA_FLAG_MANAGED
;
215 if (zif
->rtadv
.AdvOtherConfigFlag
)
216 rtadv
->nd_ra_flags_reserved
|= ND_RA_FLAG_OTHER
;
217 if (zif
->rtadv
.AdvHomeAgentFlag
)
218 rtadv
->nd_ra_flags_reserved
|= ND_RA_FLAG_HOME_AGENT
;
219 /* Note that according to Neighbor Discovery (RFC 4861 [18]),
220 * AdvDefaultLifetime is by default based on the value of
221 * MaxRtrAdvInterval. AdvDefaultLifetime is used in the Router Lifetime
222 * field of Router Advertisements. Given that this field is expressed
223 * in seconds, a small MaxRtrAdvInterval value can result in a zero
224 * value for this field. To prevent this, routers SHOULD keep
225 * AdvDefaultLifetime in at least one second, even if the use of
226 * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */
228 zif
->rtadv
.AdvDefaultLifetime
!= -1
229 ? zif
->rtadv
.AdvDefaultLifetime
230 : MAX(1, 0.003 * zif
->rtadv
.MaxRtrAdvInterval
);
231 rtadv
->nd_ra_router_lifetime
= htons(pkt_RouterLifetime
);
232 rtadv
->nd_ra_reachable
= htonl(zif
->rtadv
.AdvReachableTime
);
233 rtadv
->nd_ra_retransmit
= htonl(0);
235 len
= sizeof(struct nd_router_advert
);
237 /* If both the Home Agent Preference and Home Agent Lifetime are set to
238 * their default values specified above, this option SHOULD NOT be
239 * included in the Router Advertisement messages sent by this home
240 * agent. -- RFC6275, 7.4 */
241 if (zif
->rtadv
.AdvHomeAgentFlag
242 && (zif
->rtadv
.HomeAgentPreference
243 || zif
->rtadv
.HomeAgentLifetime
!= -1)) {
244 struct nd_opt_homeagent_info
*ndopt_hai
=
245 (struct nd_opt_homeagent_info
*)(buf
+ len
);
246 ndopt_hai
->nd_opt_hai_type
= ND_OPT_HA_INFORMATION
;
247 ndopt_hai
->nd_opt_hai_len
= 1;
248 ndopt_hai
->nd_opt_hai_reserved
= 0;
249 ndopt_hai
->nd_opt_hai_preference
=
250 htons(zif
->rtadv
.HomeAgentPreference
);
251 /* 16-bit unsigned integer. The lifetime associated with the
253 * agent in units of seconds. The default value is the same as
255 * Router Lifetime, as specified in the main body of the Router
256 * Advertisement. The maximum value corresponds to 18.2 hours.
258 * value of 0 MUST NOT be used. -- RFC6275, 7.5 */
259 ndopt_hai
->nd_opt_hai_lifetime
=
260 htons(zif
->rtadv
.HomeAgentLifetime
!= -1
261 ? zif
->rtadv
.HomeAgentLifetime
262 : MAX(1, pkt_RouterLifetime
) /* 0 is OK
267 len
+= sizeof(struct nd_opt_homeagent_info
);
270 if (zif
->rtadv
.AdvIntervalOption
) {
271 struct nd_opt_adv_interval
*ndopt_adv
=
272 (struct nd_opt_adv_interval
*)(buf
+ len
);
273 ndopt_adv
->nd_opt_ai_type
= ND_OPT_ADV_INTERVAL
;
274 ndopt_adv
->nd_opt_ai_len
= 1;
275 ndopt_adv
->nd_opt_ai_reserved
= 0;
276 ndopt_adv
->nd_opt_ai_interval
=
277 htonl(zif
->rtadv
.MaxRtrAdvInterval
);
278 len
+= sizeof(struct nd_opt_adv_interval
);
281 /* Fill in prefix. */
282 for (ALL_LIST_ELEMENTS_RO(zif
->rtadv
.AdvPrefixList
, node
, rprefix
)) {
283 struct nd_opt_prefix_info
*pinfo
;
285 pinfo
= (struct nd_opt_prefix_info
*)(buf
+ len
);
287 pinfo
->nd_opt_pi_type
= ND_OPT_PREFIX_INFORMATION
;
288 pinfo
->nd_opt_pi_len
= 4;
289 pinfo
->nd_opt_pi_prefix_len
= rprefix
->prefix
.prefixlen
;
291 pinfo
->nd_opt_pi_flags_reserved
= 0;
292 if (rprefix
->AdvOnLinkFlag
)
293 pinfo
->nd_opt_pi_flags_reserved
|=
294 ND_OPT_PI_FLAG_ONLINK
;
295 if (rprefix
->AdvAutonomousFlag
)
296 pinfo
->nd_opt_pi_flags_reserved
|= ND_OPT_PI_FLAG_AUTO
;
297 if (rprefix
->AdvRouterAddressFlag
)
298 pinfo
->nd_opt_pi_flags_reserved
|= ND_OPT_PI_FLAG_RADDR
;
300 pinfo
->nd_opt_pi_valid_time
= htonl(rprefix
->AdvValidLifetime
);
301 pinfo
->nd_opt_pi_preferred_time
=
302 htonl(rprefix
->AdvPreferredLifetime
);
303 pinfo
->nd_opt_pi_reserved2
= 0;
305 IPV6_ADDR_COPY(&pinfo
->nd_opt_pi_prefix
,
306 &rprefix
->prefix
.prefix
);
310 u_char buf
[INET6_ADDRSTRLEN
];
312 zlog_debug("DEBUG %s",
313 inet_ntop(AF_INET6
, &pinfo
->nd_opt_pi_prefix
,
314 buf
, INET6_ADDRSTRLEN
));
318 len
+= sizeof(struct nd_opt_prefix_info
);
321 /* Hardware address. */
322 if (ifp
->hw_addr_len
!= 0) {
323 buf
[len
++] = ND_OPT_SOURCE_LINKADDR
;
325 /* Option length should be rounded up to next octet if
326 the link address does not end on an octet boundary. */
327 buf
[len
++] = (ifp
->hw_addr_len
+ 9) >> 3;
329 memcpy(buf
+ len
, ifp
->hw_addr
, ifp
->hw_addr_len
);
330 len
+= ifp
->hw_addr_len
;
332 /* Pad option to end on an octet boundary. */
333 memset(buf
+ len
, 0, -(ifp
->hw_addr_len
+ 2) & 0x7);
334 len
+= -(ifp
->hw_addr_len
+ 2) & 0x7;
338 if (zif
->rtadv
.AdvLinkMTU
) {
339 struct nd_opt_mtu
*opt
= (struct nd_opt_mtu
*)(buf
+ len
);
340 opt
->nd_opt_mtu_type
= ND_OPT_MTU
;
341 opt
->nd_opt_mtu_len
= 1;
342 opt
->nd_opt_mtu_reserved
= 0;
343 opt
->nd_opt_mtu_mtu
= htonl(zif
->rtadv
.AdvLinkMTU
);
344 len
+= sizeof(struct nd_opt_mtu
);
347 msg
.msg_name
= (void *)&addr
;
348 msg
.msg_namelen
= sizeof(struct sockaddr_in6
);
351 msg
.msg_control
= (void *)adata
;
352 msg
.msg_controllen
= CMSG_SPACE(sizeof(struct in6_pktinfo
));
357 cmsgptr
= ZCMSG_FIRSTHDR(&msg
);
358 cmsgptr
->cmsg_len
= CMSG_LEN(sizeof(struct in6_pktinfo
));
359 cmsgptr
->cmsg_level
= IPPROTO_IPV6
;
360 cmsgptr
->cmsg_type
= IPV6_PKTINFO
;
362 pkt
= (struct in6_pktinfo
*)CMSG_DATA(cmsgptr
);
363 memset(&pkt
->ipi6_addr
, 0, sizeof(struct in6_addr
));
364 pkt
->ipi6_ifindex
= ifp
->ifindex
;
366 ret
= sendmsg(sock
, &msg
, 0);
368 zlog_err("%s(%u): Tx RA failed, socket %u error %d (%s)",
369 ifp
->name
, ifp
->ifindex
, sock
, errno
,
370 safe_strerror(errno
));
375 static int rtadv_timer(struct thread
*thread
)
377 struct zebra_ns
*zns
= THREAD_ARG(thread
);
379 struct listnode
*node
, *nnode
;
380 struct interface
*ifp
;
381 struct zebra_if
*zif
;
384 zns
->rtadv
.ra_timer
= NULL
;
385 if (zns
->rtadv
.adv_msec_if_count
== 0) {
386 period
= 1000; /* 1 s */
387 rtadv_event(zns
, RTADV_TIMER
, 1 /* 1 s */);
389 period
= 10; /* 10 ms */
390 rtadv_event(zns
, RTADV_TIMER_MSEC
, 10 /* 10 ms */);
393 RB_FOREACH(vrf
, vrf_id_head
, &vrfs_by_id
)
394 for (ALL_LIST_ELEMENTS(vrf
->iflist
, node
, nnode
, ifp
)) {
395 if (if_is_loopback(ifp
)
396 || CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_VRF_LOOPBACK
)
397 || !if_is_operative(ifp
))
402 if (zif
->rtadv
.AdvSendAdvertisements
) {
403 if (zif
->rtadv
.inFastRexmit
) {
404 /* We assume we fast rexmit every sec so no
406 if (--zif
->rtadv
.NumFastReXmitsRemain
<= 0)
407 zif
->rtadv
.inFastRexmit
= 0;
409 if (IS_ZEBRA_DEBUG_SEND
)
411 "Fast RA Rexmit on interface %s",
414 rtadv_send_packet(zns
->rtadv
.sock
, ifp
);
416 zif
->rtadv
.AdvIntervalTimer
-= period
;
417 if (zif
->rtadv
.AdvIntervalTimer
<= 0) {
418 /* FIXME: using MaxRtrAdvInterval each
419 time isn't what section
420 6.2.4 of RFC4861 tells to do. */
421 zif
->rtadv
.AdvIntervalTimer
=
422 zif
->rtadv
.MaxRtrAdvInterval
;
423 rtadv_send_packet(zns
->rtadv
.sock
, ifp
);
432 static void rtadv_process_solicit(struct interface
*ifp
)
434 struct zebra_vrf
*zvrf
= vrf_info_lookup(ifp
->vrf_id
);
435 struct zebra_ns
*zns
= zvrf
->zns
;
438 rtadv_send_packet(zns
->rtadv
.sock
, ifp
);
441 static void rtadv_process_advert(u_char
*msg
, unsigned int len
,
442 struct interface
*ifp
,
443 struct sockaddr_in6
*addr
)
445 struct nd_router_advert
*radvert
;
446 char addr_str
[INET6_ADDRSTRLEN
];
447 struct zebra_if
*zif
;
452 inet_ntop(AF_INET6
, &addr
->sin6_addr
, addr_str
, INET6_ADDRSTRLEN
);
454 if (len
< sizeof(struct nd_router_advert
)) {
455 zlog_warn("%s(%u): Rx RA with invalid length %d from %s",
456 ifp
->name
, ifp
->ifindex
, len
, addr_str
);
459 if (!IN6_IS_ADDR_LINKLOCAL(&addr
->sin6_addr
)) {
461 "%s(%u): Rx RA with non-linklocal source address from %s",
462 ifp
->name
, ifp
->ifindex
, addr_str
);
466 radvert
= (struct nd_router_advert
*)msg
;
468 if ((radvert
->nd_ra_curhoplimit
&& zif
->rtadv
.AdvCurHopLimit
)
469 && (radvert
->nd_ra_curhoplimit
!= zif
->rtadv
.AdvCurHopLimit
)) {
471 "%s(%u): Rx RA - our AdvCurHopLimit doesn't agree with %s",
472 ifp
->name
, ifp
->ifindex
, addr_str
);
475 if ((radvert
->nd_ra_flags_reserved
& ND_RA_FLAG_MANAGED
)
476 && !zif
->rtadv
.AdvManagedFlag
) {
478 "%s(%u): Rx RA - our AdvManagedFlag doesn't agree with %s",
479 ifp
->name
, ifp
->ifindex
, addr_str
);
482 if ((radvert
->nd_ra_flags_reserved
& ND_RA_FLAG_OTHER
)
483 && !zif
->rtadv
.AdvOtherConfigFlag
) {
485 "%s(%u): Rx RA - our AdvOtherConfigFlag doesn't agree with %s",
486 ifp
->name
, ifp
->ifindex
, addr_str
);
489 if ((radvert
->nd_ra_reachable
&& zif
->rtadv
.AdvReachableTime
)
490 && (ntohl(radvert
->nd_ra_reachable
)
491 != zif
->rtadv
.AdvReachableTime
)) {
493 "%s(%u): Rx RA - our AdvReachableTime doesn't agree with %s",
494 ifp
->name
, ifp
->ifindex
, addr_str
);
497 if ((radvert
->nd_ra_retransmit
&& zif
->rtadv
.AdvRetransTimer
)
498 && (ntohl(radvert
->nd_ra_retransmit
)
499 != (unsigned int)zif
->rtadv
.AdvRetransTimer
)) {
501 "%s(%u): Rx RA - our AdvRetransTimer doesn't agree with %s",
502 ifp
->name
, ifp
->ifindex
, addr_str
);
505 /* Create entry for neighbor if not known. */
507 IPV6_ADDR_COPY(&p
.u
.prefix
, &addr
->sin6_addr
);
508 p
.prefixlen
= IPV6_MAX_PREFIXLEN
;
510 if (!nbr_connected_check(ifp
, &p
))
511 nbr_connected_add_ipv6(ifp
, &addr
->sin6_addr
);
515 static void rtadv_process_packet(u_char
*buf
, unsigned int len
,
516 ifindex_t ifindex
, int hoplimit
,
517 struct sockaddr_in6
*from
,
518 struct zebra_ns
*zns
)
520 struct icmp6_hdr
*icmph
;
521 struct interface
*ifp
;
522 struct zebra_if
*zif
;
523 char addr_str
[INET6_ADDRSTRLEN
];
525 inet_ntop(AF_INET6
, &from
->sin6_addr
, addr_str
, INET6_ADDRSTRLEN
);
527 /* Interface search. */
528 ifp
= if_lookup_by_index_per_ns(zns
, ifindex
);
530 zlog_warn("RA/RS received on unknown IF %u from %s", ifindex
,
535 if (IS_ZEBRA_DEBUG_PACKET
)
536 zlog_debug("%s(%u): Rx RA/RS len %d from %s", ifp
->name
,
537 ifp
->ifindex
, len
, addr_str
);
539 if (if_is_loopback(ifp
)
540 || CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_VRF_LOOPBACK
))
543 /* Check interface configuration. */
545 if (!zif
->rtadv
.AdvSendAdvertisements
)
548 /* ICMP message length check. */
549 if (len
< sizeof(struct icmp6_hdr
)) {
550 zlog_warn("%s(%u): Rx RA with Invalid ICMPV6 packet length %d",
551 ifp
->name
, ifp
->ifindex
, len
);
555 icmph
= (struct icmp6_hdr
*)buf
;
557 /* ICMP message type check. */
558 if (icmph
->icmp6_type
!= ND_ROUTER_SOLICIT
559 && icmph
->icmp6_type
!= ND_ROUTER_ADVERT
) {
560 zlog_warn("%s(%u): Rx RA - Unwanted ICMPV6 message type %d",
561 ifp
->name
, ifp
->ifindex
, icmph
->icmp6_type
);
565 /* Hoplimit check. */
566 if (hoplimit
>= 0 && hoplimit
!= 255) {
567 zlog_warn("%s(%u): Rx RA - Invalid hoplimit %d", ifp
->name
,
568 ifp
->ifindex
, hoplimit
);
572 /* Check ICMP message type. */
573 if (icmph
->icmp6_type
== ND_ROUTER_SOLICIT
)
574 rtadv_process_solicit(ifp
);
575 else if (icmph
->icmp6_type
== ND_ROUTER_ADVERT
)
576 rtadv_process_advert(buf
, len
, ifp
, from
);
581 static int rtadv_read(struct thread
*thread
)
585 u_char buf
[RTADV_MSG_SIZE
];
586 struct sockaddr_in6 from
;
587 ifindex_t ifindex
= 0;
589 struct zebra_ns
*zns
= THREAD_ARG(thread
);
591 sock
= THREAD_FD(thread
);
592 zns
->rtadv
.ra_read
= NULL
;
594 /* Register myself. */
595 rtadv_event(zns
, RTADV_READ
, sock
);
597 len
= rtadv_recv_packet(zns
, sock
, buf
, sizeof(buf
), &from
, &ifindex
,
601 zlog_warn("RA/RS recv failed, socket %u error %s", sock
,
602 safe_strerror(errno
));
606 rtadv_process_packet(buf
, (unsigned)len
, ifindex
, hoplimit
, &from
, zns
);
611 static int rtadv_make_socket(void)
615 struct icmp6_filter filter
;
617 if (zserv_privs
.change(ZPRIVS_RAISE
))
618 zlog_err("rtadv_make_socket: could not raise privs, %s",
619 safe_strerror(errno
));
621 sock
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
623 if (zserv_privs
.change(ZPRIVS_LOWER
))
624 zlog_err("rtadv_make_socket: could not lower privs, %s",
625 safe_strerror(errno
));
632 ret
= setsockopt_ipv6_pktinfo(sock
, 1);
637 ret
= setsockopt_ipv6_multicast_loop(sock
, 0);
642 ret
= setsockopt_ipv6_unicast_hops(sock
, 255);
647 ret
= setsockopt_ipv6_multicast_hops(sock
, 255);
652 ret
= setsockopt_ipv6_hoplimit(sock
, 1);
658 ICMP6_FILTER_SETBLOCKALL(&filter
);
659 ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT
, &filter
);
660 ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT
, &filter
);
662 ret
= setsockopt(sock
, IPPROTO_ICMPV6
, ICMP6_FILTER
, &filter
,
663 sizeof(struct icmp6_filter
));
665 zlog_info("ICMP6_FILTER set fail: %s", safe_strerror(errno
));
672 static struct rtadv_prefix
*rtadv_prefix_new(void)
674 return XCALLOC(MTYPE_RTADV_PREFIX
, sizeof(struct rtadv_prefix
));
677 static void rtadv_prefix_free(struct rtadv_prefix
*rtadv_prefix
)
679 XFREE(MTYPE_RTADV_PREFIX
, rtadv_prefix
);
682 static struct rtadv_prefix
*rtadv_prefix_lookup(struct list
*rplist
,
683 struct prefix_ipv6
*p
)
685 struct listnode
*node
;
686 struct rtadv_prefix
*rprefix
;
688 for (ALL_LIST_ELEMENTS_RO(rplist
, node
, rprefix
))
689 if (prefix_same((struct prefix
*)&rprefix
->prefix
,
695 static struct rtadv_prefix
*rtadv_prefix_get(struct list
*rplist
,
696 struct prefix_ipv6
*p
)
698 struct rtadv_prefix
*rprefix
;
700 rprefix
= rtadv_prefix_lookup(rplist
, p
);
704 rprefix
= rtadv_prefix_new();
705 memcpy(&rprefix
->prefix
, p
, sizeof(struct prefix_ipv6
));
706 listnode_add(rplist
, rprefix
);
711 static void rtadv_prefix_set(struct zebra_if
*zif
, struct rtadv_prefix
*rp
)
713 struct rtadv_prefix
*rprefix
;
715 rprefix
= rtadv_prefix_get(zif
->rtadv
.AdvPrefixList
, &rp
->prefix
);
717 /* Set parameters. */
718 rprefix
->AdvValidLifetime
= rp
->AdvValidLifetime
;
719 rprefix
->AdvPreferredLifetime
= rp
->AdvPreferredLifetime
;
720 rprefix
->AdvOnLinkFlag
= rp
->AdvOnLinkFlag
;
721 rprefix
->AdvAutonomousFlag
= rp
->AdvAutonomousFlag
;
722 rprefix
->AdvRouterAddressFlag
= rp
->AdvRouterAddressFlag
;
725 static int rtadv_prefix_reset(struct zebra_if
*zif
, struct rtadv_prefix
*rp
)
727 struct rtadv_prefix
*rprefix
;
729 rprefix
= rtadv_prefix_lookup(zif
->rtadv
.AdvPrefixList
, &rp
->prefix
);
730 if (rprefix
!= NULL
) {
731 listnode_delete(zif
->rtadv
.AdvPrefixList
, (void *)rprefix
);
732 rtadv_prefix_free(rprefix
);
738 static void ipv6_nd_suppress_ra_set(struct interface
*ifp
,
739 ipv6_nd_suppress_ra_status status
)
741 struct zebra_if
*zif
;
742 struct zebra_vrf
*zvrf
;
743 struct zebra_ns
*zns
;
746 zvrf
= vrf_info_lookup(ifp
->vrf_id
);
749 if (status
== RA_SUPPRESS
) {
750 /* RA is currently enabled */
751 if (zif
->rtadv
.AdvSendAdvertisements
) {
752 zif
->rtadv
.AdvSendAdvertisements
= 0;
753 zif
->rtadv
.AdvIntervalTimer
= 0;
754 zns
->rtadv
.adv_if_count
--;
756 if_leave_all_router(zns
->rtadv
.sock
, ifp
);
758 if (zns
->rtadv
.adv_if_count
== 0)
759 rtadv_event(zns
, RTADV_STOP
, 0);
762 if (!zif
->rtadv
.AdvSendAdvertisements
) {
763 zif
->rtadv
.AdvSendAdvertisements
= 1;
764 zif
->rtadv
.AdvIntervalTimer
= 0;
765 zns
->rtadv
.adv_if_count
++;
767 if (zif
->rtadv
.MaxRtrAdvInterval
>= 1000) {
768 /* Enable Fast RA only when RA interval is in
770 zif
->rtadv
.inFastRexmit
= 1;
771 zif
->rtadv
.NumFastReXmitsRemain
=
772 RTADV_NUM_FAST_REXMITS
;
775 if_join_all_router(zns
->rtadv
.sock
, ifp
);
777 if (zns
->rtadv
.adv_if_count
== 1)
778 rtadv_event(zns
, RTADV_START
, zns
->rtadv
.sock
);
784 * Handle client (BGP) message to enable or disable IPv6 RA on an interface.
785 * Note that while the client could request RA on an interface on which the
786 * operator has not enabled RA, RA won't be disabled upon client request
787 * if the operator has explicitly enabled RA. The enable request can also
788 * specify a RA interval (in seconds).
790 void zebra_interface_radv_set(struct zserv
*client
, int sock
, u_short length
,
791 struct zebra_vrf
*zvrf
, int enable
)
794 unsigned int ifindex
;
795 struct interface
*ifp
;
796 struct zebra_if
*zif
;
801 /* Get interface index and RA interval. */
802 ifindex
= stream_getl(s
);
803 ra_interval
= stream_getl(s
);
805 if (IS_ZEBRA_DEBUG_EVENT
)
806 zlog_debug("%u: IF %u RA %s from client %s, interval %ds",
807 zvrf_id(zvrf
), ifindex
,
808 enable
? "enable" : "disable",
809 zebra_route_string(client
->proto
), ra_interval
);
811 /* Locate interface and check VRF match. */
812 ifp
= if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT
), ifindex
);
814 zlog_warn("%u: IF %u RA %s client %s - interface unknown",
815 zvrf_id(zvrf
), ifindex
, enable
? "enable" : "disable",
816 zebra_route_string(client
->proto
));
819 if (ifp
->vrf_id
!= zvrf_id(zvrf
)) {
820 zlog_warn("%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u",
821 zvrf_id(zvrf
), ifindex
, enable
? "enable" : "disable",
822 zebra_route_string(client
->proto
), ifp
->vrf_id
);
828 ipv6_nd_suppress_ra_set(ifp
, RA_ENABLE
);
830 && (ra_interval
* 1000) < zif
->rtadv
.MaxRtrAdvInterval
)
831 zif
->rtadv
.MaxRtrAdvInterval
= ra_interval
* 1000;
833 if (!zif
->rtadv
.configured
) {
834 zif
->rtadv
.MaxRtrAdvInterval
=
835 RTADV_MAX_RTR_ADV_INTERVAL
;
836 ipv6_nd_suppress_ra_set(ifp
, RA_SUPPRESS
);
841 DEFUN (ipv6_nd_suppress_ra
,
842 ipv6_nd_suppress_ra_cmd
,
843 "ipv6 nd suppress-ra",
844 "Interface IPv6 config commands\n"
845 "Neighbor discovery\n"
846 "Suppress Router Advertisement\n")
848 VTY_DECLVAR_CONTEXT(interface
, ifp
);
849 struct zebra_if
*zif
= ifp
->info
;
851 if (if_is_loopback(ifp
)
852 || CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_VRF_LOOPBACK
)) {
854 "Cannot configure IPv6 Router Advertisements on this interface\n");
855 return CMD_WARNING_CONFIG_FAILED
;
858 ipv6_nd_suppress_ra_set(ifp
, RA_SUPPRESS
);
859 zif
->rtadv
.configured
= 0;
863 DEFUN (no_ipv6_nd_suppress_ra
,
864 no_ipv6_nd_suppress_ra_cmd
,
865 "no ipv6 nd suppress-ra",
867 "Interface IPv6 config commands\n"
868 "Neighbor discovery\n"
869 "Suppress Router Advertisement\n")
871 VTY_DECLVAR_CONTEXT(interface
, ifp
);
872 struct zebra_if
*zif
= ifp
->info
;
874 if (if_is_loopback(ifp
)
875 || CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_VRF_LOOPBACK
)) {
877 "Cannot configure IPv6 Router Advertisements on this interface\n");
878 return CMD_WARNING_CONFIG_FAILED
;
881 ipv6_nd_suppress_ra_set(ifp
, RA_ENABLE
);
882 zif
->rtadv
.configured
= 1;
886 DEFUN (ipv6_nd_ra_interval_msec
,
887 ipv6_nd_ra_interval_msec_cmd
,
888 "ipv6 nd ra-interval msec (70-1800000)",
889 "Interface IPv6 config commands\n"
890 "Neighbor discovery\n"
891 "Router Advertisement interval\n"
892 "Router Advertisement interval in milliseconds\n"
893 "Router Advertisement interval in milliseconds\n")
896 VTY_DECLVAR_CONTEXT(interface
, ifp
);
898 struct zebra_if
*zif
= ifp
->info
;
899 struct zebra_vrf
*zvrf
= vrf_info_lookup(ifp
->vrf_id
);
900 struct zebra_ns
*zns
;
903 interval
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
904 if ((zif
->rtadv
.AdvDefaultLifetime
!= -1
905 && interval
> (unsigned)zif
->rtadv
.AdvDefaultLifetime
* 1000)) {
907 "This ra-interval would conflict with configured ra-lifetime!\n");
908 return CMD_WARNING_CONFIG_FAILED
;
911 if (zif
->rtadv
.MaxRtrAdvInterval
% 1000)
912 zns
->rtadv
.adv_msec_if_count
--;
915 zns
->rtadv
.adv_msec_if_count
++;
917 zif
->rtadv
.MaxRtrAdvInterval
= interval
;
918 zif
->rtadv
.MinRtrAdvInterval
= 0.33 * interval
;
919 zif
->rtadv
.AdvIntervalTimer
= 0;
924 DEFUN (ipv6_nd_ra_interval
,
925 ipv6_nd_ra_interval_cmd
,
926 "ipv6 nd ra-interval (1-1800)",
927 "Interface IPv6 config commands\n"
928 "Neighbor discovery\n"
929 "Router Advertisement interval\n"
930 "Router Advertisement interval in seconds\n")
933 VTY_DECLVAR_CONTEXT(interface
, ifp
);
935 struct zebra_if
*zif
= ifp
->info
;
936 struct zebra_vrf
*zvrf
= vrf_info_lookup(ifp
->vrf_id
);
937 struct zebra_ns
*zns
;
940 interval
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
941 if ((zif
->rtadv
.AdvDefaultLifetime
!= -1
942 && interval
> (unsigned)zif
->rtadv
.AdvDefaultLifetime
)) {
944 "This ra-interval would conflict with configured ra-lifetime!\n");
945 return CMD_WARNING_CONFIG_FAILED
;
948 if (zif
->rtadv
.MaxRtrAdvInterval
% 1000)
949 zns
->rtadv
.adv_msec_if_count
--;
951 /* convert to milliseconds */
952 interval
= interval
* 1000;
954 zif
->rtadv
.MaxRtrAdvInterval
= interval
;
955 zif
->rtadv
.MinRtrAdvInterval
= 0.33 * interval
;
956 zif
->rtadv
.AdvIntervalTimer
= 0;
961 DEFUN (no_ipv6_nd_ra_interval
,
962 no_ipv6_nd_ra_interval_cmd
,
963 "no ipv6 nd ra-interval [<(1-1800)|msec (1-1800000)>]",
965 "Interface IPv6 config commands\n"
966 "Neighbor discovery\n"
967 "Router Advertisement interval\n"
968 "Router Advertisement interval in seconds\n"
969 "Specify millisecond router advertisement interval\n"
970 "Router Advertisement interval in milliseconds\n")
972 VTY_DECLVAR_CONTEXT(interface
, ifp
);
973 struct zebra_if
*zif
= ifp
->info
;
974 struct zebra_vrf
*zvrf
;
975 struct zebra_ns
*zns
;
977 zvrf
= vrf_info_lookup(ifp
->vrf_id
);
980 if (zif
->rtadv
.MaxRtrAdvInterval
% 1000)
981 zns
->rtadv
.adv_msec_if_count
--;
983 zif
->rtadv
.MaxRtrAdvInterval
= RTADV_MAX_RTR_ADV_INTERVAL
;
984 zif
->rtadv
.MinRtrAdvInterval
= RTADV_MIN_RTR_ADV_INTERVAL
;
985 zif
->rtadv
.AdvIntervalTimer
= zif
->rtadv
.MaxRtrAdvInterval
;
990 DEFUN (ipv6_nd_ra_lifetime
,
991 ipv6_nd_ra_lifetime_cmd
,
992 "ipv6 nd ra-lifetime (0-9000)",
993 "Interface IPv6 config commands\n"
994 "Neighbor discovery\n"
996 "Router lifetime in seconds (0 stands for a non-default gw)\n")
999 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1000 struct zebra_if
*zif
= ifp
->info
;
1003 lifetime
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
1005 /* The value to be placed in the Router Lifetime field
1006 * of Router Advertisements sent from the interface,
1007 * in seconds. MUST be either zero or between
1008 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
1009 if ((lifetime
!= 0 && lifetime
* 1000 < zif
->rtadv
.MaxRtrAdvInterval
)) {
1011 "This ra-lifetime would conflict with configured ra-interval\n");
1012 return CMD_WARNING_CONFIG_FAILED
;
1015 zif
->rtadv
.AdvDefaultLifetime
= lifetime
;
1020 DEFUN (no_ipv6_nd_ra_lifetime
,
1021 no_ipv6_nd_ra_lifetime_cmd
,
1022 "no ipv6 nd ra-lifetime [(0-9000)]",
1024 "Interface IPv6 config commands\n"
1025 "Neighbor discovery\n"
1027 "Router lifetime in seconds (0 stands for a non-default gw)\n")
1029 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1030 struct zebra_if
*zif
= ifp
->info
;
1032 zif
->rtadv
.AdvDefaultLifetime
= -1;
1037 DEFUN (ipv6_nd_reachable_time
,
1038 ipv6_nd_reachable_time_cmd
,
1039 "ipv6 nd reachable-time (1-3600000)",
1040 "Interface IPv6 config commands\n"
1041 "Neighbor discovery\n"
1043 "Reachable time in milliseconds\n")
1046 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1047 struct zebra_if
*zif
= ifp
->info
;
1048 zif
->rtadv
.AdvReachableTime
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
1052 DEFUN (no_ipv6_nd_reachable_time
,
1053 no_ipv6_nd_reachable_time_cmd
,
1054 "no ipv6 nd reachable-time [(1-3600000)]",
1056 "Interface IPv6 config commands\n"
1057 "Neighbor discovery\n"
1059 "Reachable time in milliseconds\n")
1061 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1062 struct zebra_if
*zif
= ifp
->info
;
1064 zif
->rtadv
.AdvReachableTime
= 0;
1069 DEFUN (ipv6_nd_homeagent_preference
,
1070 ipv6_nd_homeagent_preference_cmd
,
1071 "ipv6 nd home-agent-preference (0-65535)",
1072 "Interface IPv6 config commands\n"
1073 "Neighbor discovery\n"
1074 "Home Agent preference\n"
1075 "preference value (default is 0, least preferred)\n")
1078 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1079 struct zebra_if
*zif
= ifp
->info
;
1080 zif
->rtadv
.HomeAgentPreference
=
1081 strtoul(argv
[idx_number
]->arg
, NULL
, 10);
1085 DEFUN (no_ipv6_nd_homeagent_preference
,
1086 no_ipv6_nd_homeagent_preference_cmd
,
1087 "no ipv6 nd home-agent-preference [(0-65535)]",
1089 "Interface IPv6 config commands\n"
1090 "Neighbor discovery\n"
1091 "Home Agent preference\n"
1092 "preference value (default is 0, least preferred)\n")
1094 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1095 struct zebra_if
*zif
= ifp
->info
;
1097 zif
->rtadv
.HomeAgentPreference
= 0;
1102 DEFUN (ipv6_nd_homeagent_lifetime
,
1103 ipv6_nd_homeagent_lifetime_cmd
,
1104 "ipv6 nd home-agent-lifetime (0-65520)",
1105 "Interface IPv6 config commands\n"
1106 "Neighbor discovery\n"
1107 "Home Agent lifetime\n"
1108 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
1111 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1112 struct zebra_if
*zif
= ifp
->info
;
1113 zif
->rtadv
.HomeAgentLifetime
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
1117 DEFUN (no_ipv6_nd_homeagent_lifetime
,
1118 no_ipv6_nd_homeagent_lifetime_cmd
,
1119 "no ipv6 nd home-agent-lifetime [(0-65520)]",
1121 "Interface IPv6 config commands\n"
1122 "Neighbor discovery\n"
1123 "Home Agent lifetime\n"
1124 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
1126 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1127 struct zebra_if
*zif
= ifp
->info
;
1129 zif
->rtadv
.HomeAgentLifetime
= -1;
1134 DEFUN (ipv6_nd_managed_config_flag
,
1135 ipv6_nd_managed_config_flag_cmd
,
1136 "ipv6 nd managed-config-flag",
1137 "Interface IPv6 config commands\n"
1138 "Neighbor discovery\n"
1139 "Managed address configuration flag\n")
1141 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1142 struct zebra_if
*zif
= ifp
->info
;
1144 zif
->rtadv
.AdvManagedFlag
= 1;
1149 DEFUN (no_ipv6_nd_managed_config_flag
,
1150 no_ipv6_nd_managed_config_flag_cmd
,
1151 "no ipv6 nd managed-config-flag",
1153 "Interface IPv6 config commands\n"
1154 "Neighbor discovery\n"
1155 "Managed address configuration flag\n")
1157 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1158 struct zebra_if
*zif
= ifp
->info
;
1160 zif
->rtadv
.AdvManagedFlag
= 0;
1165 DEFUN (ipv6_nd_homeagent_config_flag
,
1166 ipv6_nd_homeagent_config_flag_cmd
,
1167 "ipv6 nd home-agent-config-flag",
1168 "Interface IPv6 config commands\n"
1169 "Neighbor discovery\n"
1170 "Home Agent configuration flag\n")
1172 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1173 struct zebra_if
*zif
= ifp
->info
;
1175 zif
->rtadv
.AdvHomeAgentFlag
= 1;
1180 DEFUN (no_ipv6_nd_homeagent_config_flag
,
1181 no_ipv6_nd_homeagent_config_flag_cmd
,
1182 "no ipv6 nd home-agent-config-flag",
1184 "Interface IPv6 config commands\n"
1185 "Neighbor discovery\n"
1186 "Home Agent configuration flag\n")
1188 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1189 struct zebra_if
*zif
= ifp
->info
;
1191 zif
->rtadv
.AdvHomeAgentFlag
= 0;
1196 DEFUN (ipv6_nd_adv_interval_config_option
,
1197 ipv6_nd_adv_interval_config_option_cmd
,
1198 "ipv6 nd adv-interval-option",
1199 "Interface IPv6 config commands\n"
1200 "Neighbor discovery\n"
1201 "Advertisement Interval Option\n")
1203 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1204 struct zebra_if
*zif
= ifp
->info
;
1206 zif
->rtadv
.AdvIntervalOption
= 1;
1211 DEFUN (no_ipv6_nd_adv_interval_config_option
,
1212 no_ipv6_nd_adv_interval_config_option_cmd
,
1213 "no ipv6 nd adv-interval-option",
1215 "Interface IPv6 config commands\n"
1216 "Neighbor discovery\n"
1217 "Advertisement Interval Option\n")
1219 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1220 struct zebra_if
*zif
= ifp
->info
;
1222 zif
->rtadv
.AdvIntervalOption
= 0;
1227 DEFUN (ipv6_nd_other_config_flag
,
1228 ipv6_nd_other_config_flag_cmd
,
1229 "ipv6 nd other-config-flag",
1230 "Interface IPv6 config commands\n"
1231 "Neighbor discovery\n"
1232 "Other statefull configuration flag\n")
1234 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1235 struct zebra_if
*zif
= ifp
->info
;
1237 zif
->rtadv
.AdvOtherConfigFlag
= 1;
1242 DEFUN (no_ipv6_nd_other_config_flag
,
1243 no_ipv6_nd_other_config_flag_cmd
,
1244 "no ipv6 nd other-config-flag",
1246 "Interface IPv6 config commands\n"
1247 "Neighbor discovery\n"
1248 "Other statefull configuration flag\n")
1250 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1251 struct zebra_if
*zif
= ifp
->info
;
1253 zif
->rtadv
.AdvOtherConfigFlag
= 0;
1258 DEFUN (ipv6_nd_prefix
,
1260 "ipv6 nd prefix X:X::X:X/M [<(0-4294967295)|infinite> <(0-4294967295)|infinite>] [<router-address|off-link [no-autoconfig]|no-autoconfig [off-link]>]",
1261 "Interface IPv6 config commands\n"
1262 "Neighbor discovery\n"
1263 "Prefix information\n"
1265 "Valid lifetime in seconds\n"
1266 "Infinite valid lifetime\n"
1267 "Preferred lifetime in seconds\n"
1268 "Infinite preferred lifetime\n"
1269 "Set Router Address flag\n"
1270 "Do not use prefix for onlink determination\n"
1271 "Do not use prefix for autoconfiguration\n"
1272 "Do not use prefix for autoconfiguration\n"
1273 "Do not use prefix for onlink determination\n")
1276 char *prefix
= argv
[3]->arg
;
1277 int lifetimes
= (argc
> 4) && (argv
[4]->type
== RANGE_TKN
1278 || strmatch(argv
[4]->text
, "infinite"));
1279 int routeropts
= lifetimes
? argc
> 6 : argc
> 4;
1281 int idx_routeropts
= routeropts
? (lifetimes
? 6 : 4) : 0;
1283 char *lifetime
= NULL
, *preflifetime
= NULL
;
1284 int routeraddr
= 0, offlink
= 0, noautoconf
= 0;
1286 lifetime
= argv
[4]->type
== RANGE_TKN
? argv
[4]->arg
1288 preflifetime
= argv
[5]->type
== RANGE_TKN
? argv
[5]->arg
1293 strmatch(argv
[idx_routeropts
]->text
, "router-address");
1295 offlink
= (argc
> idx_routeropts
+ 1
1296 || strmatch(argv
[idx_routeropts
]->text
,
1298 noautoconf
= (argc
> idx_routeropts
+ 1
1299 || strmatch(argv
[idx_routeropts
]->text
,
1305 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1306 struct zebra_if
*zebra_if
= ifp
->info
;
1308 struct rtadv_prefix rp
;
1310 ret
= str2prefix_ipv6(prefix
, &rp
.prefix
);
1312 vty_out(vty
, "Malformed IPv6 prefix\n");
1313 return CMD_WARNING_CONFIG_FAILED
;
1315 apply_mask_ipv6(&rp
.prefix
); /* RFC4861 4.6.2 */
1316 rp
.AdvOnLinkFlag
= !offlink
;
1317 rp
.AdvAutonomousFlag
= !noautoconf
;
1318 rp
.AdvRouterAddressFlag
= routeraddr
;
1319 rp
.AdvValidLifetime
= RTADV_VALID_LIFETIME
;
1320 rp
.AdvPreferredLifetime
= RTADV_PREFERRED_LIFETIME
;
1323 rp
.AdvValidLifetime
= strmatch(lifetime
, "infinite")
1325 : strtoll(lifetime
, NULL
, 10);
1326 rp
.AdvPreferredLifetime
=
1327 strmatch(preflifetime
, "infinite")
1329 : strtoll(preflifetime
, NULL
, 10);
1330 if (rp
.AdvPreferredLifetime
> rp
.AdvValidLifetime
) {
1331 vty_out(vty
, "Invalid preferred lifetime\n");
1332 return CMD_WARNING_CONFIG_FAILED
;
1336 rtadv_prefix_set(zebra_if
, &rp
);
1341 DEFUN (no_ipv6_nd_prefix
,
1342 no_ipv6_nd_prefix_cmd
,
1343 "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]>]",
1345 "Interface IPv6 config commands\n"
1346 "Neighbor discovery\n"
1347 "Prefix information\n"
1349 "Valid lifetime in seconds\n"
1350 "Infinite valid lifetime\n"
1351 "Preferred lifetime in seconds\n"
1352 "Infinite preferred lifetime\n"
1353 "Set Router Address flag\n"
1354 "Do not use prefix for onlink determination\n"
1355 "Do not use prefix for autoconfiguration\n"
1356 "Do not use prefix for autoconfiguration\n"
1357 "Do not use prefix for onlink determination\n")
1359 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1360 struct zebra_if
*zebra_if
= ifp
->info
;
1362 struct rtadv_prefix rp
;
1363 char *prefix
= argv
[4]->arg
;
1365 ret
= str2prefix_ipv6(prefix
, &rp
.prefix
);
1367 vty_out(vty
, "Malformed IPv6 prefix\n");
1368 return CMD_WARNING_CONFIG_FAILED
;
1370 apply_mask_ipv6(&rp
.prefix
); /* RFC4861 4.6.2 */
1372 ret
= rtadv_prefix_reset(zebra_if
, &rp
);
1374 vty_out(vty
, "Non-existant IPv6 prefix\n");
1375 return CMD_WARNING_CONFIG_FAILED
;
1381 DEFUN (ipv6_nd_router_preference
,
1382 ipv6_nd_router_preference_cmd
,
1383 "ipv6 nd router-preference <high|medium|low>",
1384 "Interface IPv6 config commands\n"
1385 "Neighbor discovery\n"
1386 "Default router preference\n"
1387 "High default router preference\n"
1388 "Medium default router preference (default)\n"
1389 "Low default router preference\n")
1391 int idx_high_medium_low
= 3;
1392 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1393 struct zebra_if
*zif
= ifp
->info
;
1396 while (0 != rtadv_pref_strs
[i
]) {
1397 if (strncmp(argv
[idx_high_medium_low
]->arg
, rtadv_pref_strs
[i
],
1400 zif
->rtadv
.DefaultPreference
= i
;
1406 return CMD_ERR_NO_MATCH
;
1409 DEFUN (no_ipv6_nd_router_preference
,
1410 no_ipv6_nd_router_preference_cmd
,
1411 "no ipv6 nd router-preference [<high|medium|low>]",
1413 "Interface IPv6 config commands\n"
1414 "Neighbor discovery\n"
1415 "Default router preference\n"
1416 "High default router preference\n"
1417 "Medium default router preference (default)\n"
1418 "Low default router preference\n")
1420 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1421 struct zebra_if
*zif
= ifp
->info
;
1423 zif
->rtadv
.DefaultPreference
=
1424 RTADV_PREF_MEDIUM
; /* Default per RFC4191. */
1431 "ipv6 nd mtu (1-65535)",
1432 "Interface IPv6 config commands\n"
1433 "Neighbor discovery\n"
1438 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1439 struct zebra_if
*zif
= ifp
->info
;
1440 zif
->rtadv
.AdvLinkMTU
= strtoul(argv
[idx_number
]->arg
, NULL
, 10);
1444 DEFUN (no_ipv6_nd_mtu
,
1446 "no ipv6 nd mtu [(1-65535)]",
1448 "Interface IPv6 config commands\n"
1449 "Neighbor discovery\n"
1453 VTY_DECLVAR_CONTEXT(interface
, ifp
);
1454 struct zebra_if
*zif
= ifp
->info
;
1455 zif
->rtadv
.AdvLinkMTU
= 0;
1460 /* Write configuration about router advertisement. */
1461 void rtadv_config_write(struct vty
*vty
, struct interface
*ifp
)
1463 struct zebra_if
*zif
;
1464 struct listnode
*node
;
1465 struct rtadv_prefix
*rprefix
;
1466 char buf
[PREFIX_STRLEN
];
1471 if (!(if_is_loopback(ifp
)
1472 || CHECK_FLAG(ifp
->status
, ZEBRA_INTERFACE_VRF_LOOPBACK
))) {
1473 if (zif
->rtadv
.AdvSendAdvertisements
)
1474 vty_out(vty
, " no ipv6 nd suppress-ra\n");
1477 interval
= zif
->rtadv
.MaxRtrAdvInterval
;
1478 if (interval
% 1000)
1479 vty_out(vty
, " ipv6 nd ra-interval msec %d\n", interval
);
1480 else if (interval
!= RTADV_MAX_RTR_ADV_INTERVAL
)
1481 vty_out(vty
, " ipv6 nd ra-interval %d\n", interval
/ 1000);
1483 if (zif
->rtadv
.AdvIntervalOption
)
1484 vty_out(vty
, " ipv6 nd adv-interval-option\n");
1486 if (zif
->rtadv
.AdvDefaultLifetime
!= -1)
1487 vty_out(vty
, " ipv6 nd ra-lifetime %d\n",
1488 zif
->rtadv
.AdvDefaultLifetime
);
1490 if (zif
->rtadv
.HomeAgentPreference
)
1491 vty_out(vty
, " ipv6 nd home-agent-preference %u\n",
1492 zif
->rtadv
.HomeAgentPreference
);
1494 if (zif
->rtadv
.HomeAgentLifetime
!= -1)
1495 vty_out(vty
, " ipv6 nd home-agent-lifetime %u\n",
1496 zif
->rtadv
.HomeAgentLifetime
);
1498 if (zif
->rtadv
.AdvHomeAgentFlag
)
1499 vty_out(vty
, " ipv6 nd home-agent-config-flag\n");
1501 if (zif
->rtadv
.AdvReachableTime
)
1502 vty_out(vty
, " ipv6 nd reachable-time %d\n",
1503 zif
->rtadv
.AdvReachableTime
);
1505 if (zif
->rtadv
.AdvManagedFlag
)
1506 vty_out(vty
, " ipv6 nd managed-config-flag\n");
1508 if (zif
->rtadv
.AdvOtherConfigFlag
)
1509 vty_out(vty
, " ipv6 nd other-config-flag\n");
1511 if (zif
->rtadv
.DefaultPreference
!= RTADV_PREF_MEDIUM
)
1512 vty_out(vty
, " ipv6 nd router-preference %s\n",
1513 rtadv_pref_strs
[zif
->rtadv
.DefaultPreference
]);
1515 if (zif
->rtadv
.AdvLinkMTU
)
1516 vty_out(vty
, " ipv6 nd mtu %d\n", zif
->rtadv
.AdvLinkMTU
);
1518 for (ALL_LIST_ELEMENTS_RO(zif
->rtadv
.AdvPrefixList
, node
, rprefix
)) {
1519 vty_out(vty
, " ipv6 nd prefix %s",
1520 prefix2str(&rprefix
->prefix
, buf
, sizeof(buf
)));
1521 if ((rprefix
->AdvValidLifetime
!= RTADV_VALID_LIFETIME
)
1522 || (rprefix
->AdvPreferredLifetime
1523 != RTADV_PREFERRED_LIFETIME
)) {
1524 if (rprefix
->AdvValidLifetime
== UINT32_MAX
)
1525 vty_out(vty
, " infinite");
1527 vty_out(vty
, " %u", rprefix
->AdvValidLifetime
);
1528 if (rprefix
->AdvPreferredLifetime
== UINT32_MAX
)
1529 vty_out(vty
, " infinite");
1532 rprefix
->AdvPreferredLifetime
);
1534 if (!rprefix
->AdvOnLinkFlag
)
1535 vty_out(vty
, " off-link");
1536 if (!rprefix
->AdvAutonomousFlag
)
1537 vty_out(vty
, " no-autoconfig");
1538 if (rprefix
->AdvRouterAddressFlag
)
1539 vty_out(vty
, " router-address");
1545 static void rtadv_event(struct zebra_ns
*zns
, enum rtadv_event event
, int val
)
1547 struct rtadv
*rtadv
= &zns
->rtadv
;
1551 thread_add_read(zebrad
.master
, rtadv_read
, zns
, val
,
1553 thread_add_event(zebrad
.master
, rtadv_timer
, zns
, 0,
1557 if (rtadv
->ra_timer
) {
1558 thread_cancel(rtadv
->ra_timer
);
1559 rtadv
->ra_timer
= NULL
;
1561 if (rtadv
->ra_read
) {
1562 thread_cancel(rtadv
->ra_read
);
1563 rtadv
->ra_read
= NULL
;
1567 thread_add_timer(zebrad
.master
, rtadv_timer
, zns
, val
,
1570 case RTADV_TIMER_MSEC
:
1571 thread_add_timer_msec(zebrad
.master
, rtadv_timer
, zns
, val
,
1575 thread_add_read(zebrad
.master
, rtadv_read
, zns
, val
,
1584 void rtadv_init(struct zebra_ns
*zns
)
1586 zns
->rtadv
.sock
= rtadv_make_socket();
1589 void rtadv_terminate(struct zebra_ns
*zns
)
1591 rtadv_event(zns
, RTADV_STOP
, 0);
1592 if (zns
->rtadv
.sock
>= 0) {
1593 close(zns
->rtadv
.sock
);
1594 zns
->rtadv
.sock
= -1;
1597 zns
->rtadv
.adv_if_count
= 0;
1598 zns
->rtadv
.adv_msec_if_count
= 0;
1601 void rtadv_cmd_init(void)
1603 install_element(INTERFACE_NODE
, &ipv6_nd_suppress_ra_cmd
);
1604 install_element(INTERFACE_NODE
, &no_ipv6_nd_suppress_ra_cmd
);
1605 install_element(INTERFACE_NODE
, &ipv6_nd_ra_interval_cmd
);
1606 install_element(INTERFACE_NODE
, &ipv6_nd_ra_interval_msec_cmd
);
1607 install_element(INTERFACE_NODE
, &no_ipv6_nd_ra_interval_cmd
);
1608 install_element(INTERFACE_NODE
, &ipv6_nd_ra_lifetime_cmd
);
1609 install_element(INTERFACE_NODE
, &no_ipv6_nd_ra_lifetime_cmd
);
1610 install_element(INTERFACE_NODE
, &ipv6_nd_reachable_time_cmd
);
1611 install_element(INTERFACE_NODE
, &no_ipv6_nd_reachable_time_cmd
);
1612 install_element(INTERFACE_NODE
, &ipv6_nd_managed_config_flag_cmd
);
1613 install_element(INTERFACE_NODE
, &no_ipv6_nd_managed_config_flag_cmd
);
1614 install_element(INTERFACE_NODE
, &ipv6_nd_other_config_flag_cmd
);
1615 install_element(INTERFACE_NODE
, &no_ipv6_nd_other_config_flag_cmd
);
1616 install_element(INTERFACE_NODE
, &ipv6_nd_homeagent_config_flag_cmd
);
1617 install_element(INTERFACE_NODE
, &no_ipv6_nd_homeagent_config_flag_cmd
);
1618 install_element(INTERFACE_NODE
, &ipv6_nd_homeagent_preference_cmd
);
1619 install_element(INTERFACE_NODE
, &no_ipv6_nd_homeagent_preference_cmd
);
1620 install_element(INTERFACE_NODE
, &ipv6_nd_homeagent_lifetime_cmd
);
1621 install_element(INTERFACE_NODE
, &no_ipv6_nd_homeagent_lifetime_cmd
);
1622 install_element(INTERFACE_NODE
,
1623 &ipv6_nd_adv_interval_config_option_cmd
);
1624 install_element(INTERFACE_NODE
,
1625 &no_ipv6_nd_adv_interval_config_option_cmd
);
1626 install_element(INTERFACE_NODE
, &ipv6_nd_prefix_cmd
);
1627 install_element(INTERFACE_NODE
, &no_ipv6_nd_prefix_cmd
);
1628 install_element(INTERFACE_NODE
, &ipv6_nd_router_preference_cmd
);
1629 install_element(INTERFACE_NODE
, &no_ipv6_nd_router_preference_cmd
);
1630 install_element(INTERFACE_NODE
, &ipv6_nd_mtu_cmd
);
1631 install_element(INTERFACE_NODE
, &no_ipv6_nd_mtu_cmd
);
1634 static int if_join_all_router(int sock
, struct interface
*ifp
)
1638 struct ipv6_mreq mreq
;
1640 memset(&mreq
, 0, sizeof(struct ipv6_mreq
));
1641 inet_pton(AF_INET6
, ALLROUTER
, &mreq
.ipv6mr_multiaddr
);
1642 mreq
.ipv6mr_interface
= ifp
->ifindex
;
1644 ret
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (char *)&mreq
,
1647 zlog_warn("%s(%u): Failed to join group, socket %u error %s",
1648 ifp
->name
, ifp
->ifindex
, sock
, safe_strerror(errno
));
1650 if (IS_ZEBRA_DEBUG_EVENT
)
1652 "%s(%u): Join All-Routers multicast group, socket %u",
1653 ifp
->name
, ifp
->ifindex
, sock
);
1658 static int if_leave_all_router(int sock
, struct interface
*ifp
)
1662 struct ipv6_mreq mreq
;
1664 memset(&mreq
, 0, sizeof(struct ipv6_mreq
));
1665 inet_pton(AF_INET6
, ALLROUTER
, &mreq
.ipv6mr_multiaddr
);
1666 mreq
.ipv6mr_interface
= ifp
->ifindex
;
1668 ret
= setsockopt(sock
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, (char *)&mreq
,
1671 zlog_warn("%s(%u): Failed to leave group, socket %u error %s",
1672 ifp
->name
, ifp
->ifindex
, sock
, safe_strerror(errno
));
1674 if (IS_ZEBRA_DEBUG_EVENT
)
1676 "%s(%u): Leave All-Routers multicast group, socket %u",
1677 ifp
->name
, ifp
->ifindex
, sock
);
1683 void rtadv_init(struct zebra_ns
*zns
)
1687 void rtadv_terminate(struct zebra_ns
*zns
)
1691 void rtadv_cmd_init(void)
1695 #endif /* HAVE_RTADV */