blob: be4aeb1b17f053fd1a6c9f2469a638965f4961f0 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* Router advertisement
vincent7cee1bb2005-03-25 13:08:53 +00002 * Copyright (C) 2005 6WIND <jean-mickael.guerin@6wind.com>
paul718e3742002-12-13 20:15:29 +00003 * Copyright (C) 1999 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "memory.h"
26#include "sockopt.h"
27#include "thread.h"
28#include "if.h"
29#include "log.h"
30#include "prefix.h"
31#include "linklist.h"
32#include "command.h"
pauledd7c242003-06-04 13:59:38 +000033#include "privs.h"
Feng Lu49f76092015-05-22 11:40:10 +020034#include "vrf.h"
paul718e3742002-12-13 20:15:29 +000035
36#include "zebra/interface.h"
37#include "zebra/rtadv.h"
38#include "zebra/debug.h"
paul537d8ea2003-08-27 06:45:32 +000039#include "zebra/rib.h"
gdt4b5e1352003-12-03 17:54:34 +000040#include "zebra/zserv.h"
paul718e3742002-12-13 20:15:29 +000041
pauledd7c242003-06-04 13:59:38 +000042extern struct zebra_privs_t zserv_privs;
43
paul718e3742002-12-13 20:15:29 +000044#if defined (HAVE_IPV6) && defined (RTADV)
45
hassofa2b17e2004-03-04 17:45:00 +000046#ifdef OPEN_BSD
47#include <netinet/icmp6.h>
48#endif
49
paul718e3742002-12-13 20:15:29 +000050/* If RFC2133 definition is used. */
51#ifndef IPV6_JOIN_GROUP
52#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
53#endif
54#ifndef IPV6_LEAVE_GROUP
55#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
56#endif
57
58#define ALLNODE "ff02::1"
59#define ALLROUTER "ff02::2"
60
paulb21b19c2003-06-15 01:28:29 +000061extern struct zebra_t zebrad;
62
vincent7cee1bb2005-03-25 13:08:53 +000063enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER,
64 RTADV_TIMER_MSEC, RTADV_READ};
paul718e3742002-12-13 20:15:29 +000065
Feng Lu49f76092015-05-22 11:40:10 +020066static void rtadv_event (struct zebra_vrf *, enum rtadv_event, int);
paul718e3742002-12-13 20:15:29 +000067
paula1ac18c2005-06-28 17:17:12 +000068static int if_join_all_router (int, struct interface *);
69static int if_leave_all_router (int, struct interface *);
David Lamparter6b0655a2014-06-04 06:53:35 +020070
paula1ac18c2005-06-28 17:17:12 +000071static int
paul718e3742002-12-13 20:15:29 +000072rtadv_recv_packet (int sock, u_char *buf, int buflen,
73 struct sockaddr_in6 *from, unsigned int *ifindex,
74 int *hoplimit)
75{
76 int ret;
77 struct msghdr msg;
78 struct iovec iov;
79 struct cmsghdr *cmsgptr;
80 struct in6_addr dst;
81
82 char adata[1024];
83
84 /* Fill in message and iovec. */
85 msg.msg_name = (void *) from;
86 msg.msg_namelen = sizeof (struct sockaddr_in6);
87 msg.msg_iov = &iov;
88 msg.msg_iovlen = 1;
89 msg.msg_control = (void *) adata;
90 msg.msg_controllen = sizeof adata;
91 iov.iov_base = buf;
92 iov.iov_len = buflen;
93
94 /* If recvmsg fail return minus value. */
95 ret = recvmsg (sock, &msg, 0);
96 if (ret < 0)
97 return ret;
98
ajsb99760a2005-01-04 16:24:43 +000099 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
paul718e3742002-12-13 20:15:29 +0000100 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
101 {
102 /* I want interface index which this packet comes from. */
103 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
104 cmsgptr->cmsg_type == IPV6_PKTINFO)
105 {
106 struct in6_pktinfo *ptr;
107
108 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
109 *ifindex = ptr->ipi6_ifindex;
110 memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
111 }
112
113 /* Incoming packet's hop limit. */
114 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
115 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
Stephen Hemmingerb0b709a2009-12-08 13:26:14 +0300116 {
117 int *hoptr = (int *) CMSG_DATA (cmsgptr);
118 *hoplimit = *hoptr;
119 }
paul718e3742002-12-13 20:15:29 +0000120 }
121 return ret;
122}
123
124#define RTADV_MSG_SIZE 4096
125
126/* Send router advertisement packet. */
paula1ac18c2005-06-28 17:17:12 +0000127static void
paul718e3742002-12-13 20:15:29 +0000128rtadv_send_packet (int sock, struct interface *ifp)
129{
130 struct msghdr msg;
131 struct iovec iov;
132 struct cmsghdr *cmsgptr;
133 struct in6_pktinfo *pkt;
134 struct sockaddr_in6 addr;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000135#ifdef HAVE_STRUCT_SOCKADDR_DL
paul718e3742002-12-13 20:15:29 +0000136 struct sockaddr_dl *sdl;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000137#endif /* HAVE_STRUCT_SOCKADDR_DL */
gdt57492d52004-08-11 18:06:38 +0000138 static void *adata = NULL;
paul718e3742002-12-13 20:15:29 +0000139 unsigned char buf[RTADV_MSG_SIZE];
140 struct nd_router_advert *rtadv;
141 int ret;
142 int len = 0;
143 struct zebra_if *zif;
paul1eb8ef22005-04-07 07:30:20 +0000144 struct rtadv_prefix *rprefix;
paul718e3742002-12-13 20:15:29 +0000145 u_char all_nodes_addr[] = {0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
hasso52dc7ee2004-09-23 19:18:23 +0000146 struct listnode *node;
Denis Ovsienkod660f692011-12-30 21:55:49 +0400147 u_int16_t pkt_RouterLifetime;
paul718e3742002-12-13 20:15:29 +0000148
gdt57492d52004-08-11 18:06:38 +0000149 /*
150 * Allocate control message bufffer. This is dynamic because
151 * CMSG_SPACE is not guaranteed not to call a function. Note that
152 * the size will be different on different architectures due to
153 * differing alignment rules.
154 */
155 if (adata == NULL)
156 {
157 /* XXX Free on shutdown. */
158 adata = malloc(CMSG_SPACE(sizeof(struct in6_pktinfo)));
159
160 if (adata == NULL)
161 zlog_err("rtadv_send_packet: can't malloc control data\n");
162 }
163
paul718e3742002-12-13 20:15:29 +0000164 /* Logging of packet. */
165 if (IS_ZEBRA_DEBUG_PACKET)
ajsb6178002004-12-07 21:12:56 +0000166 zlog_debug ("Router advertisement send to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +0000167
168 /* Fill in sockaddr_in6. */
169 memset (&addr, 0, sizeof (struct sockaddr_in6));
170 addr.sin6_family = AF_INET6;
171#ifdef SIN6_LEN
172 addr.sin6_len = sizeof (struct sockaddr_in6);
173#endif /* SIN6_LEN */
174 addr.sin6_port = htons (IPPROTO_ICMPV6);
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400175 IPV6_ADDR_COPY (&addr.sin6_addr, all_nodes_addr);
paul718e3742002-12-13 20:15:29 +0000176
177 /* Fetch interface information. */
178 zif = ifp->info;
179
180 /* Make router advertisement message. */
181 rtadv = (struct nd_router_advert *) buf;
182
183 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
184 rtadv->nd_ra_code = 0;
185 rtadv->nd_ra_cksum = 0;
186
187 rtadv->nd_ra_curhoplimit = 64;
Chris Caputob60668d2009-05-03 04:40:57 +0000188
189 /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
190 rtadv->nd_ra_flags_reserved =
191 zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference;
192 rtadv->nd_ra_flags_reserved <<= 3;
193
paul718e3742002-12-13 20:15:29 +0000194 if (zif->rtadv.AdvManagedFlag)
195 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
196 if (zif->rtadv.AdvOtherConfigFlag)
197 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
vincent7cee1bb2005-03-25 13:08:53 +0000198 if (zif->rtadv.AdvHomeAgentFlag)
199 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
Denis Ovsienkod660f692011-12-30 21:55:49 +0400200 /* Note that according to Neighbor Discovery (RFC 4861 [18]),
201 * AdvDefaultLifetime is by default based on the value of
202 * MaxRtrAdvInterval. AdvDefaultLifetime is used in the Router Lifetime
203 * field of Router Advertisements. Given that this field is expressed
204 * in seconds, a small MaxRtrAdvInterval value can result in a zero
205 * value for this field. To prevent this, routers SHOULD keep
206 * AdvDefaultLifetime in at least one second, even if the use of
207 * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */
208 pkt_RouterLifetime = zif->rtadv.AdvDefaultLifetime != -1 ?
209 zif->rtadv.AdvDefaultLifetime :
210 MAX (1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
211 rtadv->nd_ra_router_lifetime = htons (pkt_RouterLifetime);
paul718e3742002-12-13 20:15:29 +0000212 rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
213 rtadv->nd_ra_retransmit = htonl (0);
214
215 len = sizeof (struct nd_router_advert);
216
Denis Ovsienkod660f692011-12-30 21:55:49 +0400217 /* If both the Home Agent Preference and Home Agent Lifetime are set to
218 * their default values specified above, this option SHOULD NOT be
219 * included in the Router Advertisement messages sent by this home
220 * agent. -- RFC6275, 7.4 */
221 if
222 (
223 zif->rtadv.AdvHomeAgentFlag &&
224 (zif->rtadv.HomeAgentPreference || zif->rtadv.HomeAgentLifetime != -1)
225 )
vincent7cee1bb2005-03-25 13:08:53 +0000226 {
227 struct nd_opt_homeagent_info *ndopt_hai =
228 (struct nd_opt_homeagent_info *)(buf + len);
229 ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
230 ndopt_hai->nd_opt_hai_len = 1;
231 ndopt_hai->nd_opt_hai_reserved = 0;
232 ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference);
Denis Ovsienkod660f692011-12-30 21:55:49 +0400233 /* 16-bit unsigned integer. The lifetime associated with the home
234 * agent in units of seconds. The default value is the same as the
235 * Router Lifetime, as specified in the main body of the Router
236 * Advertisement. The maximum value corresponds to 18.2 hours. A
237 * value of 0 MUST NOT be used. -- RFC6275, 7.5 */
238 ndopt_hai->nd_opt_hai_lifetime = htons
239 (
240 zif->rtadv.HomeAgentLifetime != -1 ?
241 zif->rtadv.HomeAgentLifetime :
242 MAX (1, pkt_RouterLifetime) /* 0 is OK for RL, but not for HAL*/
243 );
vincent7cee1bb2005-03-25 13:08:53 +0000244 len += sizeof(struct nd_opt_homeagent_info);
245 }
246
247 if (zif->rtadv.AdvIntervalOption)
248 {
249 struct nd_opt_adv_interval *ndopt_adv =
250 (struct nd_opt_adv_interval *)(buf + len);
251 ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL;
252 ndopt_adv->nd_opt_ai_len = 1;
253 ndopt_adv->nd_opt_ai_reserved = 0;
254 ndopt_adv->nd_opt_ai_interval = htonl(zif->rtadv.MaxRtrAdvInterval);
255 len += sizeof(struct nd_opt_adv_interval);
256 }
257
paul718e3742002-12-13 20:15:29 +0000258 /* Fill in prefix. */
paul1eb8ef22005-04-07 07:30:20 +0000259 for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
paul718e3742002-12-13 20:15:29 +0000260 {
261 struct nd_opt_prefix_info *pinfo;
paul718e3742002-12-13 20:15:29 +0000262
263 pinfo = (struct nd_opt_prefix_info *) (buf + len);
264
265 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
266 pinfo->nd_opt_pi_len = 4;
267 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
268
269 pinfo->nd_opt_pi_flags_reserved = 0;
270 if (rprefix->AdvOnLinkFlag)
271 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
272 if (rprefix->AdvAutonomousFlag)
273 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
vincent7cee1bb2005-03-25 13:08:53 +0000274 if (rprefix->AdvRouterAddressFlag)
275 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
paul718e3742002-12-13 20:15:29 +0000276
277 pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
278 pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
279 pinfo->nd_opt_pi_reserved2 = 0;
280
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400281 IPV6_ADDR_COPY (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.prefix);
paul718e3742002-12-13 20:15:29 +0000282
283#ifdef DEBUG
284 {
285 u_char buf[INET6_ADDRSTRLEN];
286
ajsb6178002004-12-07 21:12:56 +0000287 zlog_debug ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix,
hasso3e31cde2004-05-18 11:58:59 +0000288 buf, INET6_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +0000289
290 }
291#endif /* DEBUG */
292
293 len += sizeof (struct nd_opt_prefix_info);
294 }
295
296 /* Hardware address. */
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000297#ifdef HAVE_STRUCT_SOCKADDR_DL
paul718e3742002-12-13 20:15:29 +0000298 sdl = &ifp->sdl;
299 if (sdl != NULL && sdl->sdl_alen != 0)
300 {
301 buf[len++] = ND_OPT_SOURCE_LINKADDR;
David Ward50adf782009-08-31 10:42:06 -0400302
303 /* Option length should be rounded up to next octet if
304 the link address does not end on an octet boundary. */
305 buf[len++] = (sdl->sdl_alen + 9) >> 3;
paul718e3742002-12-13 20:15:29 +0000306
307 memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
308 len += sdl->sdl_alen;
David Ward50adf782009-08-31 10:42:06 -0400309
310 /* Pad option to end on an octet boundary. */
311 memset (buf + len, 0, -(sdl->sdl_alen + 2) & 0x7);
312 len += -(sdl->sdl_alen + 2) & 0x7;
paul718e3742002-12-13 20:15:29 +0000313 }
314#else
315 if (ifp->hw_addr_len != 0)
316 {
317 buf[len++] = ND_OPT_SOURCE_LINKADDR;
David Ward50adf782009-08-31 10:42:06 -0400318
319 /* Option length should be rounded up to next octet if
320 the link address does not end on an octet boundary. */
321 buf[len++] = (ifp->hw_addr_len + 9) >> 3;
paul718e3742002-12-13 20:15:29 +0000322
323 memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
324 len += ifp->hw_addr_len;
David Ward50adf782009-08-31 10:42:06 -0400325
326 /* Pad option to end on an octet boundary. */
327 memset (buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7);
328 len += -(ifp->hw_addr_len + 2) & 0x7;
paul718e3742002-12-13 20:15:29 +0000329 }
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000330#endif /* HAVE_STRUCT_SOCKADDR_DL */
paul718e3742002-12-13 20:15:29 +0000331
Denis Ovsienko6ae93c02011-12-27 10:45:36 +0400332 /* MTU */
333 if (zif->rtadv.AdvLinkMTU)
334 {
335 struct nd_opt_mtu * opt = (struct nd_opt_mtu *) (buf + len);
336 opt->nd_opt_mtu_type = ND_OPT_MTU;
337 opt->nd_opt_mtu_len = 1;
338 opt->nd_opt_mtu_reserved = 0;
339 opt->nd_opt_mtu_mtu = htonl (zif->rtadv.AdvLinkMTU);
340 len += sizeof (struct nd_opt_mtu);
341 }
342
paul718e3742002-12-13 20:15:29 +0000343 msg.msg_name = (void *) &addr;
344 msg.msg_namelen = sizeof (struct sockaddr_in6);
345 msg.msg_iov = &iov;
346 msg.msg_iovlen = 1;
347 msg.msg_control = (void *) adata;
gdtf841e022004-08-11 19:20:01 +0000348 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
gdt57492d52004-08-11 18:06:38 +0000349 msg.msg_flags = 0;
paul718e3742002-12-13 20:15:29 +0000350 iov.iov_base = buf;
351 iov.iov_len = len;
352
ajsb99760a2005-01-04 16:24:43 +0000353 cmsgptr = ZCMSG_FIRSTHDR(&msg);
gdt57492d52004-08-11 18:06:38 +0000354 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
paul718e3742002-12-13 20:15:29 +0000355 cmsgptr->cmsg_level = IPPROTO_IPV6;
356 cmsgptr->cmsg_type = IPV6_PKTINFO;
gdt80893812004-08-11 15:58:00 +0000357
paul718e3742002-12-13 20:15:29 +0000358 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
359 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
360 pkt->ipi6_ifindex = ifp->ifindex;
361
362 ret = sendmsg (sock, &msg, 0);
gdt9ccabd12004-01-06 18:23:02 +0000363 if (ret < 0)
364 {
365 zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n",
ajs6099b3b2004-11-20 02:06:59 +0000366 errno, safe_strerror(errno));
gdt9ccabd12004-01-06 18:23:02 +0000367 }
paul718e3742002-12-13 20:15:29 +0000368}
369
paula1ac18c2005-06-28 17:17:12 +0000370static int
paul718e3742002-12-13 20:15:29 +0000371rtadv_timer (struct thread *thread)
372{
Feng Lu49f76092015-05-22 11:40:10 +0200373 struct zebra_vrf *zvrf = THREAD_ARG (thread);
paul1eb8ef22005-04-07 07:30:20 +0000374 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000375 struct interface *ifp;
376 struct zebra_if *zif;
vincent7cee1bb2005-03-25 13:08:53 +0000377 int period;
paul718e3742002-12-13 20:15:29 +0000378
Feng Lu49f76092015-05-22 11:40:10 +0200379 zvrf->rtadv.ra_timer = NULL;
380 if (zvrf->rtadv.adv_msec_if_count == 0)
vincent7cee1bb2005-03-25 13:08:53 +0000381 {
382 period = 1000; /* 1 s */
Feng Lu49f76092015-05-22 11:40:10 +0200383 rtadv_event (zvrf, RTADV_TIMER, 1 /* 1 s */);
vincent7cee1bb2005-03-25 13:08:53 +0000384 }
385 else
386 {
387 period = 10; /* 10 ms */
Feng Lu49f76092015-05-22 11:40:10 +0200388 rtadv_event (zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */);
vincent7cee1bb2005-03-25 13:08:53 +0000389 }
paul718e3742002-12-13 20:15:29 +0000390
Feng Lu49f76092015-05-22 11:40:10 +0200391 for (ALL_LIST_ELEMENTS (vrf_iflist (zvrf->vrf_id), node, nnode, ifp))
paul718e3742002-12-13 20:15:29 +0000392 {
Denis Ovsienkofb5174a2011-12-27 10:18:47 +0400393 if (if_is_loopback (ifp) || ! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +0000394 continue;
395
396 zif = ifp->info;
397
398 if (zif->rtadv.AdvSendAdvertisements)
vincent7cee1bb2005-03-25 13:08:53 +0000399 {
400 zif->rtadv.AdvIntervalTimer -= period;
401 if (zif->rtadv.AdvIntervalTimer <= 0)
402 {
Denis Ovsienkod660f692011-12-30 21:55:49 +0400403 /* FIXME: using MaxRtrAdvInterval each time isn't what section
404 6.2.4 of RFC4861 tells to do. */
vincent7cee1bb2005-03-25 13:08:53 +0000405 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
Feng Lu49f76092015-05-22 11:40:10 +0200406 rtadv_send_packet (zvrf->rtadv.sock, ifp);
vincent7cee1bb2005-03-25 13:08:53 +0000407 }
408 }
paul718e3742002-12-13 20:15:29 +0000409 }
410 return 0;
411}
412
paula1ac18c2005-06-28 17:17:12 +0000413static void
paul718e3742002-12-13 20:15:29 +0000414rtadv_process_solicit (struct interface *ifp)
415{
Feng Lu49f76092015-05-22 11:40:10 +0200416 struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000417
Feng Lu49f76092015-05-22 11:40:10 +0200418 zlog_info ("Router solicitation received on %s vrf %u", ifp->name, zvrf->vrf_id);
419
420 rtadv_send_packet (zvrf->rtadv.sock, ifp);
paul718e3742002-12-13 20:15:29 +0000421}
422
paula1ac18c2005-06-28 17:17:12 +0000423static void
424rtadv_process_advert (void)
paul718e3742002-12-13 20:15:29 +0000425{
426 zlog_info ("Router advertisement received");
427}
428
paula1ac18c2005-06-28 17:17:12 +0000429static void
Feng Lu49f76092015-05-22 11:40:10 +0200430rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex,
431 int hoplimit, vrf_id_t vrf_id)
paul718e3742002-12-13 20:15:29 +0000432{
433 struct icmp6_hdr *icmph;
434 struct interface *ifp;
435 struct zebra_if *zif;
436
437 /* Interface search. */
Feng Lu49f76092015-05-22 11:40:10 +0200438 ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
paul718e3742002-12-13 20:15:29 +0000439 if (ifp == NULL)
440 {
Feng Lu49f76092015-05-22 11:40:10 +0200441 zlog_warn ("Unknown interface index: %d, vrf %u", ifindex, vrf_id);
paul718e3742002-12-13 20:15:29 +0000442 return;
443 }
444
445 if (if_is_loopback (ifp))
446 return;
447
448 /* Check interface configuration. */
449 zif = ifp->info;
450 if (! zif->rtadv.AdvSendAdvertisements)
451 return;
452
453 /* ICMP message length check. */
454 if (len < sizeof (struct icmp6_hdr))
455 {
456 zlog_warn ("Invalid ICMPV6 packet length: %d", len);
457 return;
458 }
459
460 icmph = (struct icmp6_hdr *) buf;
461
462 /* ICMP message type check. */
463 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
464 icmph->icmp6_type != ND_ROUTER_ADVERT)
465 {
466 zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
467 return;
468 }
469
470 /* Hoplimit check. */
471 if (hoplimit >= 0 && hoplimit != 255)
472 {
473 zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
474 hoplimit);
475 return;
476 }
477
478 /* Check ICMP message type. */
479 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
480 rtadv_process_solicit (ifp);
481 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
482 rtadv_process_advert ();
483
484 return;
485}
486
paula1ac18c2005-06-28 17:17:12 +0000487static int
paul718e3742002-12-13 20:15:29 +0000488rtadv_read (struct thread *thread)
489{
490 int sock;
491 int len;
492 u_char buf[RTADV_MSG_SIZE];
493 struct sockaddr_in6 from;
Stephen Hemmingerb0b709a2009-12-08 13:26:14 +0300494 unsigned int ifindex = 0;
paul718e3742002-12-13 20:15:29 +0000495 int hoplimit = -1;
Feng Lu49f76092015-05-22 11:40:10 +0200496 struct zebra_vrf *zvrf = THREAD_ARG (thread);
paul718e3742002-12-13 20:15:29 +0000497
498 sock = THREAD_FD (thread);
Feng Lu49f76092015-05-22 11:40:10 +0200499 zvrf->rtadv.ra_read = NULL;
paul718e3742002-12-13 20:15:29 +0000500
501 /* Register myself. */
Feng Lu49f76092015-05-22 11:40:10 +0200502 rtadv_event (zvrf, RTADV_READ, sock);
paul718e3742002-12-13 20:15:29 +0000503
504 len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
505
506 if (len < 0)
507 {
ajs6099b3b2004-11-20 02:06:59 +0000508 zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000509 return len;
510 }
511
Feng Lu49f76092015-05-22 11:40:10 +0200512 rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, zvrf->vrf_id);
paul718e3742002-12-13 20:15:29 +0000513
514 return 0;
515}
516
paula1ac18c2005-06-28 17:17:12 +0000517static int
Feng Lu49f76092015-05-22 11:40:10 +0200518rtadv_make_socket (vrf_id_t vrf_id)
paul718e3742002-12-13 20:15:29 +0000519{
520 int sock;
521 int ret;
522 struct icmp6_filter filter;
523
pauledd7c242003-06-04 13:59:38 +0000524 if ( zserv_privs.change (ZPRIVS_RAISE) )
525 zlog_err ("rtadv_make_socket: could not raise privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000526 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000527
Feng Lu49f76092015-05-22 11:40:10 +0200528 sock = vrf_socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, vrf_id);
paul718e3742002-12-13 20:15:29 +0000529
pauledd7c242003-06-04 13:59:38 +0000530 if ( zserv_privs.change (ZPRIVS_LOWER) )
531 zlog_err ("rtadv_make_socket: could not lower privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000532 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000533
paul718e3742002-12-13 20:15:29 +0000534 /* When we can't make ICMPV6 socket simply back. Router
535 advertisement feature will not be supported. */
536 if (sock < 0)
537 return -1;
538
539 ret = setsockopt_ipv6_pktinfo (sock, 1);
540 if (ret < 0)
541 return ret;
paul718e3742002-12-13 20:15:29 +0000542 ret = setsockopt_ipv6_multicast_loop (sock, 0);
543 if (ret < 0)
544 return ret;
545 ret = setsockopt_ipv6_unicast_hops (sock, 255);
546 if (ret < 0)
547 return ret;
548 ret = setsockopt_ipv6_multicast_hops (sock, 255);
549 if (ret < 0)
550 return ret;
551 ret = setsockopt_ipv6_hoplimit (sock, 1);
552 if (ret < 0)
553 return ret;
554
555 ICMP6_FILTER_SETBLOCKALL(&filter);
556 ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
557 ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
558
559 ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
560 sizeof (struct icmp6_filter));
561 if (ret < 0)
562 {
ajs6099b3b2004-11-20 02:06:59 +0000563 zlog_info ("ICMP6_FILTER set fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000564 return ret;
565 }
566
567 return sock;
568}
David Lamparter6b0655a2014-06-04 06:53:35 +0200569
paula1ac18c2005-06-28 17:17:12 +0000570static struct rtadv_prefix *
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800571rtadv_prefix_new (void)
paul718e3742002-12-13 20:15:29 +0000572{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700573 return XCALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
paul718e3742002-12-13 20:15:29 +0000574}
575
paula1ac18c2005-06-28 17:17:12 +0000576static void
paul718e3742002-12-13 20:15:29 +0000577rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
578{
579 XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
580}
581
paula1ac18c2005-06-28 17:17:12 +0000582static struct rtadv_prefix *
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400583rtadv_prefix_lookup (struct list *rplist, struct prefix_ipv6 *p)
paul718e3742002-12-13 20:15:29 +0000584{
hasso52dc7ee2004-09-23 19:18:23 +0000585 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000586 struct rtadv_prefix *rprefix;
587
paul1eb8ef22005-04-07 07:30:20 +0000588 for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix))
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400589 if (prefix_same ((struct prefix *) &rprefix->prefix, (struct prefix *) p))
paul1eb8ef22005-04-07 07:30:20 +0000590 return rprefix;
paul718e3742002-12-13 20:15:29 +0000591 return NULL;
592}
593
paula1ac18c2005-06-28 17:17:12 +0000594static struct rtadv_prefix *
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400595rtadv_prefix_get (struct list *rplist, struct prefix_ipv6 *p)
paul718e3742002-12-13 20:15:29 +0000596{
597 struct rtadv_prefix *rprefix;
598
599 rprefix = rtadv_prefix_lookup (rplist, p);
600 if (rprefix)
601 return rprefix;
602
603 rprefix = rtadv_prefix_new ();
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400604 memcpy (&rprefix->prefix, p, sizeof (struct prefix_ipv6));
paul718e3742002-12-13 20:15:29 +0000605 listnode_add (rplist, rprefix);
606
607 return rprefix;
608}
609
paula1ac18c2005-06-28 17:17:12 +0000610static void
paul718e3742002-12-13 20:15:29 +0000611rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
612{
613 struct rtadv_prefix *rprefix;
614
615 rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
616
617 /* Set parameters. */
618 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
619 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
620 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
621 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
vincent7cee1bb2005-03-25 13:08:53 +0000622 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
paul718e3742002-12-13 20:15:29 +0000623}
624
paula1ac18c2005-06-28 17:17:12 +0000625static int
paul718e3742002-12-13 20:15:29 +0000626rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
627{
628 struct rtadv_prefix *rprefix;
629
630 rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
631 if (rprefix != NULL)
632 {
633 listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
634 rtadv_prefix_free (rprefix);
635 return 1;
636 }
637 else
638 return 0;
639}
640
641DEFUN (ipv6_nd_suppress_ra,
642 ipv6_nd_suppress_ra_cmd,
643 "ipv6 nd suppress-ra",
hasso3e31cde2004-05-18 11:58:59 +0000644 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000645 "Neighbor discovery\n"
646 "Suppress Router Advertisement\n")
647{
648 struct interface *ifp;
649 struct zebra_if *zif;
Feng Lu49f76092015-05-22 11:40:10 +0200650 struct zebra_vrf *zvrf;
paul718e3742002-12-13 20:15:29 +0000651
652 ifp = vty->index;
653 zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200654 zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000655
656 if (if_is_loopback (ifp))
657 {
658 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
659 return CMD_WARNING;
660 }
661
662 if (zif->rtadv.AdvSendAdvertisements)
663 {
664 zif->rtadv.AdvSendAdvertisements = 0;
665 zif->rtadv.AdvIntervalTimer = 0;
Feng Lu49f76092015-05-22 11:40:10 +0200666 zvrf->rtadv.adv_if_count--;
paul718e3742002-12-13 20:15:29 +0000667
Feng Lu49f76092015-05-22 11:40:10 +0200668 if_leave_all_router (zvrf->rtadv.sock, ifp);
paul718e3742002-12-13 20:15:29 +0000669
Feng Lu49f76092015-05-22 11:40:10 +0200670 if (zvrf->rtadv.adv_if_count == 0)
671 rtadv_event (zvrf, RTADV_STOP, 0);
paul718e3742002-12-13 20:15:29 +0000672 }
673
674 return CMD_SUCCESS;
675}
676
paul718e3742002-12-13 20:15:29 +0000677DEFUN (no_ipv6_nd_suppress_ra,
678 no_ipv6_nd_suppress_ra_cmd,
679 "no ipv6 nd suppress-ra",
680 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000681 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000682 "Neighbor discovery\n"
683 "Suppress Router Advertisement\n")
684{
685 struct interface *ifp;
686 struct zebra_if *zif;
Feng Lu49f76092015-05-22 11:40:10 +0200687 struct zebra_vrf *zvrf;
paul718e3742002-12-13 20:15:29 +0000688
689 ifp = vty->index;
690 zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200691 zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000692
693 if (if_is_loopback (ifp))
694 {
695 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
696 return CMD_WARNING;
697 }
698
699 if (! zif->rtadv.AdvSendAdvertisements)
700 {
701 zif->rtadv.AdvSendAdvertisements = 1;
702 zif->rtadv.AdvIntervalTimer = 0;
Feng Lu49f76092015-05-22 11:40:10 +0200703 zvrf->rtadv.adv_if_count++;
paul718e3742002-12-13 20:15:29 +0000704
Feng Lu49f76092015-05-22 11:40:10 +0200705 if_join_all_router (zvrf->rtadv.sock, ifp);
paul718e3742002-12-13 20:15:29 +0000706
Feng Lu49f76092015-05-22 11:40:10 +0200707 if (zvrf->rtadv.adv_if_count == 1)
708 rtadv_event (zvrf, RTADV_START, zvrf->rtadv.sock);
paul718e3742002-12-13 20:15:29 +0000709 }
710
711 return CMD_SUCCESS;
712}
713
vincent7cee1bb2005-03-25 13:08:53 +0000714DEFUN (ipv6_nd_ra_interval_msec,
715 ipv6_nd_ra_interval_msec_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400716 "ipv6 nd ra-interval msec <70-1800000>",
vincent7cee1bb2005-03-25 13:08:53 +0000717 "Interface IPv6 config commands\n"
718 "Neighbor discovery\n"
719 "Router Advertisement interval\n"
720 "Router Advertisement interval in milliseconds\n")
721{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400722 unsigned interval;
723 struct interface *ifp = (struct interface *) vty->index;
724 struct zebra_if *zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200725 struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
vincent7cee1bb2005-03-25 13:08:53 +0000726
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400727 VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000);
728 if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000))
729 {
730 vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE);
731 return CMD_WARNING;
732 }
vincent7cee1bb2005-03-25 13:08:53 +0000733
734 if (zif->rtadv.MaxRtrAdvInterval % 1000)
Feng Lu49f76092015-05-22 11:40:10 +0200735 zvrf->rtadv.adv_msec_if_count--;
vincent7cee1bb2005-03-25 13:08:53 +0000736
737 if (interval % 1000)
Feng Lu49f76092015-05-22 11:40:10 +0200738 zvrf->rtadv.adv_msec_if_count++;
vincent7cee1bb2005-03-25 13:08:53 +0000739
740 zif->rtadv.MaxRtrAdvInterval = interval;
741 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
742 zif->rtadv.AdvIntervalTimer = 0;
743
744 return CMD_SUCCESS;
745}
746
paul718e3742002-12-13 20:15:29 +0000747DEFUN (ipv6_nd_ra_interval,
748 ipv6_nd_ra_interval_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400749 "ipv6 nd ra-interval <1-1800>",
hasso3e31cde2004-05-18 11:58:59 +0000750 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000751 "Neighbor discovery\n"
752 "Router Advertisement interval\n"
753 "Router Advertisement interval in seconds\n")
754{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400755 unsigned interval;
756 struct interface *ifp = (struct interface *) vty->index;
757 struct zebra_if *zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200758 struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000759
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400760 VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800);
761 if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime))
762 {
763 vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE);
764 return CMD_WARNING;
765 }
paul718e3742002-12-13 20:15:29 +0000766
vincent7cee1bb2005-03-25 13:08:53 +0000767 if (zif->rtadv.MaxRtrAdvInterval % 1000)
Feng Lu49f76092015-05-22 11:40:10 +0200768 zvrf->rtadv.adv_msec_if_count--;
vincent7cee1bb2005-03-25 13:08:53 +0000769
770 /* convert to milliseconds */
771 interval = interval * 1000;
772
paul718e3742002-12-13 20:15:29 +0000773 zif->rtadv.MaxRtrAdvInterval = interval;
774 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
775 zif->rtadv.AdvIntervalTimer = 0;
776
777 return CMD_SUCCESS;
778}
779
780DEFUN (no_ipv6_nd_ra_interval,
781 no_ipv6_nd_ra_interval_cmd,
782 "no ipv6 nd ra-interval",
783 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000784 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000785 "Neighbor discovery\n"
786 "Router Advertisement interval\n")
787{
788 struct interface *ifp;
789 struct zebra_if *zif;
Feng Lu49f76092015-05-22 11:40:10 +0200790 struct zebra_vrf *zvrf;
paul718e3742002-12-13 20:15:29 +0000791
792 ifp = (struct interface *) vty->index;
793 zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200794 zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000795
vincent7cee1bb2005-03-25 13:08:53 +0000796 if (zif->rtadv.MaxRtrAdvInterval % 1000)
Feng Lu49f76092015-05-22 11:40:10 +0200797 zvrf->rtadv.adv_msec_if_count--;
vincent7cee1bb2005-03-25 13:08:53 +0000798
paul718e3742002-12-13 20:15:29 +0000799 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
800 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
801 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
802
803 return CMD_SUCCESS;
804}
805
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400806ALIAS (no_ipv6_nd_ra_interval,
807 no_ipv6_nd_ra_interval_val_cmd,
808 "no ipv6 nd ra-interval <1-1800>",
809 NO_STR
810 "Interface IPv6 config commands\n"
811 "Neighbor discovery\n"
812 "Router Advertisement interval\n")
813
814ALIAS (no_ipv6_nd_ra_interval,
815 no_ipv6_nd_ra_interval_msec_val_cmd,
816 "no ipv6 nd ra-interval msec <1-1800000>",
817 NO_STR
818 "Interface IPv6 config commands\n"
819 "Neighbor discovery\n"
820 "Router Advertisement interval\n"
821 "Router Advertisement interval in milliseconds\n")
822
paul718e3742002-12-13 20:15:29 +0000823DEFUN (ipv6_nd_ra_lifetime,
824 ipv6_nd_ra_lifetime_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400825 "ipv6 nd ra-lifetime <0-9000>",
hasso3e31cde2004-05-18 11:58:59 +0000826 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000827 "Neighbor discovery\n"
828 "Router lifetime\n"
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400829 "Router lifetime in seconds (0 stands for a non-default gw)\n")
paul718e3742002-12-13 20:15:29 +0000830{
831 int lifetime;
832 struct interface *ifp;
833 struct zebra_if *zif;
834
835 ifp = (struct interface *) vty->index;
836 zif = ifp->info;
837
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400838 VTY_GET_INTEGER_RANGE ("router lifetime", lifetime, argv[0], 0, 9000);
paul718e3742002-12-13 20:15:29 +0000839
Denis Ovsienkod660f692011-12-30 21:55:49 +0400840 /* The value to be placed in the Router Lifetime field
841 * of Router Advertisements sent from the interface,
842 * in seconds. MUST be either zero or between
843 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400844 if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval))
paul718e3742002-12-13 20:15:29 +0000845 {
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400846 vty_out (vty, "This ra-lifetime would conflict with configured ra-interval%s", VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000847 return CMD_WARNING;
848 }
849
850 zif->rtadv.AdvDefaultLifetime = lifetime;
851
852 return CMD_SUCCESS;
853}
854
855DEFUN (no_ipv6_nd_ra_lifetime,
856 no_ipv6_nd_ra_lifetime_cmd,
857 "no ipv6 nd ra-lifetime",
858 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000859 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000860 "Neighbor discovery\n"
861 "Router lifetime\n")
862{
863 struct interface *ifp;
864 struct zebra_if *zif;
865
866 ifp = (struct interface *) vty->index;
867 zif = ifp->info;
868
Denis Ovsienkod660f692011-12-30 21:55:49 +0400869 zif->rtadv.AdvDefaultLifetime = -1;
paul718e3742002-12-13 20:15:29 +0000870
871 return CMD_SUCCESS;
872}
873
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400874ALIAS (no_ipv6_nd_ra_lifetime,
875 no_ipv6_nd_ra_lifetime_val_cmd,
876 "no ipv6 nd ra-lifetime <0-9000>",
877 NO_STR
878 "Interface IPv6 config commands\n"
879 "Neighbor discovery\n"
880 "Router lifetime\n"
881 "Router lifetime in seconds (0 stands for a non-default gw)\n")
882
paul718e3742002-12-13 20:15:29 +0000883DEFUN (ipv6_nd_reachable_time,
884 ipv6_nd_reachable_time_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400885 "ipv6 nd reachable-time <1-3600000>",
hasso3e31cde2004-05-18 11:58:59 +0000886 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000887 "Neighbor discovery\n"
888 "Reachable time\n"
889 "Reachable time in milliseconds\n")
890{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400891 struct interface *ifp = (struct interface *) vty->index;
892 struct zebra_if *zif = ifp->info;
893 VTY_GET_INTEGER_RANGE ("reachable time", zif->rtadv.AdvReachableTime, argv[0], 1, RTADV_MAX_REACHABLE_TIME);
paul718e3742002-12-13 20:15:29 +0000894 return CMD_SUCCESS;
895}
896
897DEFUN (no_ipv6_nd_reachable_time,
898 no_ipv6_nd_reachable_time_cmd,
899 "no ipv6 nd reachable-time",
900 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000901 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000902 "Neighbor discovery\n"
903 "Reachable time\n")
904{
905 struct interface *ifp;
906 struct zebra_if *zif;
907
908 ifp = (struct interface *) vty->index;
909 zif = ifp->info;
910
911 zif->rtadv.AdvReachableTime = 0;
912
913 return CMD_SUCCESS;
914}
915
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400916ALIAS (no_ipv6_nd_reachable_time,
917 no_ipv6_nd_reachable_time_val_cmd,
918 "no ipv6 nd reachable-time <1-3600000>",
919 NO_STR
920 "Interface IPv6 config commands\n"
921 "Neighbor discovery\n"
922 "Reachable time\n"
923 "Reachable time in milliseconds\n")
924
vincent7cee1bb2005-03-25 13:08:53 +0000925DEFUN (ipv6_nd_homeagent_preference,
926 ipv6_nd_homeagent_preference_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400927 "ipv6 nd home-agent-preference <0-65535>",
vincent7cee1bb2005-03-25 13:08:53 +0000928 "Interface IPv6 config commands\n"
929 "Neighbor discovery\n"
930 "Home Agent preference\n"
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400931 "preference value (default is 0, least preferred)\n")
vincent7cee1bb2005-03-25 13:08:53 +0000932{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400933 struct interface *ifp = (struct interface *) vty->index;
934 struct zebra_if *zif = ifp->info;
935 VTY_GET_INTEGER_RANGE ("home agent preference", zif->rtadv.HomeAgentPreference, argv[0], 0, 65535);
vincent7cee1bb2005-03-25 13:08:53 +0000936 return CMD_SUCCESS;
937}
938
939DEFUN (no_ipv6_nd_homeagent_preference,
940 no_ipv6_nd_homeagent_preference_cmd,
941 "no ipv6 nd home-agent-preference",
942 NO_STR
943 "Interface IPv6 config commands\n"
944 "Neighbor discovery\n"
945 "Home Agent preference\n")
946{
947 struct interface *ifp;
948 struct zebra_if *zif;
949
950 ifp = (struct interface *) vty->index;
951 zif = ifp->info;
952
953 zif->rtadv.HomeAgentPreference = 0;
954
955 return CMD_SUCCESS;
956}
957
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400958ALIAS (no_ipv6_nd_homeagent_preference,
959 no_ipv6_nd_homeagent_preference_val_cmd,
960 "no ipv6 nd home-agent-preference <0-65535>",
961 NO_STR
962 "Interface IPv6 config commands\n"
963 "Neighbor discovery\n"
964 "Home Agent preference\n"
965 "preference value (default is 0, least preferred)\n")
966
vincent7cee1bb2005-03-25 13:08:53 +0000967DEFUN (ipv6_nd_homeagent_lifetime,
968 ipv6_nd_homeagent_lifetime_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400969 "ipv6 nd home-agent-lifetime <0-65520>",
vincent7cee1bb2005-03-25 13:08:53 +0000970 "Interface IPv6 config commands\n"
971 "Neighbor discovery\n"
972 "Home Agent lifetime\n"
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400973 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
vincent7cee1bb2005-03-25 13:08:53 +0000974{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400975 struct interface *ifp = (struct interface *) vty->index;
976 struct zebra_if *zif = ifp->info;
977 VTY_GET_INTEGER_RANGE ("home agent lifetime", zif->rtadv.HomeAgentLifetime, argv[0], 0, RTADV_MAX_HALIFETIME);
vincent7cee1bb2005-03-25 13:08:53 +0000978 return CMD_SUCCESS;
979}
980
981DEFUN (no_ipv6_nd_homeagent_lifetime,
982 no_ipv6_nd_homeagent_lifetime_cmd,
983 "no ipv6 nd home-agent-lifetime",
984 NO_STR
985 "Interface IPv6 config commands\n"
986 "Neighbor discovery\n"
987 "Home Agent lifetime\n")
988{
989 struct interface *ifp;
990 struct zebra_if *zif;
991
992 ifp = (struct interface *) vty->index;
993 zif = ifp->info;
994
Denis Ovsienkod660f692011-12-30 21:55:49 +0400995 zif->rtadv.HomeAgentLifetime = -1;
vincent7cee1bb2005-03-25 13:08:53 +0000996
997 return CMD_SUCCESS;
998}
999
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001000ALIAS (no_ipv6_nd_homeagent_lifetime,
1001 no_ipv6_nd_homeagent_lifetime_val_cmd,
1002 "no ipv6 nd home-agent-lifetime <0-65520>",
1003 NO_STR
1004 "Interface IPv6 config commands\n"
1005 "Neighbor discovery\n"
1006 "Home Agent lifetime\n"
1007 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
1008
paul718e3742002-12-13 20:15:29 +00001009DEFUN (ipv6_nd_managed_config_flag,
1010 ipv6_nd_managed_config_flag_cmd,
1011 "ipv6 nd managed-config-flag",
hasso3e31cde2004-05-18 11:58:59 +00001012 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001013 "Neighbor discovery\n"
1014 "Managed address configuration flag\n")
1015{
1016 struct interface *ifp;
1017 struct zebra_if *zif;
1018
1019 ifp = (struct interface *) vty->index;
1020 zif = ifp->info;
1021
1022 zif->rtadv.AdvManagedFlag = 1;
1023
1024 return CMD_SUCCESS;
1025}
1026
1027DEFUN (no_ipv6_nd_managed_config_flag,
1028 no_ipv6_nd_managed_config_flag_cmd,
1029 "no ipv6 nd managed-config-flag",
1030 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001031 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001032 "Neighbor discovery\n"
1033 "Managed address configuration flag\n")
1034{
1035 struct interface *ifp;
1036 struct zebra_if *zif;
1037
1038 ifp = (struct interface *) vty->index;
1039 zif = ifp->info;
1040
1041 zif->rtadv.AdvManagedFlag = 0;
1042
1043 return CMD_SUCCESS;
1044}
1045
vincent7cee1bb2005-03-25 13:08:53 +00001046DEFUN (ipv6_nd_homeagent_config_flag,
1047 ipv6_nd_homeagent_config_flag_cmd,
1048 "ipv6 nd home-agent-config-flag",
1049 "Interface IPv6 config commands\n"
1050 "Neighbor discovery\n"
1051 "Home Agent configuration flag\n")
1052{
1053 struct interface *ifp;
1054 struct zebra_if *zif;
1055
1056 ifp = (struct interface *) vty->index;
1057 zif = ifp->info;
1058
1059 zif->rtadv.AdvHomeAgentFlag = 1;
1060
1061 return CMD_SUCCESS;
1062}
1063
1064DEFUN (no_ipv6_nd_homeagent_config_flag,
1065 no_ipv6_nd_homeagent_config_flag_cmd,
1066 "no ipv6 nd home-agent-config-flag",
1067 NO_STR
1068 "Interface IPv6 config commands\n"
1069 "Neighbor discovery\n"
1070 "Home Agent configuration flag\n")
1071{
1072 struct interface *ifp;
1073 struct zebra_if *zif;
1074
1075 ifp = (struct interface *) vty->index;
1076 zif = ifp->info;
1077
1078 zif->rtadv.AdvHomeAgentFlag = 0;
1079
1080 return CMD_SUCCESS;
1081}
1082
1083DEFUN (ipv6_nd_adv_interval_config_option,
1084 ipv6_nd_adv_interval_config_option_cmd,
1085 "ipv6 nd adv-interval-option",
1086 "Interface IPv6 config commands\n"
1087 "Neighbor discovery\n"
1088 "Advertisement Interval Option\n")
1089{
1090 struct interface *ifp;
1091 struct zebra_if *zif;
1092
1093 ifp = (struct interface *) vty->index;
1094 zif = ifp->info;
1095
1096 zif->rtadv.AdvIntervalOption = 1;
1097
1098 return CMD_SUCCESS;
1099}
1100
1101DEFUN (no_ipv6_nd_adv_interval_config_option,
1102 no_ipv6_nd_adv_interval_config_option_cmd,
1103 "no ipv6 nd adv-interval-option",
1104 NO_STR
1105 "Interface IPv6 config commands\n"
1106 "Neighbor discovery\n"
1107 "Advertisement Interval Option\n")
1108{
1109 struct interface *ifp;
1110 struct zebra_if *zif;
1111
1112 ifp = (struct interface *) vty->index;
1113 zif = ifp->info;
1114
1115 zif->rtadv.AdvIntervalOption = 0;
1116
1117 return CMD_SUCCESS;
1118}
1119
paul718e3742002-12-13 20:15:29 +00001120DEFUN (ipv6_nd_other_config_flag,
1121 ipv6_nd_other_config_flag_cmd,
1122 "ipv6 nd other-config-flag",
hasso3e31cde2004-05-18 11:58:59 +00001123 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001124 "Neighbor discovery\n"
1125 "Other statefull configuration flag\n")
1126{
1127 struct interface *ifp;
1128 struct zebra_if *zif;
1129
1130 ifp = (struct interface *) vty->index;
1131 zif = ifp->info;
1132
1133 zif->rtadv.AdvOtherConfigFlag = 1;
1134
1135 return CMD_SUCCESS;
1136}
1137
1138DEFUN (no_ipv6_nd_other_config_flag,
1139 no_ipv6_nd_other_config_flag_cmd,
1140 "no ipv6 nd other-config-flag",
1141 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001142 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001143 "Neighbor discovery\n"
1144 "Other statefull configuration flag\n")
1145{
1146 struct interface *ifp;
1147 struct zebra_if *zif;
1148
1149 ifp = (struct interface *) vty->index;
1150 zif = ifp->info;
1151
1152 zif->rtadv.AdvOtherConfigFlag = 0;
1153
1154 return CMD_SUCCESS;
1155}
1156
hasso3e31cde2004-05-18 11:58:59 +00001157DEFUN (ipv6_nd_prefix,
1158 ipv6_nd_prefix_cmd,
1159 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
vincent7cee1bb2005-03-25 13:08:53 +00001160 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)",
hasso3e31cde2004-05-18 11:58:59 +00001161 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001162 "Neighbor discovery\n"
1163 "Prefix information\n"
1164 "IPv6 prefix\n"
1165 "Valid lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001166 "Infinite valid lifetime\n"
paul718e3742002-12-13 20:15:29 +00001167 "Preferred lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001168 "Infinite preferred lifetime\n"
1169 "Do not use prefix for onlink determination\n"
vincent7cee1bb2005-03-25 13:08:53 +00001170 "Do not use prefix for autoconfiguration\n"
1171 "Set Router Address flag\n")
paul718e3742002-12-13 20:15:29 +00001172{
1173 int i;
1174 int ret;
hasso3e31cde2004-05-18 11:58:59 +00001175 int cursor = 1;
paul718e3742002-12-13 20:15:29 +00001176 struct interface *ifp;
1177 struct zebra_if *zebra_if;
1178 struct rtadv_prefix rp;
1179
1180 ifp = (struct interface *) vty->index;
1181 zebra_if = ifp->info;
1182
Denis Ovsienkoaca43b62012-01-08 18:27:12 +04001183 ret = str2prefix_ipv6 (argv[0], &rp.prefix);
paul718e3742002-12-13 20:15:29 +00001184 if (!ret)
1185 {
1186 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1187 return CMD_WARNING;
1188 }
Denis Ovsienko6bb12732012-01-08 17:46:34 +04001189 apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
hasso3e31cde2004-05-18 11:58:59 +00001190 rp.AdvOnLinkFlag = 1;
1191 rp.AdvAutonomousFlag = 1;
vincent7cee1bb2005-03-25 13:08:53 +00001192 rp.AdvRouterAddressFlag = 0;
hasso3e31cde2004-05-18 11:58:59 +00001193 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1194 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
paul718e3742002-12-13 20:15:29 +00001195
hasso3e31cde2004-05-18 11:58:59 +00001196 if (argc > 1)
paul718e3742002-12-13 20:15:29 +00001197 {
David Lamparter52f02b42015-04-10 09:14:30 +02001198 if ((isdigit((unsigned char)argv[1][0]))
1199 || strncmp (argv[1], "i", 1) == 0)
paul718e3742002-12-13 20:15:29 +00001200 {
hasso3e31cde2004-05-18 11:58:59 +00001201 if ( strncmp (argv[1], "i", 1) == 0)
1202 rp.AdvValidLifetime = UINT32_MAX;
1203 else
1204 rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1],
1205 (char **)NULL, 10);
1206
1207 if ( strncmp (argv[2], "i", 1) == 0)
1208 rp.AdvPreferredLifetime = UINT32_MAX;
1209 else
1210 rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2],
1211 (char **)NULL, 10);
1212
1213 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
1214 {
1215 vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
1216 return CMD_WARNING;
1217 }
1218 cursor = cursor + 2;
paul718e3742002-12-13 20:15:29 +00001219 }
hasso3e31cde2004-05-18 11:58:59 +00001220 if (argc > cursor)
paul718e3742002-12-13 20:15:29 +00001221 {
hasso3e31cde2004-05-18 11:58:59 +00001222 for (i = cursor; i < argc; i++)
1223 {
1224 if (strncmp (argv[i], "of", 2) == 0)
1225 rp.AdvOnLinkFlag = 0;
1226 if (strncmp (argv[i], "no", 2) == 0)
1227 rp.AdvAutonomousFlag = 0;
vincent7cee1bb2005-03-25 13:08:53 +00001228 if (strncmp (argv[i], "ro", 2) == 0)
1229 rp.AdvRouterAddressFlag = 1;
hasso3e31cde2004-05-18 11:58:59 +00001230 }
paul718e3742002-12-13 20:15:29 +00001231 }
1232 }
1233
1234 rtadv_prefix_set (zebra_if, &rp);
1235
1236 return CMD_SUCCESS;
1237}
1238
hasso3e31cde2004-05-18 11:58:59 +00001239ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001240 ipv6_nd_prefix_val_nortaddr_cmd,
1241 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1242 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
1243 "Interface IPv6 config commands\n"
1244 "Neighbor discovery\n"
1245 "Prefix information\n"
1246 "IPv6 prefix\n"
1247 "Valid lifetime in seconds\n"
1248 "Infinite valid lifetime\n"
1249 "Preferred lifetime in seconds\n"
1250 "Infinite preferred lifetime\n"
1251 "Do not use prefix for onlink determination\n"
1252 "Do not use prefix for autoconfiguration\n")
1253
1254ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001255 ipv6_nd_prefix_val_rev_cmd,
1256 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1257 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)",
1258 "Interface IPv6 config commands\n"
1259 "Neighbor discovery\n"
1260 "Prefix information\n"
1261 "IPv6 prefix\n"
1262 "Valid lifetime in seconds\n"
1263 "Infinite valid lifetime\n"
1264 "Preferred lifetime in seconds\n"
1265 "Infinite preferred lifetime\n"
1266 "Do not use prefix for autoconfiguration\n"
1267 "Do not use prefix for onlink determination\n")
1268
1269ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001270 ipv6_nd_prefix_val_rev_rtaddr_cmd,
1271 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1272 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)",
1273 "Interface IPv6 config commands\n"
1274 "Neighbor discovery\n"
1275 "Prefix information\n"
1276 "IPv6 prefix\n"
1277 "Valid lifetime in seconds\n"
1278 "Infinite valid lifetime\n"
1279 "Preferred lifetime in seconds\n"
1280 "Infinite preferred lifetime\n"
1281 "Do not use prefix for autoconfiguration\n"
1282 "Do not use prefix for onlink determination\n"
1283 "Set Router Address flag\n")
1284
1285ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001286 ipv6_nd_prefix_val_noauto_cmd,
1287 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1288 "(<0-4294967295>|infinite) (no-autoconfig|)",
1289 "Interface IPv6 config commands\n"
1290 "Neighbor discovery\n"
1291 "Prefix information\n"
1292 "IPv6 prefix\n"
1293 "Valid lifetime in seconds\n"
1294 "Infinite valid lifetime\n"
1295 "Preferred lifetime in seconds\n"
1296 "Infinite preferred lifetime\n"
vincent7cee1bb2005-03-25 13:08:53 +00001297 "Do not use prefix for autoconfiguration")
hasso3e31cde2004-05-18 11:58:59 +00001298
1299ALIAS (ipv6_nd_prefix,
1300 ipv6_nd_prefix_val_offlink_cmd,
1301 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1302 "(<0-4294967295>|infinite) (off-link|)",
1303 "Interface IPv6 config commands\n"
1304 "Neighbor discovery\n"
1305 "Prefix information\n"
1306 "IPv6 prefix\n"
1307 "Valid lifetime in seconds\n"
1308 "Infinite valid lifetime\n"
1309 "Preferred lifetime in seconds\n"
1310 "Infinite preferred lifetime\n"
1311 "Do not use prefix for onlink determination\n")
1312
1313ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001314 ipv6_nd_prefix_val_rtaddr_cmd,
1315 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1316 "(<0-4294967295>|infinite) (router-address|)",
1317 "Interface IPv6 config commands\n"
1318 "Neighbor discovery\n"
1319 "Prefix information\n"
1320 "IPv6 prefix\n"
1321 "Valid lifetime in seconds\n"
1322 "Infinite valid lifetime\n"
1323 "Preferred lifetime in seconds\n"
1324 "Infinite preferred lifetime\n"
1325 "Set Router Address flag\n")
1326
1327ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001328 ipv6_nd_prefix_val_cmd,
1329 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1330 "(<0-4294967295>|infinite)",
1331 "Interface IPv6 config commands\n"
1332 "Neighbor discovery\n"
1333 "Prefix information\n"
1334 "IPv6 prefix\n"
1335 "Valid lifetime in seconds\n"
1336 "Infinite valid lifetime\n"
1337 "Preferred lifetime in seconds\n"
1338 "Infinite preferred lifetime\n")
1339
1340ALIAS (ipv6_nd_prefix,
1341 ipv6_nd_prefix_noval_cmd,
1342 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)",
1343 "Interface IPv6 config commands\n"
1344 "Neighbor discovery\n"
1345 "Prefix information\n"
1346 "IPv6 prefix\n"
1347 "Do not use prefix for autoconfiguration\n"
1348 "Do not use prefix for onlink determination\n")
1349
1350ALIAS (ipv6_nd_prefix,
1351 ipv6_nd_prefix_noval_rev_cmd,
1352 "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)",
1353 "Interface IPv6 config commands\n"
1354 "Neighbor discovery\n"
1355 "Prefix information\n"
1356 "IPv6 prefix\n"
1357 "Do not use prefix for onlink determination\n"
1358 "Do not use prefix for autoconfiguration\n")
1359
1360ALIAS (ipv6_nd_prefix,
1361 ipv6_nd_prefix_noval_noauto_cmd,
1362 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)",
1363 "Interface IPv6 config commands\n"
1364 "Neighbor discovery\n"
1365 "Prefix information\n"
1366 "IPv6 prefix\n"
1367 "Do not use prefix for autoconfiguration\n")
1368
1369ALIAS (ipv6_nd_prefix,
1370 ipv6_nd_prefix_noval_offlink_cmd,
1371 "ipv6 nd prefix X:X::X:X/M (off-link|)",
1372 "Interface IPv6 config commands\n"
1373 "Neighbor discovery\n"
1374 "Prefix information\n"
1375 "IPv6 prefix\n"
1376 "Do not use prefix for onlink determination\n")
1377
1378ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001379 ipv6_nd_prefix_noval_rtaddr_cmd,
1380 "ipv6 nd prefix X:X::X:X/M (router-address|)",
1381 "Interface IPv6 config commands\n"
1382 "Neighbor discovery\n"
1383 "Prefix information\n"
1384 "IPv6 prefix\n"
1385 "Set Router Address flag\n")
1386
1387ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001388 ipv6_nd_prefix_prefix_cmd,
1389 "ipv6 nd prefix X:X::X:X/M",
1390 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001391 "Neighbor discovery\n"
1392 "Prefix information\n"
1393 "IPv6 prefix\n")
1394
hasso3e31cde2004-05-18 11:58:59 +00001395DEFUN (no_ipv6_nd_prefix,
1396 no_ipv6_nd_prefix_cmd,
1397 "no ipv6 nd prefix IPV6PREFIX",
paul718e3742002-12-13 20:15:29 +00001398 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001399 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001400 "Neighbor discovery\n"
1401 "Prefix information\n"
1402 "IPv6 prefix\n")
1403{
1404 int ret;
1405 struct interface *ifp;
1406 struct zebra_if *zebra_if;
1407 struct rtadv_prefix rp;
1408
1409 ifp = (struct interface *) vty->index;
1410 zebra_if = ifp->info;
1411
Denis Ovsienkoaca43b62012-01-08 18:27:12 +04001412 ret = str2prefix_ipv6 (argv[0], &rp.prefix);
paul718e3742002-12-13 20:15:29 +00001413 if (!ret)
1414 {
1415 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1416 return CMD_WARNING;
1417 }
Denis Ovsienko6bb12732012-01-08 17:46:34 +04001418 apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
paul718e3742002-12-13 20:15:29 +00001419
1420 ret = rtadv_prefix_reset (zebra_if, &rp);
1421 if (!ret)
1422 {
1423 vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
1424 return CMD_WARNING;
1425 }
1426
1427 return CMD_SUCCESS;
1428}
Chris Caputob60668d2009-05-03 04:40:57 +00001429
1430DEFUN (ipv6_nd_router_preference,
1431 ipv6_nd_router_preference_cmd,
1432 "ipv6 nd router-preference (high|medium|low)",
1433 "Interface IPv6 config commands\n"
1434 "Neighbor discovery\n"
1435 "Default router preference\n"
1436 "High default router preference\n"
1437 "Low default router preference\n"
1438 "Medium default router preference (default)\n")
1439{
1440 struct interface *ifp;
1441 struct zebra_if *zif;
1442 int i = 0;
1443
1444 ifp = (struct interface *) vty->index;
1445 zif = ifp->info;
1446
1447 while (0 != rtadv_pref_strs[i])
1448 {
1449 if (strncmp (argv[0], rtadv_pref_strs[i], 1) == 0)
1450 {
1451 zif->rtadv.DefaultPreference = i;
1452 return CMD_SUCCESS;
1453 }
1454 i++;
1455 }
1456
1457 return CMD_ERR_NO_MATCH;
1458}
1459
1460DEFUN (no_ipv6_nd_router_preference,
1461 no_ipv6_nd_router_preference_cmd,
1462 "no ipv6 nd router-preference",
1463 NO_STR
1464 "Interface IPv6 config commands\n"
1465 "Neighbor discovery\n"
1466 "Default router preference\n")
1467{
1468 struct interface *ifp;
1469 struct zebra_if *zif;
1470
1471 ifp = (struct interface *) vty->index;
1472 zif = ifp->info;
1473
1474 zif->rtadv.DefaultPreference = RTADV_PREF_MEDIUM; /* Default per RFC4191. */
1475
1476 return CMD_SUCCESS;
1477}
1478
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001479ALIAS (no_ipv6_nd_router_preference,
1480 no_ipv6_nd_router_preference_val_cmd,
Christian Franke2b005152013-09-30 12:27:49 +00001481 "no ipv6 nd router-preference (high|medium|low)",
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001482 NO_STR
1483 "Interface IPv6 config commands\n"
1484 "Neighbor discovery\n"
1485 "Default router preference\n"
1486 "High default router preference\n"
1487 "Low default router preference\n"
1488 "Medium default router preference (default)\n")
1489
Denis Ovsienko6ae93c02011-12-27 10:45:36 +04001490DEFUN (ipv6_nd_mtu,
1491 ipv6_nd_mtu_cmd,
1492 "ipv6 nd mtu <1-65535>",
1493 "Interface IPv6 config commands\n"
1494 "Neighbor discovery\n"
1495 "Advertised MTU\n"
1496 "MTU in bytes\n")
1497{
1498 struct interface *ifp = (struct interface *) vty->index;
1499 struct zebra_if *zif = ifp->info;
1500 VTY_GET_INTEGER_RANGE ("MTU", zif->rtadv.AdvLinkMTU, argv[0], 1, 65535);
1501 return CMD_SUCCESS;
1502}
1503
1504DEFUN (no_ipv6_nd_mtu,
1505 no_ipv6_nd_mtu_cmd,
1506 "no ipv6 nd mtu",
1507 NO_STR
1508 "Interface IPv6 config commands\n"
1509 "Neighbor discovery\n"
1510 "Advertised MTU\n")
1511{
1512 struct interface *ifp = (struct interface *) vty->index;
1513 struct zebra_if *zif = ifp->info;
1514 zif->rtadv.AdvLinkMTU = 0;
1515 return CMD_SUCCESS;
1516}
1517
1518ALIAS (no_ipv6_nd_mtu,
1519 no_ipv6_nd_mtu_val_cmd,
1520 "no ipv6 nd mtu <1-65535>",
1521 NO_STR
1522 "Interface IPv6 config commands\n"
1523 "Neighbor discovery\n"
1524 "Advertised MTU\n"
1525 "MTU in bytes\n")
1526
paul718e3742002-12-13 20:15:29 +00001527/* Write configuration about router advertisement. */
1528void
1529rtadv_config_write (struct vty *vty, struct interface *ifp)
1530{
1531 struct zebra_if *zif;
hasso52dc7ee2004-09-23 19:18:23 +00001532 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001533 struct rtadv_prefix *rprefix;
Timo Teräsbe6335d2015-05-23 11:08:41 +03001534 char buf[PREFIX_STRLEN];
vincent7cee1bb2005-03-25 13:08:53 +00001535 int interval;
paul718e3742002-12-13 20:15:29 +00001536
paul718e3742002-12-13 20:15:29 +00001537 zif = ifp->info;
1538
1539 if (! if_is_loopback (ifp))
1540 {
1541 if (zif->rtadv.AdvSendAdvertisements)
1542 vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
1543 else
1544 vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
1545 }
1546
vincent7cee1bb2005-03-25 13:08:53 +00001547
1548 interval = zif->rtadv.MaxRtrAdvInterval;
1549 if (interval % 1000)
1550 vty_out (vty, " ipv6 nd ra-interval msec %d%s", interval,
1551 VTY_NEWLINE);
1552 else
1553 if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
1554 vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000,
paul718e3742002-12-13 20:15:29 +00001555 VTY_NEWLINE);
1556
Denis Ovsienko6134b872011-12-27 18:49:15 +04001557 if (zif->rtadv.AdvIntervalOption)
1558 vty_out (vty, " ipv6 nd adv-interval-option%s", VTY_NEWLINE);
1559
Denis Ovsienkod660f692011-12-30 21:55:49 +04001560 if (zif->rtadv.AdvDefaultLifetime != -1)
paul718e3742002-12-13 20:15:29 +00001561 vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
1562 VTY_NEWLINE);
1563
Denis Ovsienko6134b872011-12-27 18:49:15 +04001564 if (zif->rtadv.HomeAgentPreference)
1565 vty_out (vty, " ipv6 nd home-agent-preference %u%s",
1566 zif->rtadv.HomeAgentPreference, VTY_NEWLINE);
1567
Denis Ovsienkod660f692011-12-30 21:55:49 +04001568 if (zif->rtadv.HomeAgentLifetime != -1)
Denis Ovsienko6134b872011-12-27 18:49:15 +04001569 vty_out (vty, " ipv6 nd home-agent-lifetime %u%s",
1570 zif->rtadv.HomeAgentLifetime, VTY_NEWLINE);
1571
1572 if (zif->rtadv.AdvHomeAgentFlag)
1573 vty_out (vty, " ipv6 nd home-agent-config-flag%s", VTY_NEWLINE);
1574
paul718e3742002-12-13 20:15:29 +00001575 if (zif->rtadv.AdvReachableTime)
1576 vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
1577 VTY_NEWLINE);
1578
1579 if (zif->rtadv.AdvManagedFlag)
1580 vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
1581
1582 if (zif->rtadv.AdvOtherConfigFlag)
1583 vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
1584
Chris Caputob60668d2009-05-03 04:40:57 +00001585 if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
1586 vty_out (vty, " ipv6 nd router-preference %s%s",
1587 rtadv_pref_strs[zif->rtadv.DefaultPreference],
1588 VTY_NEWLINE);
1589
Denis Ovsienko6ae93c02011-12-27 10:45:36 +04001590 if (zif->rtadv.AdvLinkMTU)
1591 vty_out (vty, " ipv6 nd mtu %d%s", zif->rtadv.AdvLinkMTU, VTY_NEWLINE);
1592
paul1eb8ef22005-04-07 07:30:20 +00001593 for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
paul718e3742002-12-13 20:15:29 +00001594 {
Timo Teräsbe6335d2015-05-23 11:08:41 +03001595 vty_out (vty, " ipv6 nd prefix %s",
1596 prefix2str (&rprefix->prefix, buf, sizeof(buf)));
hasso3e31cde2004-05-18 11:58:59 +00001597 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) ||
1598 (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME))
1599 {
1600 if (rprefix->AdvValidLifetime == UINT32_MAX)
1601 vty_out (vty, " infinite");
1602 else
1603 vty_out (vty, " %u", rprefix->AdvValidLifetime);
1604 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1605 vty_out (vty, " infinite");
1606 else
1607 vty_out (vty, " %u", rprefix->AdvPreferredLifetime);
1608 }
1609 if (!rprefix->AdvOnLinkFlag)
1610 vty_out (vty, " off-link");
1611 if (!rprefix->AdvAutonomousFlag)
1612 vty_out (vty, " no-autoconfig");
vincent7cee1bb2005-03-25 13:08:53 +00001613 if (rprefix->AdvRouterAddressFlag)
1614 vty_out (vty, " router-address");
paul718e3742002-12-13 20:15:29 +00001615 vty_out (vty, "%s", VTY_NEWLINE);
1616 }
1617}
1618
paul718e3742002-12-13 20:15:29 +00001619
paula1ac18c2005-06-28 17:17:12 +00001620static void
Feng Lu49f76092015-05-22 11:40:10 +02001621rtadv_event (struct zebra_vrf *zvrf, enum rtadv_event event, int val)
paul718e3742002-12-13 20:15:29 +00001622{
Feng Lu49f76092015-05-22 11:40:10 +02001623 struct rtadv *rtadv = &zvrf->rtadv;
1624
paul718e3742002-12-13 20:15:29 +00001625 switch (event)
1626 {
1627 case RTADV_START:
1628 if (! rtadv->ra_read)
Feng Lu49f76092015-05-22 11:40:10 +02001629 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val);
paul718e3742002-12-13 20:15:29 +00001630 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001631 rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
Feng Lu49f76092015-05-22 11:40:10 +02001632 zvrf, 0);
paul718e3742002-12-13 20:15:29 +00001633 break;
1634 case RTADV_STOP:
1635 if (rtadv->ra_timer)
1636 {
1637 thread_cancel (rtadv->ra_timer);
1638 rtadv->ra_timer = NULL;
1639 }
1640 if (rtadv->ra_read)
1641 {
1642 thread_cancel (rtadv->ra_read);
1643 rtadv->ra_read = NULL;
1644 }
1645 break;
1646 case RTADV_TIMER:
1647 if (! rtadv->ra_timer)
Feng Lu49f76092015-05-22 11:40:10 +02001648 rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, zvrf,
hasso3e31cde2004-05-18 11:58:59 +00001649 val);
paul718e3742002-12-13 20:15:29 +00001650 break;
vincent7cee1bb2005-03-25 13:08:53 +00001651 case RTADV_TIMER_MSEC:
1652 if (! rtadv->ra_timer)
1653 rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer,
Feng Lu49f76092015-05-22 11:40:10 +02001654 zvrf, val);
vincent7cee1bb2005-03-25 13:08:53 +00001655 break;
paul718e3742002-12-13 20:15:29 +00001656 case RTADV_READ:
1657 if (! rtadv->ra_read)
Feng Lu49f76092015-05-22 11:40:10 +02001658 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val);
paul718e3742002-12-13 20:15:29 +00001659 break;
1660 default:
1661 break;
1662 }
1663 return;
1664}
1665
1666void
Feng Lu49f76092015-05-22 11:40:10 +02001667rtadv_init (struct zebra_vrf *zvrf)
paul718e3742002-12-13 20:15:29 +00001668{
Feng Lu49f76092015-05-22 11:40:10 +02001669 zvrf->rtadv.sock = rtadv_make_socket (zvrf->vrf_id);
1670}
paul718e3742002-12-13 20:15:29 +00001671
Feng Lu49f76092015-05-22 11:40:10 +02001672void
1673rtadv_terminate (struct zebra_vrf *zvrf)
1674{
1675 rtadv_event (zvrf, RTADV_STOP, 0);
paul718e3742002-12-13 20:15:29 +00001676
Feng Lu49f76092015-05-22 11:40:10 +02001677 if (zvrf->rtadv.sock >= 0)
1678 {
1679 close (zvrf->rtadv.sock);
1680 zvrf->rtadv.sock = -1;
1681 }
paul718e3742002-12-13 20:15:29 +00001682
Feng Lu49f76092015-05-22 11:40:10 +02001683 zvrf->rtadv.adv_if_count = 0;
1684 zvrf->rtadv.adv_msec_if_count = 0;
1685}
1686
1687void
1688rtadv_cmd_init (void)
1689{
paul718e3742002-12-13 20:15:29 +00001690 install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1691 install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
paul718e3742002-12-13 20:15:29 +00001692 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001693 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
paul718e3742002-12-13 20:15:29 +00001694 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001695 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_val_cmd);
1696 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_msec_val_cmd);
paul718e3742002-12-13 20:15:29 +00001697 install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1698 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001699 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_val_cmd);
paul718e3742002-12-13 20:15:29 +00001700 install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1701 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001702 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_val_cmd);
paul718e3742002-12-13 20:15:29 +00001703 install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1704 install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1705 install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1706 install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001707 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
1708 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
1709 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
1710 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001711 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_val_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001712 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
1713 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001714 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_val_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001715 install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd);
1716 install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001717 install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001718 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd);
1719 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001720 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd);
1721 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd);
1722 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001723 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001724 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd);
1725 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd);
1726 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd);
1727 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd);
1728 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001729 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001730 install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
1731 install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
Chris Caputob60668d2009-05-03 04:40:57 +00001732 install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
1733 install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001734 install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_val_cmd);
Denis Ovsienko6ae93c02011-12-27 10:45:36 +04001735 install_element (INTERFACE_NODE, &ipv6_nd_mtu_cmd);
1736 install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
1737 install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd);
paul718e3742002-12-13 20:15:29 +00001738}
1739
paula1ac18c2005-06-28 17:17:12 +00001740static int
paul718e3742002-12-13 20:15:29 +00001741if_join_all_router (int sock, struct interface *ifp)
1742{
1743 int ret;
1744
1745 struct ipv6_mreq mreq;
1746
1747 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1748 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1749 mreq.ipv6mr_interface = ifp->ifindex;
1750
1751 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1752 (char *) &mreq, sizeof mreq);
1753 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001754 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001755
1756 zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1757
1758 return 0;
1759}
1760
paula1ac18c2005-06-28 17:17:12 +00001761static int
paul718e3742002-12-13 20:15:29 +00001762if_leave_all_router (int sock, struct interface *ifp)
1763{
1764 int ret;
1765
1766 struct ipv6_mreq mreq;
1767
1768 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1769 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1770 mreq.ipv6mr_interface = ifp->ifindex;
1771
1772 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1773 (char *) &mreq, sizeof mreq);
1774 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001775 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001776
1777 zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1778
1779 return 0;
1780}
1781
1782#else
1783void
Feng Lu49f76092015-05-22 11:40:10 +02001784rtadv_init (struct zebra_vrf *zvrf)
1785{
1786 /* Empty.*/;
1787}
1788void
1789rtadv_terminate (struct zebra_vrf *zvrf)
1790{
1791 /* Empty.*/;
1792}
1793void
1794rtadv_cmd_init (void)
paul718e3742002-12-13 20:15:29 +00001795{
1796 /* Empty.*/;
1797}
1798#endif /* RTADV && HAVE_IPV6 */