blob: 9450f9a92d1300db6fe8b69b388e6f91d6a19bce [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
Donald Sharp64257732015-11-20 08:33:30 -050044#if defined (HAVE_IPV6) && defined (HAVE_RTADV)
paul718e3742002-12-13 20:15:29 +000045
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,
Paul Jakma9099f9b2016-01-18 10:12:10 +000073 struct sockaddr_in6 *from, ifindex_t *ifindex,
paul718e3742002-12-13 20:15:29 +000074 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. */
paul718e3742002-12-13 20:15:29 +0000297 if (ifp->hw_addr_len != 0)
298 {
299 buf[len++] = ND_OPT_SOURCE_LINKADDR;
David Ward50adf782009-08-31 10:42:06 -0400300
301 /* Option length should be rounded up to next octet if
302 the link address does not end on an octet boundary. */
303 buf[len++] = (ifp->hw_addr_len + 9) >> 3;
paul718e3742002-12-13 20:15:29 +0000304
305 memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
306 len += ifp->hw_addr_len;
David Ward50adf782009-08-31 10:42:06 -0400307
308 /* Pad option to end on an octet boundary. */
309 memset (buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7);
310 len += -(ifp->hw_addr_len + 2) & 0x7;
paul718e3742002-12-13 20:15:29 +0000311 }
paul718e3742002-12-13 20:15:29 +0000312
Denis Ovsienko6ae93c02011-12-27 10:45:36 +0400313 /* MTU */
314 if (zif->rtadv.AdvLinkMTU)
315 {
316 struct nd_opt_mtu * opt = (struct nd_opt_mtu *) (buf + len);
317 opt->nd_opt_mtu_type = ND_OPT_MTU;
318 opt->nd_opt_mtu_len = 1;
319 opt->nd_opt_mtu_reserved = 0;
320 opt->nd_opt_mtu_mtu = htonl (zif->rtadv.AdvLinkMTU);
321 len += sizeof (struct nd_opt_mtu);
322 }
323
paul718e3742002-12-13 20:15:29 +0000324 msg.msg_name = (void *) &addr;
325 msg.msg_namelen = sizeof (struct sockaddr_in6);
326 msg.msg_iov = &iov;
327 msg.msg_iovlen = 1;
328 msg.msg_control = (void *) adata;
gdtf841e022004-08-11 19:20:01 +0000329 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
gdt57492d52004-08-11 18:06:38 +0000330 msg.msg_flags = 0;
paul718e3742002-12-13 20:15:29 +0000331 iov.iov_base = buf;
332 iov.iov_len = len;
333
ajsb99760a2005-01-04 16:24:43 +0000334 cmsgptr = ZCMSG_FIRSTHDR(&msg);
gdt57492d52004-08-11 18:06:38 +0000335 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
paul718e3742002-12-13 20:15:29 +0000336 cmsgptr->cmsg_level = IPPROTO_IPV6;
337 cmsgptr->cmsg_type = IPV6_PKTINFO;
gdt80893812004-08-11 15:58:00 +0000338
paul718e3742002-12-13 20:15:29 +0000339 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
340 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
341 pkt->ipi6_ifindex = ifp->ifindex;
342
343 ret = sendmsg (sock, &msg, 0);
gdt9ccabd12004-01-06 18:23:02 +0000344 if (ret < 0)
345 {
346 zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n",
ajs6099b3b2004-11-20 02:06:59 +0000347 errno, safe_strerror(errno));
gdt9ccabd12004-01-06 18:23:02 +0000348 }
paul718e3742002-12-13 20:15:29 +0000349}
350
paula1ac18c2005-06-28 17:17:12 +0000351static int
paul718e3742002-12-13 20:15:29 +0000352rtadv_timer (struct thread *thread)
353{
Feng Lu49f76092015-05-22 11:40:10 +0200354 struct zebra_vrf *zvrf = THREAD_ARG (thread);
paul1eb8ef22005-04-07 07:30:20 +0000355 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000356 struct interface *ifp;
357 struct zebra_if *zif;
vincent7cee1bb2005-03-25 13:08:53 +0000358 int period;
paul718e3742002-12-13 20:15:29 +0000359
Feng Lu49f76092015-05-22 11:40:10 +0200360 zvrf->rtadv.ra_timer = NULL;
361 if (zvrf->rtadv.adv_msec_if_count == 0)
vincent7cee1bb2005-03-25 13:08:53 +0000362 {
363 period = 1000; /* 1 s */
Feng Lu49f76092015-05-22 11:40:10 +0200364 rtadv_event (zvrf, RTADV_TIMER, 1 /* 1 s */);
vincent7cee1bb2005-03-25 13:08:53 +0000365 }
366 else
367 {
368 period = 10; /* 10 ms */
Feng Lu49f76092015-05-22 11:40:10 +0200369 rtadv_event (zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */);
vincent7cee1bb2005-03-25 13:08:53 +0000370 }
paul718e3742002-12-13 20:15:29 +0000371
Feng Lu49f76092015-05-22 11:40:10 +0200372 for (ALL_LIST_ELEMENTS (vrf_iflist (zvrf->vrf_id), node, nnode, ifp))
paul718e3742002-12-13 20:15:29 +0000373 {
Denis Ovsienkofb5174a2011-12-27 10:18:47 +0400374 if (if_is_loopback (ifp) || ! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +0000375 continue;
376
377 zif = ifp->info;
378
379 if (zif->rtadv.AdvSendAdvertisements)
vincent7cee1bb2005-03-25 13:08:53 +0000380 {
381 zif->rtadv.AdvIntervalTimer -= period;
382 if (zif->rtadv.AdvIntervalTimer <= 0)
383 {
Denis Ovsienkod660f692011-12-30 21:55:49 +0400384 /* FIXME: using MaxRtrAdvInterval each time isn't what section
385 6.2.4 of RFC4861 tells to do. */
vincent7cee1bb2005-03-25 13:08:53 +0000386 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
Feng Lu49f76092015-05-22 11:40:10 +0200387 rtadv_send_packet (zvrf->rtadv.sock, ifp);
vincent7cee1bb2005-03-25 13:08:53 +0000388 }
389 }
paul718e3742002-12-13 20:15:29 +0000390 }
391 return 0;
392}
393
paula1ac18c2005-06-28 17:17:12 +0000394static void
paul718e3742002-12-13 20:15:29 +0000395rtadv_process_solicit (struct interface *ifp)
396{
Feng Lu49f76092015-05-22 11:40:10 +0200397 struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000398
Feng Lu49f76092015-05-22 11:40:10 +0200399 zlog_info ("Router solicitation received on %s vrf %u", ifp->name, zvrf->vrf_id);
400
401 rtadv_send_packet (zvrf->rtadv.sock, ifp);
paul718e3742002-12-13 20:15:29 +0000402}
403
paula1ac18c2005-06-28 17:17:12 +0000404static void
405rtadv_process_advert (void)
paul718e3742002-12-13 20:15:29 +0000406{
407 zlog_info ("Router advertisement received");
408}
409
paula1ac18c2005-06-28 17:17:12 +0000410static void
Paul Jakma9099f9b2016-01-18 10:12:10 +0000411rtadv_process_packet (u_char *buf, unsigned int len, ifindex_t ifindex,
Feng Lu49f76092015-05-22 11:40:10 +0200412 int hoplimit, vrf_id_t vrf_id)
paul718e3742002-12-13 20:15:29 +0000413{
414 struct icmp6_hdr *icmph;
415 struct interface *ifp;
416 struct zebra_if *zif;
417
418 /* Interface search. */
Feng Lu49f76092015-05-22 11:40:10 +0200419 ifp = if_lookup_by_index_vrf (ifindex, vrf_id);
paul718e3742002-12-13 20:15:29 +0000420 if (ifp == NULL)
421 {
Feng Lu49f76092015-05-22 11:40:10 +0200422 zlog_warn ("Unknown interface index: %d, vrf %u", ifindex, vrf_id);
paul718e3742002-12-13 20:15:29 +0000423 return;
424 }
425
426 if (if_is_loopback (ifp))
427 return;
428
429 /* Check interface configuration. */
430 zif = ifp->info;
431 if (! zif->rtadv.AdvSendAdvertisements)
432 return;
433
434 /* ICMP message length check. */
435 if (len < sizeof (struct icmp6_hdr))
436 {
437 zlog_warn ("Invalid ICMPV6 packet length: %d", len);
438 return;
439 }
440
441 icmph = (struct icmp6_hdr *) buf;
442
443 /* ICMP message type check. */
444 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
445 icmph->icmp6_type != ND_ROUTER_ADVERT)
446 {
447 zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
448 return;
449 }
450
451 /* Hoplimit check. */
452 if (hoplimit >= 0 && hoplimit != 255)
453 {
454 zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
455 hoplimit);
456 return;
457 }
458
459 /* Check ICMP message type. */
460 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
461 rtadv_process_solicit (ifp);
462 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
463 rtadv_process_advert ();
464
465 return;
466}
467
paula1ac18c2005-06-28 17:17:12 +0000468static int
paul718e3742002-12-13 20:15:29 +0000469rtadv_read (struct thread *thread)
470{
471 int sock;
472 int len;
473 u_char buf[RTADV_MSG_SIZE];
474 struct sockaddr_in6 from;
Paul Jakma9099f9b2016-01-18 10:12:10 +0000475 ifindex_t ifindex = 0;
paul718e3742002-12-13 20:15:29 +0000476 int hoplimit = -1;
Feng Lu49f76092015-05-22 11:40:10 +0200477 struct zebra_vrf *zvrf = THREAD_ARG (thread);
paul718e3742002-12-13 20:15:29 +0000478
479 sock = THREAD_FD (thread);
Feng Lu49f76092015-05-22 11:40:10 +0200480 zvrf->rtadv.ra_read = NULL;
paul718e3742002-12-13 20:15:29 +0000481
482 /* Register myself. */
Feng Lu49f76092015-05-22 11:40:10 +0200483 rtadv_event (zvrf, RTADV_READ, sock);
paul718e3742002-12-13 20:15:29 +0000484
485 len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
486
487 if (len < 0)
488 {
ajs6099b3b2004-11-20 02:06:59 +0000489 zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000490 return len;
491 }
492
Feng Lu49f76092015-05-22 11:40:10 +0200493 rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit, zvrf->vrf_id);
paul718e3742002-12-13 20:15:29 +0000494
495 return 0;
496}
497
paula1ac18c2005-06-28 17:17:12 +0000498static int
Feng Lu49f76092015-05-22 11:40:10 +0200499rtadv_make_socket (vrf_id_t vrf_id)
paul718e3742002-12-13 20:15:29 +0000500{
501 int sock;
502 int ret;
503 struct icmp6_filter filter;
504
pauledd7c242003-06-04 13:59:38 +0000505 if ( zserv_privs.change (ZPRIVS_RAISE) )
506 zlog_err ("rtadv_make_socket: could not raise privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000507 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000508
Feng Lu49f76092015-05-22 11:40:10 +0200509 sock = vrf_socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, vrf_id);
paul718e3742002-12-13 20:15:29 +0000510
pauledd7c242003-06-04 13:59:38 +0000511 if ( zserv_privs.change (ZPRIVS_LOWER) )
512 zlog_err ("rtadv_make_socket: could not lower privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000513 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000514
paul718e3742002-12-13 20:15:29 +0000515 /* When we can't make ICMPV6 socket simply back. Router
516 advertisement feature will not be supported. */
517 if (sock < 0)
Morgan Stewart26b663d2015-09-16 13:17:54 -0400518 {
519 close (sock);
520 return -1;
521 }
paul718e3742002-12-13 20:15:29 +0000522
523 ret = setsockopt_ipv6_pktinfo (sock, 1);
524 if (ret < 0)
Morgan Stewart26b663d2015-09-16 13:17:54 -0400525 {
526 close (sock);
527 return ret;
528 }
paul718e3742002-12-13 20:15:29 +0000529 ret = setsockopt_ipv6_multicast_loop (sock, 0);
530 if (ret < 0)
Morgan Stewart26b663d2015-09-16 13:17:54 -0400531 {
532 close (sock);
533 return ret;
534 }
paul718e3742002-12-13 20:15:29 +0000535 ret = setsockopt_ipv6_unicast_hops (sock, 255);
536 if (ret < 0)
Morgan Stewart26b663d2015-09-16 13:17:54 -0400537 {
538 close (sock);
539 return ret;
540 }
paul718e3742002-12-13 20:15:29 +0000541 ret = setsockopt_ipv6_multicast_hops (sock, 255);
542 if (ret < 0)
Morgan Stewart26b663d2015-09-16 13:17:54 -0400543 {
544 close (sock);
545 return ret;
546 }
paul718e3742002-12-13 20:15:29 +0000547 ret = setsockopt_ipv6_hoplimit (sock, 1);
548 if (ret < 0)
Morgan Stewart26b663d2015-09-16 13:17:54 -0400549 {
550 close (sock);
551 return ret;
552 }
paul718e3742002-12-13 20:15:29 +0000553
554 ICMP6_FILTER_SETBLOCKALL(&filter);
555 ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
556 ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
557
558 ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
559 sizeof (struct icmp6_filter));
560 if (ret < 0)
561 {
ajs6099b3b2004-11-20 02:06:59 +0000562 zlog_info ("ICMP6_FILTER set fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000563 return ret;
564 }
565
566 return sock;
567}
David Lamparter6b0655a2014-06-04 06:53:35 +0200568
paula1ac18c2005-06-28 17:17:12 +0000569static struct rtadv_prefix *
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800570rtadv_prefix_new (void)
paul718e3742002-12-13 20:15:29 +0000571{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700572 return XCALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
paul718e3742002-12-13 20:15:29 +0000573}
574
paula1ac18c2005-06-28 17:17:12 +0000575static void
paul718e3742002-12-13 20:15:29 +0000576rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
577{
578 XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
579}
580
paula1ac18c2005-06-28 17:17:12 +0000581static struct rtadv_prefix *
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400582rtadv_prefix_lookup (struct list *rplist, struct prefix_ipv6 *p)
paul718e3742002-12-13 20:15:29 +0000583{
hasso52dc7ee2004-09-23 19:18:23 +0000584 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000585 struct rtadv_prefix *rprefix;
586
paul1eb8ef22005-04-07 07:30:20 +0000587 for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix))
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400588 if (prefix_same ((struct prefix *) &rprefix->prefix, (struct prefix *) p))
paul1eb8ef22005-04-07 07:30:20 +0000589 return rprefix;
paul718e3742002-12-13 20:15:29 +0000590 return NULL;
591}
592
paula1ac18c2005-06-28 17:17:12 +0000593static struct rtadv_prefix *
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400594rtadv_prefix_get (struct list *rplist, struct prefix_ipv6 *p)
paul718e3742002-12-13 20:15:29 +0000595{
596 struct rtadv_prefix *rprefix;
597
598 rprefix = rtadv_prefix_lookup (rplist, p);
599 if (rprefix)
600 return rprefix;
601
602 rprefix = rtadv_prefix_new ();
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400603 memcpy (&rprefix->prefix, p, sizeof (struct prefix_ipv6));
paul718e3742002-12-13 20:15:29 +0000604 listnode_add (rplist, rprefix);
605
606 return rprefix;
607}
608
paula1ac18c2005-06-28 17:17:12 +0000609static void
paul718e3742002-12-13 20:15:29 +0000610rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
611{
612 struct rtadv_prefix *rprefix;
613
614 rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
615
616 /* Set parameters. */
617 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
618 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
619 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
620 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
vincent7cee1bb2005-03-25 13:08:53 +0000621 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
paul718e3742002-12-13 20:15:29 +0000622}
623
paula1ac18c2005-06-28 17:17:12 +0000624static int
paul718e3742002-12-13 20:15:29 +0000625rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
626{
627 struct rtadv_prefix *rprefix;
628
629 rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
630 if (rprefix != NULL)
631 {
632 listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
633 rtadv_prefix_free (rprefix);
634 return 1;
635 }
636 else
637 return 0;
638}
639
640DEFUN (ipv6_nd_suppress_ra,
641 ipv6_nd_suppress_ra_cmd,
642 "ipv6 nd suppress-ra",
hasso3e31cde2004-05-18 11:58:59 +0000643 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000644 "Neighbor discovery\n"
645 "Suppress Router Advertisement\n")
646{
647 struct interface *ifp;
648 struct zebra_if *zif;
Feng Lu49f76092015-05-22 11:40:10 +0200649 struct zebra_vrf *zvrf;
paul718e3742002-12-13 20:15:29 +0000650
651 ifp = vty->index;
652 zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200653 zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000654
655 if (if_is_loopback (ifp))
656 {
657 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
658 return CMD_WARNING;
659 }
660
661 if (zif->rtadv.AdvSendAdvertisements)
662 {
663 zif->rtadv.AdvSendAdvertisements = 0;
664 zif->rtadv.AdvIntervalTimer = 0;
Feng Lu49f76092015-05-22 11:40:10 +0200665 zvrf->rtadv.adv_if_count--;
paul718e3742002-12-13 20:15:29 +0000666
Feng Lu49f76092015-05-22 11:40:10 +0200667 if_leave_all_router (zvrf->rtadv.sock, ifp);
paul718e3742002-12-13 20:15:29 +0000668
Feng Lu49f76092015-05-22 11:40:10 +0200669 if (zvrf->rtadv.adv_if_count == 0)
670 rtadv_event (zvrf, RTADV_STOP, 0);
paul718e3742002-12-13 20:15:29 +0000671 }
672
673 return CMD_SUCCESS;
674}
675
paul718e3742002-12-13 20:15:29 +0000676DEFUN (no_ipv6_nd_suppress_ra,
677 no_ipv6_nd_suppress_ra_cmd,
678 "no ipv6 nd suppress-ra",
679 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000680 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000681 "Neighbor discovery\n"
682 "Suppress Router Advertisement\n")
683{
684 struct interface *ifp;
685 struct zebra_if *zif;
Feng Lu49f76092015-05-22 11:40:10 +0200686 struct zebra_vrf *zvrf;
paul718e3742002-12-13 20:15:29 +0000687
688 ifp = vty->index;
689 zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200690 zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000691
692 if (if_is_loopback (ifp))
693 {
694 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
695 return CMD_WARNING;
696 }
697
698 if (! zif->rtadv.AdvSendAdvertisements)
699 {
700 zif->rtadv.AdvSendAdvertisements = 1;
701 zif->rtadv.AdvIntervalTimer = 0;
Feng Lu49f76092015-05-22 11:40:10 +0200702 zvrf->rtadv.adv_if_count++;
paul718e3742002-12-13 20:15:29 +0000703
Feng Lu49f76092015-05-22 11:40:10 +0200704 if_join_all_router (zvrf->rtadv.sock, ifp);
paul718e3742002-12-13 20:15:29 +0000705
Feng Lu49f76092015-05-22 11:40:10 +0200706 if (zvrf->rtadv.adv_if_count == 1)
707 rtadv_event (zvrf, RTADV_START, zvrf->rtadv.sock);
paul718e3742002-12-13 20:15:29 +0000708 }
709
710 return CMD_SUCCESS;
711}
712
vincent7cee1bb2005-03-25 13:08:53 +0000713DEFUN (ipv6_nd_ra_interval_msec,
714 ipv6_nd_ra_interval_msec_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400715 "ipv6 nd ra-interval msec <70-1800000>",
vincent7cee1bb2005-03-25 13:08:53 +0000716 "Interface IPv6 config commands\n"
717 "Neighbor discovery\n"
718 "Router Advertisement interval\n"
719 "Router Advertisement interval in milliseconds\n")
720{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400721 unsigned interval;
722 struct interface *ifp = (struct interface *) vty->index;
723 struct zebra_if *zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200724 struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
vincent7cee1bb2005-03-25 13:08:53 +0000725
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400726 VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 70, 1800000);
727 if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime * 1000))
728 {
729 vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE);
730 return CMD_WARNING;
731 }
vincent7cee1bb2005-03-25 13:08:53 +0000732
733 if (zif->rtadv.MaxRtrAdvInterval % 1000)
Feng Lu49f76092015-05-22 11:40:10 +0200734 zvrf->rtadv.adv_msec_if_count--;
vincent7cee1bb2005-03-25 13:08:53 +0000735
736 if (interval % 1000)
Feng Lu49f76092015-05-22 11:40:10 +0200737 zvrf->rtadv.adv_msec_if_count++;
vincent7cee1bb2005-03-25 13:08:53 +0000738
739 zif->rtadv.MaxRtrAdvInterval = interval;
740 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
741 zif->rtadv.AdvIntervalTimer = 0;
742
743 return CMD_SUCCESS;
744}
745
paul718e3742002-12-13 20:15:29 +0000746DEFUN (ipv6_nd_ra_interval,
747 ipv6_nd_ra_interval_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400748 "ipv6 nd ra-interval <1-1800>",
hasso3e31cde2004-05-18 11:58:59 +0000749 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000750 "Neighbor discovery\n"
751 "Router Advertisement interval\n"
752 "Router Advertisement interval in seconds\n")
753{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400754 unsigned interval;
755 struct interface *ifp = (struct interface *) vty->index;
756 struct zebra_if *zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200757 struct zebra_vrf *zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000758
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400759 VTY_GET_INTEGER_RANGE ("router advertisement interval", interval, argv[0], 1, 1800);
760 if ((zif->rtadv.AdvDefaultLifetime != -1 && interval > (unsigned)zif->rtadv.AdvDefaultLifetime))
761 {
762 vty_out (vty, "This ra-interval would conflict with configured ra-lifetime!%s", VTY_NEWLINE);
763 return CMD_WARNING;
764 }
paul718e3742002-12-13 20:15:29 +0000765
vincent7cee1bb2005-03-25 13:08:53 +0000766 if (zif->rtadv.MaxRtrAdvInterval % 1000)
Feng Lu49f76092015-05-22 11:40:10 +0200767 zvrf->rtadv.adv_msec_if_count--;
vincent7cee1bb2005-03-25 13:08:53 +0000768
769 /* convert to milliseconds */
770 interval = interval * 1000;
771
paul718e3742002-12-13 20:15:29 +0000772 zif->rtadv.MaxRtrAdvInterval = interval;
773 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
774 zif->rtadv.AdvIntervalTimer = 0;
775
776 return CMD_SUCCESS;
777}
778
779DEFUN (no_ipv6_nd_ra_interval,
780 no_ipv6_nd_ra_interval_cmd,
781 "no ipv6 nd ra-interval",
782 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000783 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000784 "Neighbor discovery\n"
785 "Router Advertisement interval\n")
786{
787 struct interface *ifp;
788 struct zebra_if *zif;
Feng Lu49f76092015-05-22 11:40:10 +0200789 struct zebra_vrf *zvrf;
paul718e3742002-12-13 20:15:29 +0000790
791 ifp = (struct interface *) vty->index;
792 zif = ifp->info;
Feng Lu49f76092015-05-22 11:40:10 +0200793 zvrf = vrf_info_lookup (ifp->vrf_id);
paul718e3742002-12-13 20:15:29 +0000794
vincent7cee1bb2005-03-25 13:08:53 +0000795 if (zif->rtadv.MaxRtrAdvInterval % 1000)
Feng Lu49f76092015-05-22 11:40:10 +0200796 zvrf->rtadv.adv_msec_if_count--;
vincent7cee1bb2005-03-25 13:08:53 +0000797
paul718e3742002-12-13 20:15:29 +0000798 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
799 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
800 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
801
802 return CMD_SUCCESS;
803}
804
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400805ALIAS (no_ipv6_nd_ra_interval,
806 no_ipv6_nd_ra_interval_val_cmd,
807 "no ipv6 nd ra-interval <1-1800>",
808 NO_STR
809 "Interface IPv6 config commands\n"
810 "Neighbor discovery\n"
811 "Router Advertisement interval\n")
812
813ALIAS (no_ipv6_nd_ra_interval,
814 no_ipv6_nd_ra_interval_msec_val_cmd,
815 "no ipv6 nd ra-interval msec <1-1800000>",
816 NO_STR
817 "Interface IPv6 config commands\n"
818 "Neighbor discovery\n"
819 "Router Advertisement interval\n"
820 "Router Advertisement interval in milliseconds\n")
821
paul718e3742002-12-13 20:15:29 +0000822DEFUN (ipv6_nd_ra_lifetime,
823 ipv6_nd_ra_lifetime_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400824 "ipv6 nd ra-lifetime <0-9000>",
hasso3e31cde2004-05-18 11:58:59 +0000825 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000826 "Neighbor discovery\n"
827 "Router lifetime\n"
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400828 "Router lifetime in seconds (0 stands for a non-default gw)\n")
paul718e3742002-12-13 20:15:29 +0000829{
830 int lifetime;
831 struct interface *ifp;
832 struct zebra_if *zif;
833
834 ifp = (struct interface *) vty->index;
835 zif = ifp->info;
836
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400837 VTY_GET_INTEGER_RANGE ("router lifetime", lifetime, argv[0], 0, 9000);
paul718e3742002-12-13 20:15:29 +0000838
Denis Ovsienkod660f692011-12-30 21:55:49 +0400839 /* The value to be placed in the Router Lifetime field
840 * of Router Advertisements sent from the interface,
841 * in seconds. MUST be either zero or between
842 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400843 if ((lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval))
paul718e3742002-12-13 20:15:29 +0000844 {
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400845 vty_out (vty, "This ra-lifetime would conflict with configured ra-interval%s", VTY_NEWLINE);
paul718e3742002-12-13 20:15:29 +0000846 return CMD_WARNING;
847 }
848
849 zif->rtadv.AdvDefaultLifetime = lifetime;
850
851 return CMD_SUCCESS;
852}
853
854DEFUN (no_ipv6_nd_ra_lifetime,
855 no_ipv6_nd_ra_lifetime_cmd,
856 "no ipv6 nd ra-lifetime",
857 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000858 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000859 "Neighbor discovery\n"
860 "Router lifetime\n")
861{
862 struct interface *ifp;
863 struct zebra_if *zif;
864
865 ifp = (struct interface *) vty->index;
866 zif = ifp->info;
867
Denis Ovsienkod660f692011-12-30 21:55:49 +0400868 zif->rtadv.AdvDefaultLifetime = -1;
paul718e3742002-12-13 20:15:29 +0000869
870 return CMD_SUCCESS;
871}
872
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400873ALIAS (no_ipv6_nd_ra_lifetime,
874 no_ipv6_nd_ra_lifetime_val_cmd,
875 "no ipv6 nd ra-lifetime <0-9000>",
876 NO_STR
877 "Interface IPv6 config commands\n"
878 "Neighbor discovery\n"
879 "Router lifetime\n"
880 "Router lifetime in seconds (0 stands for a non-default gw)\n")
881
paul718e3742002-12-13 20:15:29 +0000882DEFUN (ipv6_nd_reachable_time,
883 ipv6_nd_reachable_time_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400884 "ipv6 nd reachable-time <1-3600000>",
hasso3e31cde2004-05-18 11:58:59 +0000885 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000886 "Neighbor discovery\n"
887 "Reachable time\n"
888 "Reachable time in milliseconds\n")
889{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400890 struct interface *ifp = (struct interface *) vty->index;
891 struct zebra_if *zif = ifp->info;
892 VTY_GET_INTEGER_RANGE ("reachable time", zif->rtadv.AdvReachableTime, argv[0], 1, RTADV_MAX_REACHABLE_TIME);
paul718e3742002-12-13 20:15:29 +0000893 return CMD_SUCCESS;
894}
895
896DEFUN (no_ipv6_nd_reachable_time,
897 no_ipv6_nd_reachable_time_cmd,
898 "no ipv6 nd reachable-time",
899 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000900 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000901 "Neighbor discovery\n"
902 "Reachable time\n")
903{
904 struct interface *ifp;
905 struct zebra_if *zif;
906
907 ifp = (struct interface *) vty->index;
908 zif = ifp->info;
909
910 zif->rtadv.AdvReachableTime = 0;
911
912 return CMD_SUCCESS;
913}
914
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400915ALIAS (no_ipv6_nd_reachable_time,
916 no_ipv6_nd_reachable_time_val_cmd,
917 "no ipv6 nd reachable-time <1-3600000>",
918 NO_STR
919 "Interface IPv6 config commands\n"
920 "Neighbor discovery\n"
921 "Reachable time\n"
922 "Reachable time in milliseconds\n")
923
vincent7cee1bb2005-03-25 13:08:53 +0000924DEFUN (ipv6_nd_homeagent_preference,
925 ipv6_nd_homeagent_preference_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400926 "ipv6 nd home-agent-preference <0-65535>",
vincent7cee1bb2005-03-25 13:08:53 +0000927 "Interface IPv6 config commands\n"
928 "Neighbor discovery\n"
929 "Home Agent preference\n"
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400930 "preference value (default is 0, least preferred)\n")
vincent7cee1bb2005-03-25 13:08:53 +0000931{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400932 struct interface *ifp = (struct interface *) vty->index;
933 struct zebra_if *zif = ifp->info;
934 VTY_GET_INTEGER_RANGE ("home agent preference", zif->rtadv.HomeAgentPreference, argv[0], 0, 65535);
vincent7cee1bb2005-03-25 13:08:53 +0000935 return CMD_SUCCESS;
936}
937
938DEFUN (no_ipv6_nd_homeagent_preference,
939 no_ipv6_nd_homeagent_preference_cmd,
940 "no ipv6 nd home-agent-preference",
941 NO_STR
942 "Interface IPv6 config commands\n"
943 "Neighbor discovery\n"
944 "Home Agent preference\n")
945{
946 struct interface *ifp;
947 struct zebra_if *zif;
948
949 ifp = (struct interface *) vty->index;
950 zif = ifp->info;
951
952 zif->rtadv.HomeAgentPreference = 0;
953
954 return CMD_SUCCESS;
955}
956
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400957ALIAS (no_ipv6_nd_homeagent_preference,
958 no_ipv6_nd_homeagent_preference_val_cmd,
959 "no ipv6 nd home-agent-preference <0-65535>",
960 NO_STR
961 "Interface IPv6 config commands\n"
962 "Neighbor discovery\n"
963 "Home Agent preference\n"
964 "preference value (default is 0, least preferred)\n")
965
vincent7cee1bb2005-03-25 13:08:53 +0000966DEFUN (ipv6_nd_homeagent_lifetime,
967 ipv6_nd_homeagent_lifetime_cmd,
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400968 "ipv6 nd home-agent-lifetime <0-65520>",
vincent7cee1bb2005-03-25 13:08:53 +0000969 "Interface IPv6 config commands\n"
970 "Neighbor discovery\n"
971 "Home Agent lifetime\n"
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400972 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
vincent7cee1bb2005-03-25 13:08:53 +0000973{
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400974 struct interface *ifp = (struct interface *) vty->index;
975 struct zebra_if *zif = ifp->info;
976 VTY_GET_INTEGER_RANGE ("home agent lifetime", zif->rtadv.HomeAgentLifetime, argv[0], 0, RTADV_MAX_HALIFETIME);
vincent7cee1bb2005-03-25 13:08:53 +0000977 return CMD_SUCCESS;
978}
979
980DEFUN (no_ipv6_nd_homeagent_lifetime,
981 no_ipv6_nd_homeagent_lifetime_cmd,
982 "no ipv6 nd home-agent-lifetime",
983 NO_STR
984 "Interface IPv6 config commands\n"
985 "Neighbor discovery\n"
986 "Home Agent lifetime\n")
987{
988 struct interface *ifp;
989 struct zebra_if *zif;
990
991 ifp = (struct interface *) vty->index;
992 zif = ifp->info;
993
Denis Ovsienkod660f692011-12-30 21:55:49 +0400994 zif->rtadv.HomeAgentLifetime = -1;
vincent7cee1bb2005-03-25 13:08:53 +0000995
996 return CMD_SUCCESS;
997}
998
Denis Ovsienko4afa50b2012-01-24 12:39:58 +0400999ALIAS (no_ipv6_nd_homeagent_lifetime,
1000 no_ipv6_nd_homeagent_lifetime_val_cmd,
1001 "no ipv6 nd home-agent-lifetime <0-65520>",
1002 NO_STR
1003 "Interface IPv6 config commands\n"
1004 "Neighbor discovery\n"
1005 "Home Agent lifetime\n"
1006 "Home Agent lifetime in seconds (0 to track ra-lifetime)\n")
1007
paul718e3742002-12-13 20:15:29 +00001008DEFUN (ipv6_nd_managed_config_flag,
1009 ipv6_nd_managed_config_flag_cmd,
1010 "ipv6 nd managed-config-flag",
hasso3e31cde2004-05-18 11:58:59 +00001011 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001012 "Neighbor discovery\n"
1013 "Managed address configuration flag\n")
1014{
1015 struct interface *ifp;
1016 struct zebra_if *zif;
1017
1018 ifp = (struct interface *) vty->index;
1019 zif = ifp->info;
1020
1021 zif->rtadv.AdvManagedFlag = 1;
1022
1023 return CMD_SUCCESS;
1024}
1025
1026DEFUN (no_ipv6_nd_managed_config_flag,
1027 no_ipv6_nd_managed_config_flag_cmd,
1028 "no ipv6 nd managed-config-flag",
1029 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001030 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001031 "Neighbor discovery\n"
1032 "Managed address configuration flag\n")
1033{
1034 struct interface *ifp;
1035 struct zebra_if *zif;
1036
1037 ifp = (struct interface *) vty->index;
1038 zif = ifp->info;
1039
1040 zif->rtadv.AdvManagedFlag = 0;
1041
1042 return CMD_SUCCESS;
1043}
1044
vincent7cee1bb2005-03-25 13:08:53 +00001045DEFUN (ipv6_nd_homeagent_config_flag,
1046 ipv6_nd_homeagent_config_flag_cmd,
1047 "ipv6 nd home-agent-config-flag",
1048 "Interface IPv6 config commands\n"
1049 "Neighbor discovery\n"
1050 "Home Agent configuration flag\n")
1051{
1052 struct interface *ifp;
1053 struct zebra_if *zif;
1054
1055 ifp = (struct interface *) vty->index;
1056 zif = ifp->info;
1057
1058 zif->rtadv.AdvHomeAgentFlag = 1;
1059
1060 return CMD_SUCCESS;
1061}
1062
1063DEFUN (no_ipv6_nd_homeagent_config_flag,
1064 no_ipv6_nd_homeagent_config_flag_cmd,
1065 "no ipv6 nd home-agent-config-flag",
1066 NO_STR
1067 "Interface IPv6 config commands\n"
1068 "Neighbor discovery\n"
1069 "Home Agent configuration flag\n")
1070{
1071 struct interface *ifp;
1072 struct zebra_if *zif;
1073
1074 ifp = (struct interface *) vty->index;
1075 zif = ifp->info;
1076
1077 zif->rtadv.AdvHomeAgentFlag = 0;
1078
1079 return CMD_SUCCESS;
1080}
1081
1082DEFUN (ipv6_nd_adv_interval_config_option,
1083 ipv6_nd_adv_interval_config_option_cmd,
1084 "ipv6 nd adv-interval-option",
1085 "Interface IPv6 config commands\n"
1086 "Neighbor discovery\n"
1087 "Advertisement Interval Option\n")
1088{
1089 struct interface *ifp;
1090 struct zebra_if *zif;
1091
1092 ifp = (struct interface *) vty->index;
1093 zif = ifp->info;
1094
1095 zif->rtadv.AdvIntervalOption = 1;
1096
1097 return CMD_SUCCESS;
1098}
1099
1100DEFUN (no_ipv6_nd_adv_interval_config_option,
1101 no_ipv6_nd_adv_interval_config_option_cmd,
1102 "no ipv6 nd adv-interval-option",
1103 NO_STR
1104 "Interface IPv6 config commands\n"
1105 "Neighbor discovery\n"
1106 "Advertisement Interval Option\n")
1107{
1108 struct interface *ifp;
1109 struct zebra_if *zif;
1110
1111 ifp = (struct interface *) vty->index;
1112 zif = ifp->info;
1113
1114 zif->rtadv.AdvIntervalOption = 0;
1115
1116 return CMD_SUCCESS;
1117}
1118
paul718e3742002-12-13 20:15:29 +00001119DEFUN (ipv6_nd_other_config_flag,
1120 ipv6_nd_other_config_flag_cmd,
1121 "ipv6 nd other-config-flag",
hasso3e31cde2004-05-18 11:58:59 +00001122 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001123 "Neighbor discovery\n"
1124 "Other statefull configuration flag\n")
1125{
1126 struct interface *ifp;
1127 struct zebra_if *zif;
1128
1129 ifp = (struct interface *) vty->index;
1130 zif = ifp->info;
1131
1132 zif->rtadv.AdvOtherConfigFlag = 1;
1133
1134 return CMD_SUCCESS;
1135}
1136
1137DEFUN (no_ipv6_nd_other_config_flag,
1138 no_ipv6_nd_other_config_flag_cmd,
1139 "no ipv6 nd other-config-flag",
1140 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001141 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001142 "Neighbor discovery\n"
1143 "Other statefull configuration flag\n")
1144{
1145 struct interface *ifp;
1146 struct zebra_if *zif;
1147
1148 ifp = (struct interface *) vty->index;
1149 zif = ifp->info;
1150
1151 zif->rtadv.AdvOtherConfigFlag = 0;
1152
1153 return CMD_SUCCESS;
1154}
1155
hasso3e31cde2004-05-18 11:58:59 +00001156DEFUN (ipv6_nd_prefix,
1157 ipv6_nd_prefix_cmd,
1158 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
vincent7cee1bb2005-03-25 13:08:53 +00001159 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)",
hasso3e31cde2004-05-18 11:58:59 +00001160 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001161 "Neighbor discovery\n"
1162 "Prefix information\n"
1163 "IPv6 prefix\n"
1164 "Valid lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001165 "Infinite valid lifetime\n"
paul718e3742002-12-13 20:15:29 +00001166 "Preferred lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001167 "Infinite preferred lifetime\n"
1168 "Do not use prefix for onlink determination\n"
vincent7cee1bb2005-03-25 13:08:53 +00001169 "Do not use prefix for autoconfiguration\n"
1170 "Set Router Address flag\n")
paul718e3742002-12-13 20:15:29 +00001171{
1172 int i;
1173 int ret;
hasso3e31cde2004-05-18 11:58:59 +00001174 int cursor = 1;
paul718e3742002-12-13 20:15:29 +00001175 struct interface *ifp;
1176 struct zebra_if *zebra_if;
1177 struct rtadv_prefix rp;
1178
1179 ifp = (struct interface *) vty->index;
1180 zebra_if = ifp->info;
1181
Denis Ovsienkoaca43b62012-01-08 18:27:12 +04001182 ret = str2prefix_ipv6 (argv[0], &rp.prefix);
paul718e3742002-12-13 20:15:29 +00001183 if (!ret)
1184 {
1185 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1186 return CMD_WARNING;
1187 }
Denis Ovsienko6bb12732012-01-08 17:46:34 +04001188 apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
hasso3e31cde2004-05-18 11:58:59 +00001189 rp.AdvOnLinkFlag = 1;
1190 rp.AdvAutonomousFlag = 1;
vincent7cee1bb2005-03-25 13:08:53 +00001191 rp.AdvRouterAddressFlag = 0;
hasso3e31cde2004-05-18 11:58:59 +00001192 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1193 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
paul718e3742002-12-13 20:15:29 +00001194
hasso3e31cde2004-05-18 11:58:59 +00001195 if (argc > 1)
paul718e3742002-12-13 20:15:29 +00001196 {
David Lamparter52f02b42015-04-10 09:14:30 +02001197 if ((isdigit((unsigned char)argv[1][0]))
1198 || strncmp (argv[1], "i", 1) == 0)
paul718e3742002-12-13 20:15:29 +00001199 {
hasso3e31cde2004-05-18 11:58:59 +00001200 if ( strncmp (argv[1], "i", 1) == 0)
1201 rp.AdvValidLifetime = UINT32_MAX;
1202 else
1203 rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1],
1204 (char **)NULL, 10);
1205
1206 if ( strncmp (argv[2], "i", 1) == 0)
1207 rp.AdvPreferredLifetime = UINT32_MAX;
1208 else
1209 rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2],
1210 (char **)NULL, 10);
1211
1212 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
1213 {
1214 vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
1215 return CMD_WARNING;
1216 }
1217 cursor = cursor + 2;
paul718e3742002-12-13 20:15:29 +00001218 }
hasso3e31cde2004-05-18 11:58:59 +00001219 if (argc > cursor)
paul718e3742002-12-13 20:15:29 +00001220 {
hasso3e31cde2004-05-18 11:58:59 +00001221 for (i = cursor; i < argc; i++)
1222 {
1223 if (strncmp (argv[i], "of", 2) == 0)
1224 rp.AdvOnLinkFlag = 0;
1225 if (strncmp (argv[i], "no", 2) == 0)
1226 rp.AdvAutonomousFlag = 0;
vincent7cee1bb2005-03-25 13:08:53 +00001227 if (strncmp (argv[i], "ro", 2) == 0)
1228 rp.AdvRouterAddressFlag = 1;
hasso3e31cde2004-05-18 11:58:59 +00001229 }
paul718e3742002-12-13 20:15:29 +00001230 }
1231 }
1232
1233 rtadv_prefix_set (zebra_if, &rp);
1234
1235 return CMD_SUCCESS;
1236}
1237
hasso3e31cde2004-05-18 11:58:59 +00001238ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001239 ipv6_nd_prefix_val_nortaddr_cmd,
1240 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1241 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
1242 "Interface IPv6 config commands\n"
1243 "Neighbor discovery\n"
1244 "Prefix information\n"
1245 "IPv6 prefix\n"
1246 "Valid lifetime in seconds\n"
1247 "Infinite valid lifetime\n"
1248 "Preferred lifetime in seconds\n"
1249 "Infinite preferred lifetime\n"
1250 "Do not use prefix for onlink determination\n"
1251 "Do not use prefix for autoconfiguration\n")
1252
1253ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001254 ipv6_nd_prefix_val_rev_cmd,
1255 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1256 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)",
1257 "Interface IPv6 config commands\n"
1258 "Neighbor discovery\n"
1259 "Prefix information\n"
1260 "IPv6 prefix\n"
1261 "Valid lifetime in seconds\n"
1262 "Infinite valid lifetime\n"
1263 "Preferred lifetime in seconds\n"
1264 "Infinite preferred lifetime\n"
1265 "Do not use prefix for autoconfiguration\n"
1266 "Do not use prefix for onlink determination\n")
1267
1268ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001269 ipv6_nd_prefix_val_rev_rtaddr_cmd,
1270 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1271 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)",
1272 "Interface IPv6 config commands\n"
1273 "Neighbor discovery\n"
1274 "Prefix information\n"
1275 "IPv6 prefix\n"
1276 "Valid lifetime in seconds\n"
1277 "Infinite valid lifetime\n"
1278 "Preferred lifetime in seconds\n"
1279 "Infinite preferred lifetime\n"
1280 "Do not use prefix for autoconfiguration\n"
1281 "Do not use prefix for onlink determination\n"
1282 "Set Router Address flag\n")
1283
1284ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001285 ipv6_nd_prefix_val_noauto_cmd,
1286 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1287 "(<0-4294967295>|infinite) (no-autoconfig|)",
1288 "Interface IPv6 config commands\n"
1289 "Neighbor discovery\n"
1290 "Prefix information\n"
1291 "IPv6 prefix\n"
1292 "Valid lifetime in seconds\n"
1293 "Infinite valid lifetime\n"
1294 "Preferred lifetime in seconds\n"
1295 "Infinite preferred lifetime\n"
vincent7cee1bb2005-03-25 13:08:53 +00001296 "Do not use prefix for autoconfiguration")
hasso3e31cde2004-05-18 11:58:59 +00001297
1298ALIAS (ipv6_nd_prefix,
1299 ipv6_nd_prefix_val_offlink_cmd,
1300 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1301 "(<0-4294967295>|infinite) (off-link|)",
1302 "Interface IPv6 config commands\n"
1303 "Neighbor discovery\n"
1304 "Prefix information\n"
1305 "IPv6 prefix\n"
1306 "Valid lifetime in seconds\n"
1307 "Infinite valid lifetime\n"
1308 "Preferred lifetime in seconds\n"
1309 "Infinite preferred lifetime\n"
1310 "Do not use prefix for onlink determination\n")
1311
1312ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001313 ipv6_nd_prefix_val_rtaddr_cmd,
1314 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1315 "(<0-4294967295>|infinite) (router-address|)",
1316 "Interface IPv6 config commands\n"
1317 "Neighbor discovery\n"
1318 "Prefix information\n"
1319 "IPv6 prefix\n"
1320 "Valid lifetime in seconds\n"
1321 "Infinite valid lifetime\n"
1322 "Preferred lifetime in seconds\n"
1323 "Infinite preferred lifetime\n"
1324 "Set Router Address flag\n")
1325
1326ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001327 ipv6_nd_prefix_val_cmd,
1328 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1329 "(<0-4294967295>|infinite)",
1330 "Interface IPv6 config commands\n"
1331 "Neighbor discovery\n"
1332 "Prefix information\n"
1333 "IPv6 prefix\n"
1334 "Valid lifetime in seconds\n"
1335 "Infinite valid lifetime\n"
1336 "Preferred lifetime in seconds\n"
1337 "Infinite preferred lifetime\n")
1338
1339ALIAS (ipv6_nd_prefix,
1340 ipv6_nd_prefix_noval_cmd,
1341 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)",
1342 "Interface IPv6 config commands\n"
1343 "Neighbor discovery\n"
1344 "Prefix information\n"
1345 "IPv6 prefix\n"
1346 "Do not use prefix for autoconfiguration\n"
1347 "Do not use prefix for onlink determination\n")
1348
1349ALIAS (ipv6_nd_prefix,
1350 ipv6_nd_prefix_noval_rev_cmd,
1351 "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)",
1352 "Interface IPv6 config commands\n"
1353 "Neighbor discovery\n"
1354 "Prefix information\n"
1355 "IPv6 prefix\n"
1356 "Do not use prefix for onlink determination\n"
1357 "Do not use prefix for autoconfiguration\n")
1358
1359ALIAS (ipv6_nd_prefix,
1360 ipv6_nd_prefix_noval_noauto_cmd,
1361 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)",
1362 "Interface IPv6 config commands\n"
1363 "Neighbor discovery\n"
1364 "Prefix information\n"
1365 "IPv6 prefix\n"
1366 "Do not use prefix for autoconfiguration\n")
1367
1368ALIAS (ipv6_nd_prefix,
1369 ipv6_nd_prefix_noval_offlink_cmd,
1370 "ipv6 nd prefix X:X::X:X/M (off-link|)",
1371 "Interface IPv6 config commands\n"
1372 "Neighbor discovery\n"
1373 "Prefix information\n"
1374 "IPv6 prefix\n"
1375 "Do not use prefix for onlink determination\n")
1376
1377ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001378 ipv6_nd_prefix_noval_rtaddr_cmd,
1379 "ipv6 nd prefix X:X::X:X/M (router-address|)",
1380 "Interface IPv6 config commands\n"
1381 "Neighbor discovery\n"
1382 "Prefix information\n"
1383 "IPv6 prefix\n"
1384 "Set Router Address flag\n")
1385
1386ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001387 ipv6_nd_prefix_prefix_cmd,
1388 "ipv6 nd prefix X:X::X:X/M",
1389 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001390 "Neighbor discovery\n"
1391 "Prefix information\n"
1392 "IPv6 prefix\n")
1393
hasso3e31cde2004-05-18 11:58:59 +00001394DEFUN (no_ipv6_nd_prefix,
1395 no_ipv6_nd_prefix_cmd,
1396 "no ipv6 nd prefix IPV6PREFIX",
paul718e3742002-12-13 20:15:29 +00001397 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001398 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001399 "Neighbor discovery\n"
1400 "Prefix information\n"
1401 "IPv6 prefix\n")
1402{
1403 int ret;
1404 struct interface *ifp;
1405 struct zebra_if *zebra_if;
1406 struct rtadv_prefix rp;
1407
1408 ifp = (struct interface *) vty->index;
1409 zebra_if = ifp->info;
1410
Denis Ovsienkoaca43b62012-01-08 18:27:12 +04001411 ret = str2prefix_ipv6 (argv[0], &rp.prefix);
paul718e3742002-12-13 20:15:29 +00001412 if (!ret)
1413 {
1414 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1415 return CMD_WARNING;
1416 }
Denis Ovsienko6bb12732012-01-08 17:46:34 +04001417 apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
paul718e3742002-12-13 20:15:29 +00001418
1419 ret = rtadv_prefix_reset (zebra_if, &rp);
1420 if (!ret)
1421 {
1422 vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
1423 return CMD_WARNING;
1424 }
1425
1426 return CMD_SUCCESS;
1427}
Chris Caputob60668d2009-05-03 04:40:57 +00001428
1429DEFUN (ipv6_nd_router_preference,
1430 ipv6_nd_router_preference_cmd,
1431 "ipv6 nd router-preference (high|medium|low)",
1432 "Interface IPv6 config commands\n"
1433 "Neighbor discovery\n"
1434 "Default router preference\n"
1435 "High default router preference\n"
1436 "Low default router preference\n"
1437 "Medium default router preference (default)\n")
1438{
1439 struct interface *ifp;
1440 struct zebra_if *zif;
1441 int i = 0;
1442
1443 ifp = (struct interface *) vty->index;
1444 zif = ifp->info;
1445
1446 while (0 != rtadv_pref_strs[i])
1447 {
1448 if (strncmp (argv[0], rtadv_pref_strs[i], 1) == 0)
1449 {
1450 zif->rtadv.DefaultPreference = i;
1451 return CMD_SUCCESS;
1452 }
1453 i++;
1454 }
1455
1456 return CMD_ERR_NO_MATCH;
1457}
1458
1459DEFUN (no_ipv6_nd_router_preference,
1460 no_ipv6_nd_router_preference_cmd,
1461 "no ipv6 nd router-preference",
1462 NO_STR
1463 "Interface IPv6 config commands\n"
1464 "Neighbor discovery\n"
1465 "Default router preference\n")
1466{
1467 struct interface *ifp;
1468 struct zebra_if *zif;
1469
1470 ifp = (struct interface *) vty->index;
1471 zif = ifp->info;
1472
1473 zif->rtadv.DefaultPreference = RTADV_PREF_MEDIUM; /* Default per RFC4191. */
1474
1475 return CMD_SUCCESS;
1476}
1477
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001478ALIAS (no_ipv6_nd_router_preference,
1479 no_ipv6_nd_router_preference_val_cmd,
Christian Franke2b005152013-09-30 12:27:49 +00001480 "no ipv6 nd router-preference (high|medium|low)",
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001481 NO_STR
1482 "Interface IPv6 config commands\n"
1483 "Neighbor discovery\n"
1484 "Default router preference\n"
1485 "High default router preference\n"
1486 "Low default router preference\n"
1487 "Medium default router preference (default)\n")
1488
Denis Ovsienko6ae93c02011-12-27 10:45:36 +04001489DEFUN (ipv6_nd_mtu,
1490 ipv6_nd_mtu_cmd,
1491 "ipv6 nd mtu <1-65535>",
1492 "Interface IPv6 config commands\n"
1493 "Neighbor discovery\n"
1494 "Advertised MTU\n"
1495 "MTU in bytes\n")
1496{
1497 struct interface *ifp = (struct interface *) vty->index;
1498 struct zebra_if *zif = ifp->info;
1499 VTY_GET_INTEGER_RANGE ("MTU", zif->rtadv.AdvLinkMTU, argv[0], 1, 65535);
1500 return CMD_SUCCESS;
1501}
1502
1503DEFUN (no_ipv6_nd_mtu,
1504 no_ipv6_nd_mtu_cmd,
1505 "no ipv6 nd mtu",
1506 NO_STR
1507 "Interface IPv6 config commands\n"
1508 "Neighbor discovery\n"
1509 "Advertised MTU\n")
1510{
1511 struct interface *ifp = (struct interface *) vty->index;
1512 struct zebra_if *zif = ifp->info;
1513 zif->rtadv.AdvLinkMTU = 0;
1514 return CMD_SUCCESS;
1515}
1516
1517ALIAS (no_ipv6_nd_mtu,
1518 no_ipv6_nd_mtu_val_cmd,
1519 "no ipv6 nd mtu <1-65535>",
1520 NO_STR
1521 "Interface IPv6 config commands\n"
1522 "Neighbor discovery\n"
1523 "Advertised MTU\n"
1524 "MTU in bytes\n")
1525
paul718e3742002-12-13 20:15:29 +00001526/* Write configuration about router advertisement. */
1527void
1528rtadv_config_write (struct vty *vty, struct interface *ifp)
1529{
1530 struct zebra_if *zif;
hasso52dc7ee2004-09-23 19:18:23 +00001531 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001532 struct rtadv_prefix *rprefix;
Timo Teräsbe6335d2015-05-23 11:08:41 +03001533 char buf[PREFIX_STRLEN];
vincent7cee1bb2005-03-25 13:08:53 +00001534 int interval;
paul718e3742002-12-13 20:15:29 +00001535
paul718e3742002-12-13 20:15:29 +00001536 zif = ifp->info;
1537
1538 if (! if_is_loopback (ifp))
1539 {
1540 if (zif->rtadv.AdvSendAdvertisements)
1541 vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
1542 else
1543 vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
1544 }
1545
vincent7cee1bb2005-03-25 13:08:53 +00001546
1547 interval = zif->rtadv.MaxRtrAdvInterval;
1548 if (interval % 1000)
1549 vty_out (vty, " ipv6 nd ra-interval msec %d%s", interval,
1550 VTY_NEWLINE);
1551 else
1552 if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
1553 vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000,
paul718e3742002-12-13 20:15:29 +00001554 VTY_NEWLINE);
1555
Denis Ovsienko6134b872011-12-27 18:49:15 +04001556 if (zif->rtadv.AdvIntervalOption)
1557 vty_out (vty, " ipv6 nd adv-interval-option%s", VTY_NEWLINE);
1558
Denis Ovsienkod660f692011-12-30 21:55:49 +04001559 if (zif->rtadv.AdvDefaultLifetime != -1)
paul718e3742002-12-13 20:15:29 +00001560 vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
1561 VTY_NEWLINE);
1562
Denis Ovsienko6134b872011-12-27 18:49:15 +04001563 if (zif->rtadv.HomeAgentPreference)
1564 vty_out (vty, " ipv6 nd home-agent-preference %u%s",
1565 zif->rtadv.HomeAgentPreference, VTY_NEWLINE);
1566
Denis Ovsienkod660f692011-12-30 21:55:49 +04001567 if (zif->rtadv.HomeAgentLifetime != -1)
Denis Ovsienko6134b872011-12-27 18:49:15 +04001568 vty_out (vty, " ipv6 nd home-agent-lifetime %u%s",
1569 zif->rtadv.HomeAgentLifetime, VTY_NEWLINE);
1570
1571 if (zif->rtadv.AdvHomeAgentFlag)
1572 vty_out (vty, " ipv6 nd home-agent-config-flag%s", VTY_NEWLINE);
1573
paul718e3742002-12-13 20:15:29 +00001574 if (zif->rtadv.AdvReachableTime)
1575 vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
1576 VTY_NEWLINE);
1577
1578 if (zif->rtadv.AdvManagedFlag)
1579 vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
1580
1581 if (zif->rtadv.AdvOtherConfigFlag)
1582 vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
1583
Chris Caputob60668d2009-05-03 04:40:57 +00001584 if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
1585 vty_out (vty, " ipv6 nd router-preference %s%s",
1586 rtadv_pref_strs[zif->rtadv.DefaultPreference],
1587 VTY_NEWLINE);
1588
Denis Ovsienko6ae93c02011-12-27 10:45:36 +04001589 if (zif->rtadv.AdvLinkMTU)
1590 vty_out (vty, " ipv6 nd mtu %d%s", zif->rtadv.AdvLinkMTU, VTY_NEWLINE);
1591
paul1eb8ef22005-04-07 07:30:20 +00001592 for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
paul718e3742002-12-13 20:15:29 +00001593 {
Timo Teräsbe6335d2015-05-23 11:08:41 +03001594 vty_out (vty, " ipv6 nd prefix %s",
1595 prefix2str (&rprefix->prefix, buf, sizeof(buf)));
hasso3e31cde2004-05-18 11:58:59 +00001596 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) ||
1597 (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME))
1598 {
1599 if (rprefix->AdvValidLifetime == UINT32_MAX)
1600 vty_out (vty, " infinite");
1601 else
1602 vty_out (vty, " %u", rprefix->AdvValidLifetime);
1603 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1604 vty_out (vty, " infinite");
1605 else
1606 vty_out (vty, " %u", rprefix->AdvPreferredLifetime);
1607 }
1608 if (!rprefix->AdvOnLinkFlag)
1609 vty_out (vty, " off-link");
1610 if (!rprefix->AdvAutonomousFlag)
1611 vty_out (vty, " no-autoconfig");
vincent7cee1bb2005-03-25 13:08:53 +00001612 if (rprefix->AdvRouterAddressFlag)
1613 vty_out (vty, " router-address");
paul718e3742002-12-13 20:15:29 +00001614 vty_out (vty, "%s", VTY_NEWLINE);
1615 }
1616}
1617
paul718e3742002-12-13 20:15:29 +00001618
paula1ac18c2005-06-28 17:17:12 +00001619static void
Feng Lu49f76092015-05-22 11:40:10 +02001620rtadv_event (struct zebra_vrf *zvrf, enum rtadv_event event, int val)
paul718e3742002-12-13 20:15:29 +00001621{
Feng Lu49f76092015-05-22 11:40:10 +02001622 struct rtadv *rtadv = &zvrf->rtadv;
1623
paul718e3742002-12-13 20:15:29 +00001624 switch (event)
1625 {
1626 case RTADV_START:
1627 if (! rtadv->ra_read)
Feng Lu49f76092015-05-22 11:40:10 +02001628 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val);
paul718e3742002-12-13 20:15:29 +00001629 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001630 rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
Feng Lu49f76092015-05-22 11:40:10 +02001631 zvrf, 0);
paul718e3742002-12-13 20:15:29 +00001632 break;
1633 case RTADV_STOP:
1634 if (rtadv->ra_timer)
1635 {
1636 thread_cancel (rtadv->ra_timer);
1637 rtadv->ra_timer = NULL;
1638 }
1639 if (rtadv->ra_read)
1640 {
1641 thread_cancel (rtadv->ra_read);
1642 rtadv->ra_read = NULL;
1643 }
1644 break;
1645 case RTADV_TIMER:
1646 if (! rtadv->ra_timer)
Feng Lu49f76092015-05-22 11:40:10 +02001647 rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, zvrf,
hasso3e31cde2004-05-18 11:58:59 +00001648 val);
paul718e3742002-12-13 20:15:29 +00001649 break;
vincent7cee1bb2005-03-25 13:08:53 +00001650 case RTADV_TIMER_MSEC:
1651 if (! rtadv->ra_timer)
1652 rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer,
Feng Lu49f76092015-05-22 11:40:10 +02001653 zvrf, val);
vincent7cee1bb2005-03-25 13:08:53 +00001654 break;
paul718e3742002-12-13 20:15:29 +00001655 case RTADV_READ:
1656 if (! rtadv->ra_read)
Feng Lu49f76092015-05-22 11:40:10 +02001657 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, zvrf, val);
paul718e3742002-12-13 20:15:29 +00001658 break;
1659 default:
1660 break;
1661 }
1662 return;
1663}
1664
1665void
Feng Lu49f76092015-05-22 11:40:10 +02001666rtadv_init (struct zebra_vrf *zvrf)
paul718e3742002-12-13 20:15:29 +00001667{
Feng Lu49f76092015-05-22 11:40:10 +02001668 zvrf->rtadv.sock = rtadv_make_socket (zvrf->vrf_id);
1669}
paul718e3742002-12-13 20:15:29 +00001670
Feng Lu49f76092015-05-22 11:40:10 +02001671void
1672rtadv_terminate (struct zebra_vrf *zvrf)
1673{
1674 rtadv_event (zvrf, RTADV_STOP, 0);
paul718e3742002-12-13 20:15:29 +00001675
Feng Lu49f76092015-05-22 11:40:10 +02001676 if (zvrf->rtadv.sock >= 0)
1677 {
1678 close (zvrf->rtadv.sock);
1679 zvrf->rtadv.sock = -1;
1680 }
paul718e3742002-12-13 20:15:29 +00001681
Feng Lu49f76092015-05-22 11:40:10 +02001682 zvrf->rtadv.adv_if_count = 0;
1683 zvrf->rtadv.adv_msec_if_count = 0;
1684}
1685
1686void
1687rtadv_cmd_init (void)
1688{
paul718e3742002-12-13 20:15:29 +00001689 install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1690 install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
paul718e3742002-12-13 20:15:29 +00001691 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001692 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
paul718e3742002-12-13 20:15:29 +00001693 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001694 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_val_cmd);
1695 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_msec_val_cmd);
paul718e3742002-12-13 20:15:29 +00001696 install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1697 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001698 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_val_cmd);
paul718e3742002-12-13 20:15:29 +00001699 install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1700 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001701 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_val_cmd);
paul718e3742002-12-13 20:15:29 +00001702 install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1703 install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1704 install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1705 install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001706 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
1707 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
1708 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
1709 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001710 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_val_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001711 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
1712 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001713 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_val_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001714 install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd);
1715 install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001716 install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001717 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd);
1718 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001719 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd);
1720 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd);
1721 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001722 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001723 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd);
1724 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd);
1725 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd);
1726 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd);
1727 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001728 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001729 install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
1730 install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
Chris Caputob60668d2009-05-03 04:40:57 +00001731 install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
1732 install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
Denis Ovsienko4afa50b2012-01-24 12:39:58 +04001733 install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_val_cmd);
Denis Ovsienko6ae93c02011-12-27 10:45:36 +04001734 install_element (INTERFACE_NODE, &ipv6_nd_mtu_cmd);
1735 install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
1736 install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd);
paul718e3742002-12-13 20:15:29 +00001737}
1738
paula1ac18c2005-06-28 17:17:12 +00001739static int
paul718e3742002-12-13 20:15:29 +00001740if_join_all_router (int sock, struct interface *ifp)
1741{
1742 int ret;
1743
1744 struct ipv6_mreq mreq;
1745
1746 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1747 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1748 mreq.ipv6mr_interface = ifp->ifindex;
1749
1750 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1751 (char *) &mreq, sizeof mreq);
1752 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001753 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001754
1755 zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1756
1757 return 0;
1758}
1759
paula1ac18c2005-06-28 17:17:12 +00001760static int
paul718e3742002-12-13 20:15:29 +00001761if_leave_all_router (int sock, struct interface *ifp)
1762{
1763 int ret;
1764
1765 struct ipv6_mreq mreq;
1766
1767 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1768 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1769 mreq.ipv6mr_interface = ifp->ifindex;
1770
1771 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1772 (char *) &mreq, sizeof mreq);
1773 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001774 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001775
1776 zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1777
1778 return 0;
1779}
1780
1781#else
1782void
Feng Lu49f76092015-05-22 11:40:10 +02001783rtadv_init (struct zebra_vrf *zvrf)
1784{
1785 /* Empty.*/;
1786}
1787void
1788rtadv_terminate (struct zebra_vrf *zvrf)
1789{
1790 /* Empty.*/;
1791}
1792void
1793rtadv_cmd_init (void)
paul718e3742002-12-13 20:15:29 +00001794{
1795 /* Empty.*/;
1796}
Donald Sharp64257732015-11-20 08:33:30 -05001797#endif /* HAVE_RTADV && HAVE_IPV6 */