blob: c6c3b0309efe48757d155b531e6e09361c1885b1 [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"
paul718e3742002-12-13 20:15:29 +000034
35#include "zebra/interface.h"
36#include "zebra/rtadv.h"
37#include "zebra/debug.h"
paul537d8ea2003-08-27 06:45:32 +000038#include "zebra/rib.h"
gdt4b5e1352003-12-03 17:54:34 +000039#include "zebra/zserv.h"
paul718e3742002-12-13 20:15:29 +000040
pauledd7c242003-06-04 13:59:38 +000041extern struct zebra_privs_t zserv_privs;
42
paul718e3742002-12-13 20:15:29 +000043#if defined (HAVE_IPV6) && defined (RTADV)
44
hassofa2b17e2004-03-04 17:45:00 +000045#ifdef OPEN_BSD
46#include <netinet/icmp6.h>
47#endif
48
paul718e3742002-12-13 20:15:29 +000049/* If RFC2133 definition is used. */
50#ifndef IPV6_JOIN_GROUP
51#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
52#endif
53#ifndef IPV6_LEAVE_GROUP
54#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
55#endif
56
57#define ALLNODE "ff02::1"
58#define ALLROUTER "ff02::2"
59
paulb21b19c2003-06-15 01:28:29 +000060extern struct zebra_t zebrad;
61
vincent7cee1bb2005-03-25 13:08:53 +000062enum rtadv_event {RTADV_START, RTADV_STOP, RTADV_TIMER,
63 RTADV_TIMER_MSEC, RTADV_READ};
paul718e3742002-12-13 20:15:29 +000064
paula1ac18c2005-06-28 17:17:12 +000065static void rtadv_event (enum rtadv_event, int);
paul718e3742002-12-13 20:15:29 +000066
paula1ac18c2005-06-28 17:17:12 +000067static int if_join_all_router (int, struct interface *);
68static int if_leave_all_router (int, struct interface *);
paul718e3742002-12-13 20:15:29 +000069
70/* Structure which hold status of router advertisement. */
71struct rtadv
72{
73 int sock;
74
75 int adv_if_count;
vincent7cee1bb2005-03-25 13:08:53 +000076 int adv_msec_if_count;
paul718e3742002-12-13 20:15:29 +000077
78 struct thread *ra_read;
79 struct thread *ra_timer;
80};
81
82struct rtadv *rtadv = NULL;
83
paula1ac18c2005-06-28 17:17:12 +000084static struct rtadv *
85rtadv_new (void)
paul718e3742002-12-13 20:15:29 +000086{
Stephen Hemminger393deb92008-08-18 14:13:29 -070087 return XCALLOC (MTYPE_TMP, sizeof (struct rtadv));
paul718e3742002-12-13 20:15:29 +000088}
89
paula1ac18c2005-06-28 17:17:12 +000090static int
paul718e3742002-12-13 20:15:29 +000091rtadv_recv_packet (int sock, u_char *buf, int buflen,
92 struct sockaddr_in6 *from, unsigned int *ifindex,
93 int *hoplimit)
94{
95 int ret;
96 struct msghdr msg;
97 struct iovec iov;
98 struct cmsghdr *cmsgptr;
99 struct in6_addr dst;
100
101 char adata[1024];
102
103 /* Fill in message and iovec. */
104 msg.msg_name = (void *) from;
105 msg.msg_namelen = sizeof (struct sockaddr_in6);
106 msg.msg_iov = &iov;
107 msg.msg_iovlen = 1;
108 msg.msg_control = (void *) adata;
109 msg.msg_controllen = sizeof adata;
110 iov.iov_base = buf;
111 iov.iov_len = buflen;
112
113 /* If recvmsg fail return minus value. */
114 ret = recvmsg (sock, &msg, 0);
115 if (ret < 0)
116 return ret;
117
ajsb99760a2005-01-04 16:24:43 +0000118 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
paul718e3742002-12-13 20:15:29 +0000119 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
120 {
121 /* I want interface index which this packet comes from. */
122 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
123 cmsgptr->cmsg_type == IPV6_PKTINFO)
124 {
125 struct in6_pktinfo *ptr;
126
127 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
128 *ifindex = ptr->ipi6_ifindex;
129 memcpy(&dst, &ptr->ipi6_addr, sizeof(ptr->ipi6_addr));
130 }
131
132 /* Incoming packet's hop limit. */
133 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
134 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
Stephen Hemmingerb0b709a2009-12-08 13:26:14 +0300135 {
136 int *hoptr = (int *) CMSG_DATA (cmsgptr);
137 *hoplimit = *hoptr;
138 }
paul718e3742002-12-13 20:15:29 +0000139 }
140 return ret;
141}
142
143#define RTADV_MSG_SIZE 4096
144
145/* Send router advertisement packet. */
paula1ac18c2005-06-28 17:17:12 +0000146static void
paul718e3742002-12-13 20:15:29 +0000147rtadv_send_packet (int sock, struct interface *ifp)
148{
149 struct msghdr msg;
150 struct iovec iov;
151 struct cmsghdr *cmsgptr;
152 struct in6_pktinfo *pkt;
153 struct sockaddr_in6 addr;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000154#ifdef HAVE_STRUCT_SOCKADDR_DL
paul718e3742002-12-13 20:15:29 +0000155 struct sockaddr_dl *sdl;
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000156#endif /* HAVE_STRUCT_SOCKADDR_DL */
gdt57492d52004-08-11 18:06:38 +0000157 static void *adata = NULL;
paul718e3742002-12-13 20:15:29 +0000158 unsigned char buf[RTADV_MSG_SIZE];
159 struct nd_router_advert *rtadv;
160 int ret;
161 int len = 0;
162 struct zebra_if *zif;
paul1eb8ef22005-04-07 07:30:20 +0000163 struct rtadv_prefix *rprefix;
paul718e3742002-12-13 20:15:29 +0000164 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 +0000165 struct listnode *node;
Denis Ovsienkod660f692011-12-30 21:55:49 +0400166 u_int16_t pkt_RouterLifetime;
paul718e3742002-12-13 20:15:29 +0000167
gdt57492d52004-08-11 18:06:38 +0000168 /*
169 * Allocate control message bufffer. This is dynamic because
170 * CMSG_SPACE is not guaranteed not to call a function. Note that
171 * the size will be different on different architectures due to
172 * differing alignment rules.
173 */
174 if (adata == NULL)
175 {
176 /* XXX Free on shutdown. */
177 adata = malloc(CMSG_SPACE(sizeof(struct in6_pktinfo)));
178
179 if (adata == NULL)
180 zlog_err("rtadv_send_packet: can't malloc control data\n");
181 }
182
paul718e3742002-12-13 20:15:29 +0000183 /* Logging of packet. */
184 if (IS_ZEBRA_DEBUG_PACKET)
ajsb6178002004-12-07 21:12:56 +0000185 zlog_debug ("Router advertisement send to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +0000186
187 /* Fill in sockaddr_in6. */
188 memset (&addr, 0, sizeof (struct sockaddr_in6));
189 addr.sin6_family = AF_INET6;
190#ifdef SIN6_LEN
191 addr.sin6_len = sizeof (struct sockaddr_in6);
192#endif /* SIN6_LEN */
193 addr.sin6_port = htons (IPPROTO_ICMPV6);
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400194 IPV6_ADDR_COPY (&addr.sin6_addr, all_nodes_addr);
paul718e3742002-12-13 20:15:29 +0000195
196 /* Fetch interface information. */
197 zif = ifp->info;
198
199 /* Make router advertisement message. */
200 rtadv = (struct nd_router_advert *) buf;
201
202 rtadv->nd_ra_type = ND_ROUTER_ADVERT;
203 rtadv->nd_ra_code = 0;
204 rtadv->nd_ra_cksum = 0;
205
206 rtadv->nd_ra_curhoplimit = 64;
Chris Caputob60668d2009-05-03 04:40:57 +0000207
208 /* RFC4191: Default Router Preference is 0 if Router Lifetime is 0. */
209 rtadv->nd_ra_flags_reserved =
210 zif->rtadv.AdvDefaultLifetime == 0 ? 0 : zif->rtadv.DefaultPreference;
211 rtadv->nd_ra_flags_reserved <<= 3;
212
paul718e3742002-12-13 20:15:29 +0000213 if (zif->rtadv.AdvManagedFlag)
214 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_MANAGED;
215 if (zif->rtadv.AdvOtherConfigFlag)
216 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_OTHER;
vincent7cee1bb2005-03-25 13:08:53 +0000217 if (zif->rtadv.AdvHomeAgentFlag)
218 rtadv->nd_ra_flags_reserved |= ND_RA_FLAG_HOME_AGENT;
Denis Ovsienkod660f692011-12-30 21:55:49 +0400219 /* Note that according to Neighbor Discovery (RFC 4861 [18]),
220 * AdvDefaultLifetime is by default based on the value of
221 * MaxRtrAdvInterval. AdvDefaultLifetime is used in the Router Lifetime
222 * field of Router Advertisements. Given that this field is expressed
223 * in seconds, a small MaxRtrAdvInterval value can result in a zero
224 * value for this field. To prevent this, routers SHOULD keep
225 * AdvDefaultLifetime in at least one second, even if the use of
226 * MaxRtrAdvInterval would result in a smaller value. -- RFC6275, 7.5 */
227 pkt_RouterLifetime = zif->rtadv.AdvDefaultLifetime != -1 ?
228 zif->rtadv.AdvDefaultLifetime :
229 MAX (1, 0.003 * zif->rtadv.MaxRtrAdvInterval);
230 rtadv->nd_ra_router_lifetime = htons (pkt_RouterLifetime);
paul718e3742002-12-13 20:15:29 +0000231 rtadv->nd_ra_reachable = htonl (zif->rtadv.AdvReachableTime);
232 rtadv->nd_ra_retransmit = htonl (0);
233
234 len = sizeof (struct nd_router_advert);
235
Denis Ovsienkod660f692011-12-30 21:55:49 +0400236 /* If both the Home Agent Preference and Home Agent Lifetime are set to
237 * their default values specified above, this option SHOULD NOT be
238 * included in the Router Advertisement messages sent by this home
239 * agent. -- RFC6275, 7.4 */
240 if
241 (
242 zif->rtadv.AdvHomeAgentFlag &&
243 (zif->rtadv.HomeAgentPreference || zif->rtadv.HomeAgentLifetime != -1)
244 )
vincent7cee1bb2005-03-25 13:08:53 +0000245 {
246 struct nd_opt_homeagent_info *ndopt_hai =
247 (struct nd_opt_homeagent_info *)(buf + len);
248 ndopt_hai->nd_opt_hai_type = ND_OPT_HA_INFORMATION;
249 ndopt_hai->nd_opt_hai_len = 1;
250 ndopt_hai->nd_opt_hai_reserved = 0;
251 ndopt_hai->nd_opt_hai_preference = htons(zif->rtadv.HomeAgentPreference);
Denis Ovsienkod660f692011-12-30 21:55:49 +0400252 /* 16-bit unsigned integer. The lifetime associated with the home
253 * agent in units of seconds. The default value is the same as the
254 * Router Lifetime, as specified in the main body of the Router
255 * Advertisement. The maximum value corresponds to 18.2 hours. A
256 * value of 0 MUST NOT be used. -- RFC6275, 7.5 */
257 ndopt_hai->nd_opt_hai_lifetime = htons
258 (
259 zif->rtadv.HomeAgentLifetime != -1 ?
260 zif->rtadv.HomeAgentLifetime :
261 MAX (1, pkt_RouterLifetime) /* 0 is OK for RL, but not for HAL*/
262 );
vincent7cee1bb2005-03-25 13:08:53 +0000263 len += sizeof(struct nd_opt_homeagent_info);
264 }
265
266 if (zif->rtadv.AdvIntervalOption)
267 {
268 struct nd_opt_adv_interval *ndopt_adv =
269 (struct nd_opt_adv_interval *)(buf + len);
270 ndopt_adv->nd_opt_ai_type = ND_OPT_ADV_INTERVAL;
271 ndopt_adv->nd_opt_ai_len = 1;
272 ndopt_adv->nd_opt_ai_reserved = 0;
273 ndopt_adv->nd_opt_ai_interval = htonl(zif->rtadv.MaxRtrAdvInterval);
274 len += sizeof(struct nd_opt_adv_interval);
275 }
276
paul718e3742002-12-13 20:15:29 +0000277 /* Fill in prefix. */
paul1eb8ef22005-04-07 07:30:20 +0000278 for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
paul718e3742002-12-13 20:15:29 +0000279 {
280 struct nd_opt_prefix_info *pinfo;
paul718e3742002-12-13 20:15:29 +0000281
282 pinfo = (struct nd_opt_prefix_info *) (buf + len);
283
284 pinfo->nd_opt_pi_type = ND_OPT_PREFIX_INFORMATION;
285 pinfo->nd_opt_pi_len = 4;
286 pinfo->nd_opt_pi_prefix_len = rprefix->prefix.prefixlen;
287
288 pinfo->nd_opt_pi_flags_reserved = 0;
289 if (rprefix->AdvOnLinkFlag)
290 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_ONLINK;
291 if (rprefix->AdvAutonomousFlag)
292 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_AUTO;
vincent7cee1bb2005-03-25 13:08:53 +0000293 if (rprefix->AdvRouterAddressFlag)
294 pinfo->nd_opt_pi_flags_reserved |= ND_OPT_PI_FLAG_RADDR;
paul718e3742002-12-13 20:15:29 +0000295
296 pinfo->nd_opt_pi_valid_time = htonl (rprefix->AdvValidLifetime);
297 pinfo->nd_opt_pi_preferred_time = htonl (rprefix->AdvPreferredLifetime);
298 pinfo->nd_opt_pi_reserved2 = 0;
299
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400300 IPV6_ADDR_COPY (&pinfo->nd_opt_pi_prefix, &rprefix->prefix.prefix);
paul718e3742002-12-13 20:15:29 +0000301
302#ifdef DEBUG
303 {
304 u_char buf[INET6_ADDRSTRLEN];
305
ajsb6178002004-12-07 21:12:56 +0000306 zlog_debug ("DEBUG %s", inet_ntop (AF_INET6, &pinfo->nd_opt_pi_prefix,
hasso3e31cde2004-05-18 11:58:59 +0000307 buf, INET6_ADDRSTRLEN));
paul718e3742002-12-13 20:15:29 +0000308
309 }
310#endif /* DEBUG */
311
312 len += sizeof (struct nd_opt_prefix_info);
313 }
314
315 /* Hardware address. */
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000316#ifdef HAVE_STRUCT_SOCKADDR_DL
paul718e3742002-12-13 20:15:29 +0000317 sdl = &ifp->sdl;
318 if (sdl != NULL && sdl->sdl_alen != 0)
319 {
320 buf[len++] = ND_OPT_SOURCE_LINKADDR;
David Ward50adf782009-08-31 10:42:06 -0400321
322 /* Option length should be rounded up to next octet if
323 the link address does not end on an octet boundary. */
324 buf[len++] = (sdl->sdl_alen + 9) >> 3;
paul718e3742002-12-13 20:15:29 +0000325
326 memcpy (buf + len, LLADDR (sdl), sdl->sdl_alen);
327 len += sdl->sdl_alen;
David Ward50adf782009-08-31 10:42:06 -0400328
329 /* Pad option to end on an octet boundary. */
330 memset (buf + len, 0, -(sdl->sdl_alen + 2) & 0x7);
331 len += -(sdl->sdl_alen + 2) & 0x7;
paul718e3742002-12-13 20:15:29 +0000332 }
333#else
334 if (ifp->hw_addr_len != 0)
335 {
336 buf[len++] = ND_OPT_SOURCE_LINKADDR;
David Ward50adf782009-08-31 10:42:06 -0400337
338 /* Option length should be rounded up to next octet if
339 the link address does not end on an octet boundary. */
340 buf[len++] = (ifp->hw_addr_len + 9) >> 3;
paul718e3742002-12-13 20:15:29 +0000341
342 memcpy (buf + len, ifp->hw_addr, ifp->hw_addr_len);
343 len += ifp->hw_addr_len;
David Ward50adf782009-08-31 10:42:06 -0400344
345 /* Pad option to end on an octet boundary. */
346 memset (buf + len, 0, -(ifp->hw_addr_len + 2) & 0x7);
347 len += -(ifp->hw_addr_len + 2) & 0x7;
paul718e3742002-12-13 20:15:29 +0000348 }
Paul Jakma6f0e3f62007-05-10 02:38:51 +0000349#endif /* HAVE_STRUCT_SOCKADDR_DL */
paul718e3742002-12-13 20:15:29 +0000350
Denis Ovsienko6ae93c02011-12-27 10:45:36 +0400351 /* MTU */
352 if (zif->rtadv.AdvLinkMTU)
353 {
354 struct nd_opt_mtu * opt = (struct nd_opt_mtu *) (buf + len);
355 opt->nd_opt_mtu_type = ND_OPT_MTU;
356 opt->nd_opt_mtu_len = 1;
357 opt->nd_opt_mtu_reserved = 0;
358 opt->nd_opt_mtu_mtu = htonl (zif->rtadv.AdvLinkMTU);
359 len += sizeof (struct nd_opt_mtu);
360 }
361
paul718e3742002-12-13 20:15:29 +0000362 msg.msg_name = (void *) &addr;
363 msg.msg_namelen = sizeof (struct sockaddr_in6);
364 msg.msg_iov = &iov;
365 msg.msg_iovlen = 1;
366 msg.msg_control = (void *) adata;
gdtf841e022004-08-11 19:20:01 +0000367 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
gdt57492d52004-08-11 18:06:38 +0000368 msg.msg_flags = 0;
paul718e3742002-12-13 20:15:29 +0000369 iov.iov_base = buf;
370 iov.iov_len = len;
371
ajsb99760a2005-01-04 16:24:43 +0000372 cmsgptr = ZCMSG_FIRSTHDR(&msg);
gdt57492d52004-08-11 18:06:38 +0000373 cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
paul718e3742002-12-13 20:15:29 +0000374 cmsgptr->cmsg_level = IPPROTO_IPV6;
375 cmsgptr->cmsg_type = IPV6_PKTINFO;
gdt80893812004-08-11 15:58:00 +0000376
paul718e3742002-12-13 20:15:29 +0000377 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
378 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
379 pkt->ipi6_ifindex = ifp->ifindex;
380
381 ret = sendmsg (sock, &msg, 0);
gdt9ccabd12004-01-06 18:23:02 +0000382 if (ret < 0)
383 {
384 zlog_err ("rtadv_send_packet: sendmsg %d (%s)\n",
ajs6099b3b2004-11-20 02:06:59 +0000385 errno, safe_strerror(errno));
gdt9ccabd12004-01-06 18:23:02 +0000386 }
paul718e3742002-12-13 20:15:29 +0000387}
388
paula1ac18c2005-06-28 17:17:12 +0000389static int
paul718e3742002-12-13 20:15:29 +0000390rtadv_timer (struct thread *thread)
391{
paul1eb8ef22005-04-07 07:30:20 +0000392 struct listnode *node, *nnode;
paul718e3742002-12-13 20:15:29 +0000393 struct interface *ifp;
394 struct zebra_if *zif;
vincent7cee1bb2005-03-25 13:08:53 +0000395 int period;
paul718e3742002-12-13 20:15:29 +0000396
397 rtadv->ra_timer = NULL;
vincent7cee1bb2005-03-25 13:08:53 +0000398 if (rtadv->adv_msec_if_count == 0)
399 {
400 period = 1000; /* 1 s */
401 rtadv_event (RTADV_TIMER, 1 /* 1 s */);
402 }
403 else
404 {
405 period = 10; /* 10 ms */
406 rtadv_event (RTADV_TIMER_MSEC, 10 /* 10 ms */);
407 }
paul718e3742002-12-13 20:15:29 +0000408
paul1eb8ef22005-04-07 07:30:20 +0000409 for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
paul718e3742002-12-13 20:15:29 +0000410 {
Denis Ovsienkofb5174a2011-12-27 10:18:47 +0400411 if (if_is_loopback (ifp) || ! if_is_operative (ifp))
paul718e3742002-12-13 20:15:29 +0000412 continue;
413
414 zif = ifp->info;
415
416 if (zif->rtadv.AdvSendAdvertisements)
vincent7cee1bb2005-03-25 13:08:53 +0000417 {
418 zif->rtadv.AdvIntervalTimer -= period;
419 if (zif->rtadv.AdvIntervalTimer <= 0)
420 {
Denis Ovsienkod660f692011-12-30 21:55:49 +0400421 /* FIXME: using MaxRtrAdvInterval each time isn't what section
422 6.2.4 of RFC4861 tells to do. */
vincent7cee1bb2005-03-25 13:08:53 +0000423 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
424 rtadv_send_packet (rtadv->sock, ifp);
425 }
426 }
paul718e3742002-12-13 20:15:29 +0000427 }
428 return 0;
429}
430
paula1ac18c2005-06-28 17:17:12 +0000431static void
paul718e3742002-12-13 20:15:29 +0000432rtadv_process_solicit (struct interface *ifp)
433{
434 zlog_info ("Router solicitation received on %s", ifp->name);
435
436 rtadv_send_packet (rtadv->sock, ifp);
437}
438
paula1ac18c2005-06-28 17:17:12 +0000439static void
440rtadv_process_advert (void)
paul718e3742002-12-13 20:15:29 +0000441{
442 zlog_info ("Router advertisement received");
443}
444
paula1ac18c2005-06-28 17:17:12 +0000445static void
hassofce954f2004-10-07 20:29:24 +0000446rtadv_process_packet (u_char *buf, unsigned int len, unsigned int ifindex, int hoplimit)
paul718e3742002-12-13 20:15:29 +0000447{
448 struct icmp6_hdr *icmph;
449 struct interface *ifp;
450 struct zebra_if *zif;
451
452 /* Interface search. */
453 ifp = if_lookup_by_index (ifindex);
454 if (ifp == NULL)
455 {
456 zlog_warn ("Unknown interface index: %d", ifindex);
457 return;
458 }
459
460 if (if_is_loopback (ifp))
461 return;
462
463 /* Check interface configuration. */
464 zif = ifp->info;
465 if (! zif->rtadv.AdvSendAdvertisements)
466 return;
467
468 /* ICMP message length check. */
469 if (len < sizeof (struct icmp6_hdr))
470 {
471 zlog_warn ("Invalid ICMPV6 packet length: %d", len);
472 return;
473 }
474
475 icmph = (struct icmp6_hdr *) buf;
476
477 /* ICMP message type check. */
478 if (icmph->icmp6_type != ND_ROUTER_SOLICIT &&
479 icmph->icmp6_type != ND_ROUTER_ADVERT)
480 {
481 zlog_warn ("Unwanted ICMPV6 message type: %d", icmph->icmp6_type);
482 return;
483 }
484
485 /* Hoplimit check. */
486 if (hoplimit >= 0 && hoplimit != 255)
487 {
488 zlog_warn ("Invalid hoplimit %d for router advertisement ICMP packet",
489 hoplimit);
490 return;
491 }
492
493 /* Check ICMP message type. */
494 if (icmph->icmp6_type == ND_ROUTER_SOLICIT)
495 rtadv_process_solicit (ifp);
496 else if (icmph->icmp6_type == ND_ROUTER_ADVERT)
497 rtadv_process_advert ();
498
499 return;
500}
501
paula1ac18c2005-06-28 17:17:12 +0000502static int
paul718e3742002-12-13 20:15:29 +0000503rtadv_read (struct thread *thread)
504{
505 int sock;
506 int len;
507 u_char buf[RTADV_MSG_SIZE];
508 struct sockaddr_in6 from;
Stephen Hemmingerb0b709a2009-12-08 13:26:14 +0300509 unsigned int ifindex = 0;
paul718e3742002-12-13 20:15:29 +0000510 int hoplimit = -1;
511
512 sock = THREAD_FD (thread);
513 rtadv->ra_read = NULL;
514
515 /* Register myself. */
516 rtadv_event (RTADV_READ, sock);
517
518 len = rtadv_recv_packet (sock, buf, BUFSIZ, &from, &ifindex, &hoplimit);
519
520 if (len < 0)
521 {
ajs6099b3b2004-11-20 02:06:59 +0000522 zlog_warn ("router solicitation recv failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000523 return len;
524 }
525
hassofce954f2004-10-07 20:29:24 +0000526 rtadv_process_packet (buf, (unsigned)len, ifindex, hoplimit);
paul718e3742002-12-13 20:15:29 +0000527
528 return 0;
529}
530
paula1ac18c2005-06-28 17:17:12 +0000531static int
paul718e3742002-12-13 20:15:29 +0000532rtadv_make_socket (void)
533{
534 int sock;
535 int ret;
536 struct icmp6_filter filter;
537
pauledd7c242003-06-04 13:59:38 +0000538 if ( zserv_privs.change (ZPRIVS_RAISE) )
539 zlog_err ("rtadv_make_socket: could not raise privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000540 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000541
paul718e3742002-12-13 20:15:29 +0000542 sock = socket (AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
543
pauledd7c242003-06-04 13:59:38 +0000544 if ( zserv_privs.change (ZPRIVS_LOWER) )
545 zlog_err ("rtadv_make_socket: could not lower privs, %s",
ajs6099b3b2004-11-20 02:06:59 +0000546 safe_strerror (errno) );
pauledd7c242003-06-04 13:59:38 +0000547
paul718e3742002-12-13 20:15:29 +0000548 /* When we can't make ICMPV6 socket simply back. Router
549 advertisement feature will not be supported. */
550 if (sock < 0)
551 return -1;
552
553 ret = setsockopt_ipv6_pktinfo (sock, 1);
554 if (ret < 0)
555 return ret;
paul718e3742002-12-13 20:15:29 +0000556 ret = setsockopt_ipv6_multicast_loop (sock, 0);
557 if (ret < 0)
558 return ret;
559 ret = setsockopt_ipv6_unicast_hops (sock, 255);
560 if (ret < 0)
561 return ret;
562 ret = setsockopt_ipv6_multicast_hops (sock, 255);
563 if (ret < 0)
564 return ret;
565 ret = setsockopt_ipv6_hoplimit (sock, 1);
566 if (ret < 0)
567 return ret;
568
569 ICMP6_FILTER_SETBLOCKALL(&filter);
570 ICMP6_FILTER_SETPASS (ND_ROUTER_SOLICIT, &filter);
571 ICMP6_FILTER_SETPASS (ND_ROUTER_ADVERT, &filter);
572
573 ret = setsockopt (sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filter,
574 sizeof (struct icmp6_filter));
575 if (ret < 0)
576 {
ajs6099b3b2004-11-20 02:06:59 +0000577 zlog_info ("ICMP6_FILTER set fail: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +0000578 return ret;
579 }
580
581 return sock;
582}
583
paula1ac18c2005-06-28 17:17:12 +0000584static struct rtadv_prefix *
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800585rtadv_prefix_new (void)
paul718e3742002-12-13 20:15:29 +0000586{
Stephen Hemminger393deb92008-08-18 14:13:29 -0700587 return XCALLOC (MTYPE_RTADV_PREFIX, sizeof (struct rtadv_prefix));
paul718e3742002-12-13 20:15:29 +0000588}
589
paula1ac18c2005-06-28 17:17:12 +0000590static void
paul718e3742002-12-13 20:15:29 +0000591rtadv_prefix_free (struct rtadv_prefix *rtadv_prefix)
592{
593 XFREE (MTYPE_RTADV_PREFIX, rtadv_prefix);
594}
595
paula1ac18c2005-06-28 17:17:12 +0000596static struct rtadv_prefix *
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400597rtadv_prefix_lookup (struct list *rplist, struct prefix_ipv6 *p)
paul718e3742002-12-13 20:15:29 +0000598{
hasso52dc7ee2004-09-23 19:18:23 +0000599 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000600 struct rtadv_prefix *rprefix;
601
paul1eb8ef22005-04-07 07:30:20 +0000602 for (ALL_LIST_ELEMENTS_RO (rplist, node, rprefix))
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400603 if (prefix_same ((struct prefix *) &rprefix->prefix, (struct prefix *) p))
paul1eb8ef22005-04-07 07:30:20 +0000604 return rprefix;
paul718e3742002-12-13 20:15:29 +0000605 return NULL;
606}
607
paula1ac18c2005-06-28 17:17:12 +0000608static struct rtadv_prefix *
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400609rtadv_prefix_get (struct list *rplist, struct prefix_ipv6 *p)
paul718e3742002-12-13 20:15:29 +0000610{
611 struct rtadv_prefix *rprefix;
612
613 rprefix = rtadv_prefix_lookup (rplist, p);
614 if (rprefix)
615 return rprefix;
616
617 rprefix = rtadv_prefix_new ();
Denis Ovsienkoaca43b62012-01-08 18:27:12 +0400618 memcpy (&rprefix->prefix, p, sizeof (struct prefix_ipv6));
paul718e3742002-12-13 20:15:29 +0000619 listnode_add (rplist, rprefix);
620
621 return rprefix;
622}
623
paula1ac18c2005-06-28 17:17:12 +0000624static void
paul718e3742002-12-13 20:15:29 +0000625rtadv_prefix_set (struct zebra_if *zif, struct rtadv_prefix *rp)
626{
627 struct rtadv_prefix *rprefix;
628
629 rprefix = rtadv_prefix_get (zif->rtadv.AdvPrefixList, &rp->prefix);
630
631 /* Set parameters. */
632 rprefix->AdvValidLifetime = rp->AdvValidLifetime;
633 rprefix->AdvPreferredLifetime = rp->AdvPreferredLifetime;
634 rprefix->AdvOnLinkFlag = rp->AdvOnLinkFlag;
635 rprefix->AdvAutonomousFlag = rp->AdvAutonomousFlag;
vincent7cee1bb2005-03-25 13:08:53 +0000636 rprefix->AdvRouterAddressFlag = rp->AdvRouterAddressFlag;
paul718e3742002-12-13 20:15:29 +0000637}
638
paula1ac18c2005-06-28 17:17:12 +0000639static int
paul718e3742002-12-13 20:15:29 +0000640rtadv_prefix_reset (struct zebra_if *zif, struct rtadv_prefix *rp)
641{
642 struct rtadv_prefix *rprefix;
643
644 rprefix = rtadv_prefix_lookup (zif->rtadv.AdvPrefixList, &rp->prefix);
645 if (rprefix != NULL)
646 {
647 listnode_delete (zif->rtadv.AdvPrefixList, (void *) rprefix);
648 rtadv_prefix_free (rprefix);
649 return 1;
650 }
651 else
652 return 0;
653}
654
655DEFUN (ipv6_nd_suppress_ra,
656 ipv6_nd_suppress_ra_cmd,
657 "ipv6 nd suppress-ra",
hasso3e31cde2004-05-18 11:58:59 +0000658 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000659 "Neighbor discovery\n"
660 "Suppress Router Advertisement\n")
661{
662 struct interface *ifp;
663 struct zebra_if *zif;
664
665 ifp = vty->index;
666 zif = ifp->info;
667
668 if (if_is_loopback (ifp))
669 {
670 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
671 return CMD_WARNING;
672 }
673
674 if (zif->rtadv.AdvSendAdvertisements)
675 {
676 zif->rtadv.AdvSendAdvertisements = 0;
677 zif->rtadv.AdvIntervalTimer = 0;
678 rtadv->adv_if_count--;
679
680 if_leave_all_router (rtadv->sock, ifp);
681
682 if (rtadv->adv_if_count == 0)
683 rtadv_event (RTADV_STOP, 0);
684 }
685
686 return CMD_SUCCESS;
687}
688
paul718e3742002-12-13 20:15:29 +0000689DEFUN (no_ipv6_nd_suppress_ra,
690 no_ipv6_nd_suppress_ra_cmd,
691 "no ipv6 nd suppress-ra",
692 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000693 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000694 "Neighbor discovery\n"
695 "Suppress Router Advertisement\n")
696{
697 struct interface *ifp;
698 struct zebra_if *zif;
699
700 ifp = vty->index;
701 zif = ifp->info;
702
703 if (if_is_loopback (ifp))
704 {
705 vty_out (vty, "Invalid interface%s", VTY_NEWLINE);
706 return CMD_WARNING;
707 }
708
709 if (! zif->rtadv.AdvSendAdvertisements)
710 {
711 zif->rtadv.AdvSendAdvertisements = 1;
712 zif->rtadv.AdvIntervalTimer = 0;
713 rtadv->adv_if_count++;
714
715 if_join_all_router (rtadv->sock, ifp);
716
717 if (rtadv->adv_if_count == 1)
718 rtadv_event (RTADV_START, rtadv->sock);
719 }
720
721 return CMD_SUCCESS;
722}
723
vincent7cee1bb2005-03-25 13:08:53 +0000724DEFUN (ipv6_nd_ra_interval_msec,
725 ipv6_nd_ra_interval_msec_cmd,
726 "ipv6 nd ra-interval msec MILLISECONDS",
727 "Interface IPv6 config commands\n"
728 "Neighbor discovery\n"
729 "Router Advertisement interval\n"
730 "Router Advertisement interval in milliseconds\n")
731{
732 int interval;
733 struct interface *ifp;
734 struct zebra_if *zif;
735
736 ifp = (struct interface *) vty->index;
737 zif = ifp->info;
738
739 interval = atoi (argv[0]);
740
Denis Ovsienkod660f692011-12-30 21:55:49 +0400741 if
742 (
743 interval < 70 || interval > 1800000 ||
744 (zif->rtadv.AdvDefaultLifetime != -1 && interval > zif->rtadv.AdvDefaultLifetime * 1000)
745 )
vincent7cee1bb2005-03-25 13:08:53 +0000746 {
747 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
748 return CMD_WARNING;
749 }
750
751 if (zif->rtadv.MaxRtrAdvInterval % 1000)
752 rtadv->adv_msec_if_count--;
753
754 if (interval % 1000)
755 rtadv->adv_msec_if_count++;
756
757 zif->rtadv.MaxRtrAdvInterval = interval;
758 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
759 zif->rtadv.AdvIntervalTimer = 0;
760
761 return CMD_SUCCESS;
762}
763
paul718e3742002-12-13 20:15:29 +0000764DEFUN (ipv6_nd_ra_interval,
765 ipv6_nd_ra_interval_cmd,
766 "ipv6 nd ra-interval SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000767 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000768 "Neighbor discovery\n"
769 "Router Advertisement interval\n"
770 "Router Advertisement interval in seconds\n")
771{
772 int interval;
773 struct interface *ifp;
774 struct zebra_if *zif;
775
776 ifp = (struct interface *) vty->index;
777 zif = ifp->info;
778
779 interval = atoi (argv[0]);
780
Denis Ovsienkod660f692011-12-30 21:55:49 +0400781 if
782 (
783 interval < 1 || interval > 1800 ||
784 (zif->rtadv.AdvDefaultLifetime != -1 && interval > zif->rtadv.AdvDefaultLifetime)
785 )
paul718e3742002-12-13 20:15:29 +0000786 {
787 vty_out (vty, "Invalid Router Advertisement Interval%s", VTY_NEWLINE);
788 return CMD_WARNING;
789 }
790
vincent7cee1bb2005-03-25 13:08:53 +0000791 if (zif->rtadv.MaxRtrAdvInterval % 1000)
792 rtadv->adv_msec_if_count--;
793
794 /* convert to milliseconds */
795 interval = interval * 1000;
796
paul718e3742002-12-13 20:15:29 +0000797 zif->rtadv.MaxRtrAdvInterval = interval;
798 zif->rtadv.MinRtrAdvInterval = 0.33 * interval;
799 zif->rtadv.AdvIntervalTimer = 0;
800
801 return CMD_SUCCESS;
802}
803
804DEFUN (no_ipv6_nd_ra_interval,
805 no_ipv6_nd_ra_interval_cmd,
806 "no ipv6 nd ra-interval",
807 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000808 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000809 "Neighbor discovery\n"
810 "Router Advertisement interval\n")
811{
812 struct interface *ifp;
813 struct zebra_if *zif;
814
815 ifp = (struct interface *) vty->index;
816 zif = ifp->info;
817
vincent7cee1bb2005-03-25 13:08:53 +0000818 if (zif->rtadv.MaxRtrAdvInterval % 1000)
819 rtadv->adv_msec_if_count--;
820
paul718e3742002-12-13 20:15:29 +0000821 zif->rtadv.MaxRtrAdvInterval = RTADV_MAX_RTR_ADV_INTERVAL;
822 zif->rtadv.MinRtrAdvInterval = RTADV_MIN_RTR_ADV_INTERVAL;
823 zif->rtadv.AdvIntervalTimer = zif->rtadv.MaxRtrAdvInterval;
824
825 return CMD_SUCCESS;
826}
827
828DEFUN (ipv6_nd_ra_lifetime,
829 ipv6_nd_ra_lifetime_cmd,
830 "ipv6 nd ra-lifetime SECONDS",
hasso3e31cde2004-05-18 11:58:59 +0000831 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000832 "Neighbor discovery\n"
833 "Router lifetime\n"
834 "Router lifetime in seconds\n")
835{
836 int lifetime;
837 struct interface *ifp;
838 struct zebra_if *zif;
839
840 ifp = (struct interface *) vty->index;
841 zif = ifp->info;
842
843 lifetime = atoi (argv[0]);
844
Denis Ovsienkod660f692011-12-30 21:55:49 +0400845 /* The value to be placed in the Router Lifetime field
846 * of Router Advertisements sent from the interface,
847 * in seconds. MUST be either zero or between
848 * MaxRtrAdvInterval and 9000 seconds. -- RFC4861, 6.2.1 */
849 if
850 (
851 lifetime > RTADV_MAX_RTRLIFETIME ||
852 (lifetime != 0 && lifetime * 1000 < zif->rtadv.MaxRtrAdvInterval)
853 )
paul718e3742002-12-13 20:15:29 +0000854 {
855 vty_out (vty, "Invalid Router Lifetime%s", VTY_NEWLINE);
856 return CMD_WARNING;
857 }
858
859 zif->rtadv.AdvDefaultLifetime = lifetime;
860
861 return CMD_SUCCESS;
862}
863
864DEFUN (no_ipv6_nd_ra_lifetime,
865 no_ipv6_nd_ra_lifetime_cmd,
866 "no ipv6 nd ra-lifetime",
867 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000868 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000869 "Neighbor discovery\n"
870 "Router lifetime\n")
871{
872 struct interface *ifp;
873 struct zebra_if *zif;
874
875 ifp = (struct interface *) vty->index;
876 zif = ifp->info;
877
Denis Ovsienkod660f692011-12-30 21:55:49 +0400878 zif->rtadv.AdvDefaultLifetime = -1;
paul718e3742002-12-13 20:15:29 +0000879
880 return CMD_SUCCESS;
881}
882
883DEFUN (ipv6_nd_reachable_time,
884 ipv6_nd_reachable_time_cmd,
885 "ipv6 nd reachable-time MILLISECONDS",
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{
891 u_int32_t rtime;
892 struct interface *ifp;
893 struct zebra_if *zif;
894
895 ifp = (struct interface *) vty->index;
896 zif = ifp->info;
897
898 rtime = (u_int32_t) atol (argv[0]);
899
900 if (rtime > RTADV_MAX_REACHABLE_TIME)
901 {
902 vty_out (vty, "Invalid Reachable time%s", VTY_NEWLINE);
903 return CMD_WARNING;
904 }
905
906 zif->rtadv.AdvReachableTime = rtime;
907
908 return CMD_SUCCESS;
909}
910
911DEFUN (no_ipv6_nd_reachable_time,
912 no_ipv6_nd_reachable_time_cmd,
913 "no ipv6 nd reachable-time",
914 NO_STR
hasso3e31cde2004-05-18 11:58:59 +0000915 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +0000916 "Neighbor discovery\n"
917 "Reachable time\n")
918{
919 struct interface *ifp;
920 struct zebra_if *zif;
921
922 ifp = (struct interface *) vty->index;
923 zif = ifp->info;
924
925 zif->rtadv.AdvReachableTime = 0;
926
927 return CMD_SUCCESS;
928}
929
vincent7cee1bb2005-03-25 13:08:53 +0000930DEFUN (ipv6_nd_homeagent_preference,
931 ipv6_nd_homeagent_preference_cmd,
932 "ipv6 nd home-agent-preference PREFERENCE",
933 "Interface IPv6 config commands\n"
934 "Neighbor discovery\n"
935 "Home Agent preference\n"
936 "Home Agent preference value 0..65535\n")
937{
938 u_int32_t hapref;
939 struct interface *ifp;
940 struct zebra_if *zif;
941
942 ifp = (struct interface *) vty->index;
943 zif = ifp->info;
944
945 hapref = (u_int32_t) atol (argv[0]);
946
947 if (hapref > 65535)
948 {
949 vty_out (vty, "Invalid Home Agent preference%s", VTY_NEWLINE);
950 return CMD_WARNING;
951 }
952
953 zif->rtadv.HomeAgentPreference = hapref;
954
955 return CMD_SUCCESS;
956}
957
958DEFUN (no_ipv6_nd_homeagent_preference,
959 no_ipv6_nd_homeagent_preference_cmd,
960 "no ipv6 nd home-agent-preference",
961 NO_STR
962 "Interface IPv6 config commands\n"
963 "Neighbor discovery\n"
964 "Home Agent preference\n")
965{
966 struct interface *ifp;
967 struct zebra_if *zif;
968
969 ifp = (struct interface *) vty->index;
970 zif = ifp->info;
971
972 zif->rtadv.HomeAgentPreference = 0;
973
974 return CMD_SUCCESS;
975}
976
977DEFUN (ipv6_nd_homeagent_lifetime,
978 ipv6_nd_homeagent_lifetime_cmd,
979 "ipv6 nd home-agent-lifetime SECONDS",
980 "Interface IPv6 config commands\n"
981 "Neighbor discovery\n"
982 "Home Agent lifetime\n"
983 "Home Agent lifetime in seconds\n")
984{
985 u_int32_t ha_ltime;
986 struct interface *ifp;
987 struct zebra_if *zif;
988
989 ifp = (struct interface *) vty->index;
990 zif = ifp->info;
991
992 ha_ltime = (u_int32_t) atol (argv[0]);
993
Denis Ovsienkod660f692011-12-30 21:55:49 +0400994 if (ha_ltime < 1 || ha_ltime > RTADV_MAX_HALIFETIME)
vincent7cee1bb2005-03-25 13:08:53 +0000995 {
996 vty_out (vty, "Invalid Home Agent Lifetime time%s", VTY_NEWLINE);
997 return CMD_WARNING;
998 }
999
1000 zif->rtadv.HomeAgentLifetime = ha_ltime;
1001
1002 return CMD_SUCCESS;
1003}
1004
1005DEFUN (no_ipv6_nd_homeagent_lifetime,
1006 no_ipv6_nd_homeagent_lifetime_cmd,
1007 "no ipv6 nd home-agent-lifetime",
1008 NO_STR
1009 "Interface IPv6 config commands\n"
1010 "Neighbor discovery\n"
1011 "Home Agent lifetime\n")
1012{
1013 struct interface *ifp;
1014 struct zebra_if *zif;
1015
1016 ifp = (struct interface *) vty->index;
1017 zif = ifp->info;
1018
Denis Ovsienkod660f692011-12-30 21:55:49 +04001019 zif->rtadv.HomeAgentLifetime = -1;
vincent7cee1bb2005-03-25 13:08:53 +00001020
1021 return CMD_SUCCESS;
1022}
1023
paul718e3742002-12-13 20:15:29 +00001024DEFUN (ipv6_nd_managed_config_flag,
1025 ipv6_nd_managed_config_flag_cmd,
1026 "ipv6 nd managed-config-flag",
hasso3e31cde2004-05-18 11:58:59 +00001027 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001028 "Neighbor discovery\n"
1029 "Managed address configuration flag\n")
1030{
1031 struct interface *ifp;
1032 struct zebra_if *zif;
1033
1034 ifp = (struct interface *) vty->index;
1035 zif = ifp->info;
1036
1037 zif->rtadv.AdvManagedFlag = 1;
1038
1039 return CMD_SUCCESS;
1040}
1041
1042DEFUN (no_ipv6_nd_managed_config_flag,
1043 no_ipv6_nd_managed_config_flag_cmd,
1044 "no ipv6 nd managed-config-flag",
1045 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001046 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001047 "Neighbor discovery\n"
1048 "Managed address configuration flag\n")
1049{
1050 struct interface *ifp;
1051 struct zebra_if *zif;
1052
1053 ifp = (struct interface *) vty->index;
1054 zif = ifp->info;
1055
1056 zif->rtadv.AdvManagedFlag = 0;
1057
1058 return CMD_SUCCESS;
1059}
1060
vincent7cee1bb2005-03-25 13:08:53 +00001061DEFUN (ipv6_nd_homeagent_config_flag,
1062 ipv6_nd_homeagent_config_flag_cmd,
1063 "ipv6 nd home-agent-config-flag",
1064 "Interface IPv6 config commands\n"
1065 "Neighbor discovery\n"
1066 "Home Agent configuration flag\n")
1067{
1068 struct interface *ifp;
1069 struct zebra_if *zif;
1070
1071 ifp = (struct interface *) vty->index;
1072 zif = ifp->info;
1073
1074 zif->rtadv.AdvHomeAgentFlag = 1;
1075
1076 return CMD_SUCCESS;
1077}
1078
1079DEFUN (no_ipv6_nd_homeagent_config_flag,
1080 no_ipv6_nd_homeagent_config_flag_cmd,
1081 "no ipv6 nd home-agent-config-flag",
1082 NO_STR
1083 "Interface IPv6 config commands\n"
1084 "Neighbor discovery\n"
1085 "Home Agent configuration flag\n")
1086{
1087 struct interface *ifp;
1088 struct zebra_if *zif;
1089
1090 ifp = (struct interface *) vty->index;
1091 zif = ifp->info;
1092
1093 zif->rtadv.AdvHomeAgentFlag = 0;
1094
1095 return CMD_SUCCESS;
1096}
1097
1098DEFUN (ipv6_nd_adv_interval_config_option,
1099 ipv6_nd_adv_interval_config_option_cmd,
1100 "ipv6 nd adv-interval-option",
1101 "Interface IPv6 config commands\n"
1102 "Neighbor discovery\n"
1103 "Advertisement Interval Option\n")
1104{
1105 struct interface *ifp;
1106 struct zebra_if *zif;
1107
1108 ifp = (struct interface *) vty->index;
1109 zif = ifp->info;
1110
1111 zif->rtadv.AdvIntervalOption = 1;
1112
1113 return CMD_SUCCESS;
1114}
1115
1116DEFUN (no_ipv6_nd_adv_interval_config_option,
1117 no_ipv6_nd_adv_interval_config_option_cmd,
1118 "no ipv6 nd adv-interval-option",
1119 NO_STR
1120 "Interface IPv6 config commands\n"
1121 "Neighbor discovery\n"
1122 "Advertisement Interval Option\n")
1123{
1124 struct interface *ifp;
1125 struct zebra_if *zif;
1126
1127 ifp = (struct interface *) vty->index;
1128 zif = ifp->info;
1129
1130 zif->rtadv.AdvIntervalOption = 0;
1131
1132 return CMD_SUCCESS;
1133}
1134
paul718e3742002-12-13 20:15:29 +00001135DEFUN (ipv6_nd_other_config_flag,
1136 ipv6_nd_other_config_flag_cmd,
1137 "ipv6 nd other-config-flag",
hasso3e31cde2004-05-18 11:58:59 +00001138 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001139 "Neighbor discovery\n"
1140 "Other statefull configuration flag\n")
1141{
1142 struct interface *ifp;
1143 struct zebra_if *zif;
1144
1145 ifp = (struct interface *) vty->index;
1146 zif = ifp->info;
1147
1148 zif->rtadv.AdvOtherConfigFlag = 1;
1149
1150 return CMD_SUCCESS;
1151}
1152
1153DEFUN (no_ipv6_nd_other_config_flag,
1154 no_ipv6_nd_other_config_flag_cmd,
1155 "no ipv6 nd other-config-flag",
1156 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001157 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001158 "Neighbor discovery\n"
1159 "Other statefull configuration flag\n")
1160{
1161 struct interface *ifp;
1162 struct zebra_if *zif;
1163
1164 ifp = (struct interface *) vty->index;
1165 zif = ifp->info;
1166
1167 zif->rtadv.AdvOtherConfigFlag = 0;
1168
1169 return CMD_SUCCESS;
1170}
1171
hasso3e31cde2004-05-18 11:58:59 +00001172DEFUN (ipv6_nd_prefix,
1173 ipv6_nd_prefix_cmd,
1174 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
vincent7cee1bb2005-03-25 13:08:53 +00001175 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|) (router-address|)",
hasso3e31cde2004-05-18 11:58:59 +00001176 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001177 "Neighbor discovery\n"
1178 "Prefix information\n"
1179 "IPv6 prefix\n"
1180 "Valid lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001181 "Infinite valid lifetime\n"
paul718e3742002-12-13 20:15:29 +00001182 "Preferred lifetime in seconds\n"
hasso3e31cde2004-05-18 11:58:59 +00001183 "Infinite preferred lifetime\n"
1184 "Do not use prefix for onlink determination\n"
vincent7cee1bb2005-03-25 13:08:53 +00001185 "Do not use prefix for autoconfiguration\n"
1186 "Set Router Address flag\n")
paul718e3742002-12-13 20:15:29 +00001187{
1188 int i;
1189 int ret;
hasso3e31cde2004-05-18 11:58:59 +00001190 int cursor = 1;
paul718e3742002-12-13 20:15:29 +00001191 struct interface *ifp;
1192 struct zebra_if *zebra_if;
1193 struct rtadv_prefix rp;
1194
1195 ifp = (struct interface *) vty->index;
1196 zebra_if = ifp->info;
1197
Denis Ovsienkoaca43b62012-01-08 18:27:12 +04001198 ret = str2prefix_ipv6 (argv[0], &rp.prefix);
paul718e3742002-12-13 20:15:29 +00001199 if (!ret)
1200 {
1201 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1202 return CMD_WARNING;
1203 }
Denis Ovsienko6bb12732012-01-08 17:46:34 +04001204 apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
hasso3e31cde2004-05-18 11:58:59 +00001205 rp.AdvOnLinkFlag = 1;
1206 rp.AdvAutonomousFlag = 1;
vincent7cee1bb2005-03-25 13:08:53 +00001207 rp.AdvRouterAddressFlag = 0;
hasso3e31cde2004-05-18 11:58:59 +00001208 rp.AdvValidLifetime = RTADV_VALID_LIFETIME;
1209 rp.AdvPreferredLifetime = RTADV_PREFERRED_LIFETIME;
paul718e3742002-12-13 20:15:29 +00001210
hasso3e31cde2004-05-18 11:58:59 +00001211 if (argc > 1)
paul718e3742002-12-13 20:15:29 +00001212 {
hasso3e31cde2004-05-18 11:58:59 +00001213 if ((isdigit(argv[1][0])) || strncmp (argv[1], "i", 1) == 0)
paul718e3742002-12-13 20:15:29 +00001214 {
hasso3e31cde2004-05-18 11:58:59 +00001215 if ( strncmp (argv[1], "i", 1) == 0)
1216 rp.AdvValidLifetime = UINT32_MAX;
1217 else
1218 rp.AdvValidLifetime = (u_int32_t) strtoll (argv[1],
1219 (char **)NULL, 10);
1220
1221 if ( strncmp (argv[2], "i", 1) == 0)
1222 rp.AdvPreferredLifetime = UINT32_MAX;
1223 else
1224 rp.AdvPreferredLifetime = (u_int32_t) strtoll (argv[2],
1225 (char **)NULL, 10);
1226
1227 if (rp.AdvPreferredLifetime > rp.AdvValidLifetime)
1228 {
1229 vty_out (vty, "Invalid preferred lifetime%s", VTY_NEWLINE);
1230 return CMD_WARNING;
1231 }
1232 cursor = cursor + 2;
paul718e3742002-12-13 20:15:29 +00001233 }
hasso3e31cde2004-05-18 11:58:59 +00001234 if (argc > cursor)
paul718e3742002-12-13 20:15:29 +00001235 {
hasso3e31cde2004-05-18 11:58:59 +00001236 for (i = cursor; i < argc; i++)
1237 {
1238 if (strncmp (argv[i], "of", 2) == 0)
1239 rp.AdvOnLinkFlag = 0;
1240 if (strncmp (argv[i], "no", 2) == 0)
1241 rp.AdvAutonomousFlag = 0;
vincent7cee1bb2005-03-25 13:08:53 +00001242 if (strncmp (argv[i], "ro", 2) == 0)
1243 rp.AdvRouterAddressFlag = 1;
hasso3e31cde2004-05-18 11:58:59 +00001244 }
paul718e3742002-12-13 20:15:29 +00001245 }
1246 }
1247
1248 rtadv_prefix_set (zebra_if, &rp);
1249
1250 return CMD_SUCCESS;
1251}
1252
hasso3e31cde2004-05-18 11:58:59 +00001253ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001254 ipv6_nd_prefix_val_nortaddr_cmd,
1255 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1256 "(<0-4294967295>|infinite) (off-link|) (no-autoconfig|)",
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 onlink determination\n"
1266 "Do not use prefix for autoconfiguration\n")
1267
1268ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001269 ipv6_nd_prefix_val_rev_cmd,
1270 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1271 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|)",
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
1283ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001284 ipv6_nd_prefix_val_rev_rtaddr_cmd,
1285 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1286 "(<0-4294967295>|infinite) (no-autoconfig|) (off-link|) (router-address|)",
1287 "Interface IPv6 config commands\n"
1288 "Neighbor discovery\n"
1289 "Prefix information\n"
1290 "IPv6 prefix\n"
1291 "Valid lifetime in seconds\n"
1292 "Infinite valid lifetime\n"
1293 "Preferred lifetime in seconds\n"
1294 "Infinite preferred lifetime\n"
1295 "Do not use prefix for autoconfiguration\n"
1296 "Do not use prefix for onlink determination\n"
1297 "Set Router Address flag\n")
1298
1299ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001300 ipv6_nd_prefix_val_noauto_cmd,
1301 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1302 "(<0-4294967295>|infinite) (no-autoconfig|)",
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"
vincent7cee1bb2005-03-25 13:08:53 +00001311 "Do not use prefix for autoconfiguration")
hasso3e31cde2004-05-18 11:58:59 +00001312
1313ALIAS (ipv6_nd_prefix,
1314 ipv6_nd_prefix_val_offlink_cmd,
1315 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1316 "(<0-4294967295>|infinite) (off-link|)",
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 "Do not use prefix for onlink determination\n")
1326
1327ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001328 ipv6_nd_prefix_val_rtaddr_cmd,
1329 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1330 "(<0-4294967295>|infinite) (router-address|)",
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 "Set Router Address flag\n")
1340
1341ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001342 ipv6_nd_prefix_val_cmd,
1343 "ipv6 nd prefix X:X::X:X/M (<0-4294967295>|infinite) "
1344 "(<0-4294967295>|infinite)",
1345 "Interface IPv6 config commands\n"
1346 "Neighbor discovery\n"
1347 "Prefix information\n"
1348 "IPv6 prefix\n"
1349 "Valid lifetime in seconds\n"
1350 "Infinite valid lifetime\n"
1351 "Preferred lifetime in seconds\n"
1352 "Infinite preferred lifetime\n")
1353
1354ALIAS (ipv6_nd_prefix,
1355 ipv6_nd_prefix_noval_cmd,
1356 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|) (off-link|)",
1357 "Interface IPv6 config commands\n"
1358 "Neighbor discovery\n"
1359 "Prefix information\n"
1360 "IPv6 prefix\n"
1361 "Do not use prefix for autoconfiguration\n"
1362 "Do not use prefix for onlink determination\n")
1363
1364ALIAS (ipv6_nd_prefix,
1365 ipv6_nd_prefix_noval_rev_cmd,
1366 "ipv6 nd prefix X:X::X:X/M (off-link|) (no-autoconfig|)",
1367 "Interface IPv6 config commands\n"
1368 "Neighbor discovery\n"
1369 "Prefix information\n"
1370 "IPv6 prefix\n"
1371 "Do not use prefix for onlink determination\n"
1372 "Do not use prefix for autoconfiguration\n")
1373
1374ALIAS (ipv6_nd_prefix,
1375 ipv6_nd_prefix_noval_noauto_cmd,
1376 "ipv6 nd prefix X:X::X:X/M (no-autoconfig|)",
1377 "Interface IPv6 config commands\n"
1378 "Neighbor discovery\n"
1379 "Prefix information\n"
1380 "IPv6 prefix\n"
1381 "Do not use prefix for autoconfiguration\n")
1382
1383ALIAS (ipv6_nd_prefix,
1384 ipv6_nd_prefix_noval_offlink_cmd,
1385 "ipv6 nd prefix X:X::X:X/M (off-link|)",
1386 "Interface IPv6 config commands\n"
1387 "Neighbor discovery\n"
1388 "Prefix information\n"
1389 "IPv6 prefix\n"
1390 "Do not use prefix for onlink determination\n")
1391
1392ALIAS (ipv6_nd_prefix,
vincent7cee1bb2005-03-25 13:08:53 +00001393 ipv6_nd_prefix_noval_rtaddr_cmd,
1394 "ipv6 nd prefix X:X::X:X/M (router-address|)",
1395 "Interface IPv6 config commands\n"
1396 "Neighbor discovery\n"
1397 "Prefix information\n"
1398 "IPv6 prefix\n"
1399 "Set Router Address flag\n")
1400
1401ALIAS (ipv6_nd_prefix,
hasso3e31cde2004-05-18 11:58:59 +00001402 ipv6_nd_prefix_prefix_cmd,
1403 "ipv6 nd prefix X:X::X:X/M",
1404 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001405 "Neighbor discovery\n"
1406 "Prefix information\n"
1407 "IPv6 prefix\n")
1408
hasso3e31cde2004-05-18 11:58:59 +00001409DEFUN (no_ipv6_nd_prefix,
1410 no_ipv6_nd_prefix_cmd,
1411 "no ipv6 nd prefix IPV6PREFIX",
paul718e3742002-12-13 20:15:29 +00001412 NO_STR
hasso3e31cde2004-05-18 11:58:59 +00001413 "Interface IPv6 config commands\n"
paul718e3742002-12-13 20:15:29 +00001414 "Neighbor discovery\n"
1415 "Prefix information\n"
1416 "IPv6 prefix\n")
1417{
1418 int ret;
1419 struct interface *ifp;
1420 struct zebra_if *zebra_if;
1421 struct rtadv_prefix rp;
1422
1423 ifp = (struct interface *) vty->index;
1424 zebra_if = ifp->info;
1425
Denis Ovsienkoaca43b62012-01-08 18:27:12 +04001426 ret = str2prefix_ipv6 (argv[0], &rp.prefix);
paul718e3742002-12-13 20:15:29 +00001427 if (!ret)
1428 {
1429 vty_out (vty, "Malformed IPv6 prefix%s", VTY_NEWLINE);
1430 return CMD_WARNING;
1431 }
Denis Ovsienko6bb12732012-01-08 17:46:34 +04001432 apply_mask_ipv6 (&rp.prefix); /* RFC4861 4.6.2 */
paul718e3742002-12-13 20:15:29 +00001433
1434 ret = rtadv_prefix_reset (zebra_if, &rp);
1435 if (!ret)
1436 {
1437 vty_out (vty, "Non-exist IPv6 prefix%s", VTY_NEWLINE);
1438 return CMD_WARNING;
1439 }
1440
1441 return CMD_SUCCESS;
1442}
Chris Caputob60668d2009-05-03 04:40:57 +00001443
1444DEFUN (ipv6_nd_router_preference,
1445 ipv6_nd_router_preference_cmd,
1446 "ipv6 nd router-preference (high|medium|low)",
1447 "Interface IPv6 config commands\n"
1448 "Neighbor discovery\n"
1449 "Default router preference\n"
1450 "High default router preference\n"
1451 "Low default router preference\n"
1452 "Medium default router preference (default)\n")
1453{
1454 struct interface *ifp;
1455 struct zebra_if *zif;
1456 int i = 0;
1457
1458 ifp = (struct interface *) vty->index;
1459 zif = ifp->info;
1460
1461 while (0 != rtadv_pref_strs[i])
1462 {
1463 if (strncmp (argv[0], rtadv_pref_strs[i], 1) == 0)
1464 {
1465 zif->rtadv.DefaultPreference = i;
1466 return CMD_SUCCESS;
1467 }
1468 i++;
1469 }
1470
1471 return CMD_ERR_NO_MATCH;
1472}
1473
1474DEFUN (no_ipv6_nd_router_preference,
1475 no_ipv6_nd_router_preference_cmd,
1476 "no ipv6 nd router-preference",
1477 NO_STR
1478 "Interface IPv6 config commands\n"
1479 "Neighbor discovery\n"
1480 "Default router preference\n")
1481{
1482 struct interface *ifp;
1483 struct zebra_if *zif;
1484
1485 ifp = (struct interface *) vty->index;
1486 zif = ifp->info;
1487
1488 zif->rtadv.DefaultPreference = RTADV_PREF_MEDIUM; /* Default per RFC4191. */
1489
1490 return CMD_SUCCESS;
1491}
1492
Denis Ovsienko6ae93c02011-12-27 10:45:36 +04001493DEFUN (ipv6_nd_mtu,
1494 ipv6_nd_mtu_cmd,
1495 "ipv6 nd mtu <1-65535>",
1496 "Interface IPv6 config commands\n"
1497 "Neighbor discovery\n"
1498 "Advertised MTU\n"
1499 "MTU in bytes\n")
1500{
1501 struct interface *ifp = (struct interface *) vty->index;
1502 struct zebra_if *zif = ifp->info;
1503 VTY_GET_INTEGER_RANGE ("MTU", zif->rtadv.AdvLinkMTU, argv[0], 1, 65535);
1504 return CMD_SUCCESS;
1505}
1506
1507DEFUN (no_ipv6_nd_mtu,
1508 no_ipv6_nd_mtu_cmd,
1509 "no ipv6 nd mtu",
1510 NO_STR
1511 "Interface IPv6 config commands\n"
1512 "Neighbor discovery\n"
1513 "Advertised MTU\n")
1514{
1515 struct interface *ifp = (struct interface *) vty->index;
1516 struct zebra_if *zif = ifp->info;
1517 zif->rtadv.AdvLinkMTU = 0;
1518 return CMD_SUCCESS;
1519}
1520
1521ALIAS (no_ipv6_nd_mtu,
1522 no_ipv6_nd_mtu_val_cmd,
1523 "no ipv6 nd mtu <1-65535>",
1524 NO_STR
1525 "Interface IPv6 config commands\n"
1526 "Neighbor discovery\n"
1527 "Advertised MTU\n"
1528 "MTU in bytes\n")
1529
paul718e3742002-12-13 20:15:29 +00001530/* Write configuration about router advertisement. */
1531void
1532rtadv_config_write (struct vty *vty, struct interface *ifp)
1533{
1534 struct zebra_if *zif;
hasso52dc7ee2004-09-23 19:18:23 +00001535 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001536 struct rtadv_prefix *rprefix;
1537 u_char buf[INET6_ADDRSTRLEN];
vincent7cee1bb2005-03-25 13:08:53 +00001538 int interval;
paul718e3742002-12-13 20:15:29 +00001539
1540 if (! rtadv)
1541 return;
1542
1543 zif = ifp->info;
1544
1545 if (! if_is_loopback (ifp))
1546 {
1547 if (zif->rtadv.AdvSendAdvertisements)
1548 vty_out (vty, " no ipv6 nd suppress-ra%s", VTY_NEWLINE);
1549 else
1550 vty_out (vty, " ipv6 nd suppress-ra%s", VTY_NEWLINE);
1551 }
1552
vincent7cee1bb2005-03-25 13:08:53 +00001553
1554 interval = zif->rtadv.MaxRtrAdvInterval;
1555 if (interval % 1000)
1556 vty_out (vty, " ipv6 nd ra-interval msec %d%s", interval,
1557 VTY_NEWLINE);
1558 else
1559 if (interval != RTADV_MAX_RTR_ADV_INTERVAL)
1560 vty_out (vty, " ipv6 nd ra-interval %d%s", interval / 1000,
paul718e3742002-12-13 20:15:29 +00001561 VTY_NEWLINE);
1562
Denis Ovsienko6134b872011-12-27 18:49:15 +04001563 if (zif->rtadv.AdvIntervalOption)
1564 vty_out (vty, " ipv6 nd adv-interval-option%s", VTY_NEWLINE);
1565
Denis Ovsienkod660f692011-12-30 21:55:49 +04001566 if (zif->rtadv.AdvDefaultLifetime != -1)
paul718e3742002-12-13 20:15:29 +00001567 vty_out (vty, " ipv6 nd ra-lifetime %d%s", zif->rtadv.AdvDefaultLifetime,
1568 VTY_NEWLINE);
1569
Denis Ovsienko6134b872011-12-27 18:49:15 +04001570 if (zif->rtadv.HomeAgentPreference)
1571 vty_out (vty, " ipv6 nd home-agent-preference %u%s",
1572 zif->rtadv.HomeAgentPreference, VTY_NEWLINE);
1573
Denis Ovsienkod660f692011-12-30 21:55:49 +04001574 if (zif->rtadv.HomeAgentLifetime != -1)
Denis Ovsienko6134b872011-12-27 18:49:15 +04001575 vty_out (vty, " ipv6 nd home-agent-lifetime %u%s",
1576 zif->rtadv.HomeAgentLifetime, VTY_NEWLINE);
1577
1578 if (zif->rtadv.AdvHomeAgentFlag)
1579 vty_out (vty, " ipv6 nd home-agent-config-flag%s", VTY_NEWLINE);
1580
paul718e3742002-12-13 20:15:29 +00001581 if (zif->rtadv.AdvReachableTime)
1582 vty_out (vty, " ipv6 nd reachable-time %d%s", zif->rtadv.AdvReachableTime,
1583 VTY_NEWLINE);
1584
1585 if (zif->rtadv.AdvManagedFlag)
1586 vty_out (vty, " ipv6 nd managed-config-flag%s", VTY_NEWLINE);
1587
1588 if (zif->rtadv.AdvOtherConfigFlag)
1589 vty_out (vty, " ipv6 nd other-config-flag%s", VTY_NEWLINE);
1590
Chris Caputob60668d2009-05-03 04:40:57 +00001591 if (zif->rtadv.DefaultPreference != RTADV_PREF_MEDIUM)
1592 vty_out (vty, " ipv6 nd router-preference %s%s",
1593 rtadv_pref_strs[zif->rtadv.DefaultPreference],
1594 VTY_NEWLINE);
1595
Denis Ovsienko6ae93c02011-12-27 10:45:36 +04001596 if (zif->rtadv.AdvLinkMTU)
1597 vty_out (vty, " ipv6 nd mtu %d%s", zif->rtadv.AdvLinkMTU, VTY_NEWLINE);
1598
paul1eb8ef22005-04-07 07:30:20 +00001599 for (ALL_LIST_ELEMENTS_RO (zif->rtadv.AdvPrefixList, node, rprefix))
paul718e3742002-12-13 20:15:29 +00001600 {
hasso3e31cde2004-05-18 11:58:59 +00001601 vty_out (vty, " ipv6 nd prefix %s/%d",
Denis Ovsienkoaca43b62012-01-08 18:27:12 +04001602 inet_ntop (AF_INET6, &rprefix->prefix.prefix,
hassoc9e52be2004-09-26 16:09:34 +00001603 (char *) buf, INET6_ADDRSTRLEN),
hasso3e31cde2004-05-18 11:58:59 +00001604 rprefix->prefix.prefixlen);
1605 if ((rprefix->AdvValidLifetime != RTADV_VALID_LIFETIME) ||
1606 (rprefix->AdvPreferredLifetime != RTADV_PREFERRED_LIFETIME))
1607 {
1608 if (rprefix->AdvValidLifetime == UINT32_MAX)
1609 vty_out (vty, " infinite");
1610 else
1611 vty_out (vty, " %u", rprefix->AdvValidLifetime);
1612 if (rprefix->AdvPreferredLifetime == UINT32_MAX)
1613 vty_out (vty, " infinite");
1614 else
1615 vty_out (vty, " %u", rprefix->AdvPreferredLifetime);
1616 }
1617 if (!rprefix->AdvOnLinkFlag)
1618 vty_out (vty, " off-link");
1619 if (!rprefix->AdvAutonomousFlag)
1620 vty_out (vty, " no-autoconfig");
vincent7cee1bb2005-03-25 13:08:53 +00001621 if (rprefix->AdvRouterAddressFlag)
1622 vty_out (vty, " router-address");
paul718e3742002-12-13 20:15:29 +00001623 vty_out (vty, "%s", VTY_NEWLINE);
1624 }
1625}
1626
paul718e3742002-12-13 20:15:29 +00001627
paula1ac18c2005-06-28 17:17:12 +00001628static void
paul718e3742002-12-13 20:15:29 +00001629rtadv_event (enum rtadv_event event, int val)
1630{
1631 switch (event)
1632 {
1633 case RTADV_START:
1634 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001635 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001636 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001637 rtadv->ra_timer = thread_add_event (zebrad.master, rtadv_timer,
1638 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001639 break;
1640 case RTADV_STOP:
1641 if (rtadv->ra_timer)
1642 {
1643 thread_cancel (rtadv->ra_timer);
1644 rtadv->ra_timer = NULL;
1645 }
1646 if (rtadv->ra_read)
1647 {
1648 thread_cancel (rtadv->ra_read);
1649 rtadv->ra_read = NULL;
1650 }
1651 break;
1652 case RTADV_TIMER:
1653 if (! rtadv->ra_timer)
hasso3e31cde2004-05-18 11:58:59 +00001654 rtadv->ra_timer = thread_add_timer (zebrad.master, rtadv_timer, NULL,
1655 val);
paul718e3742002-12-13 20:15:29 +00001656 break;
vincent7cee1bb2005-03-25 13:08:53 +00001657 case RTADV_TIMER_MSEC:
1658 if (! rtadv->ra_timer)
1659 rtadv->ra_timer = thread_add_timer_msec (zebrad.master, rtadv_timer,
1660 NULL, val);
1661 break;
paul718e3742002-12-13 20:15:29 +00001662 case RTADV_READ:
1663 if (! rtadv->ra_read)
paulb21b19c2003-06-15 01:28:29 +00001664 rtadv->ra_read = thread_add_read (zebrad.master, rtadv_read, NULL, val);
paul718e3742002-12-13 20:15:29 +00001665 break;
1666 default:
1667 break;
1668 }
1669 return;
1670}
1671
1672void
paula1ac18c2005-06-28 17:17:12 +00001673rtadv_init (void)
paul718e3742002-12-13 20:15:29 +00001674{
1675 int sock;
1676
1677 sock = rtadv_make_socket ();
1678 if (sock < 0)
1679 return;
1680
1681 rtadv = rtadv_new ();
1682 rtadv->sock = sock;
1683
1684 install_element (INTERFACE_NODE, &ipv6_nd_suppress_ra_cmd);
1685 install_element (INTERFACE_NODE, &no_ipv6_nd_suppress_ra_cmd);
paul718e3742002-12-13 20:15:29 +00001686 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001687 install_element (INTERFACE_NODE, &ipv6_nd_ra_interval_msec_cmd);
paul718e3742002-12-13 20:15:29 +00001688 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_interval_cmd);
1689 install_element (INTERFACE_NODE, &ipv6_nd_ra_lifetime_cmd);
1690 install_element (INTERFACE_NODE, &no_ipv6_nd_ra_lifetime_cmd);
1691 install_element (INTERFACE_NODE, &ipv6_nd_reachable_time_cmd);
1692 install_element (INTERFACE_NODE, &no_ipv6_nd_reachable_time_cmd);
1693 install_element (INTERFACE_NODE, &ipv6_nd_managed_config_flag_cmd);
1694 install_element (INTERFACE_NODE, &no_ipv6_nd_managed_config_flag_cmd);
1695 install_element (INTERFACE_NODE, &ipv6_nd_other_config_flag_cmd);
1696 install_element (INTERFACE_NODE, &no_ipv6_nd_other_config_flag_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001697 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_config_flag_cmd);
1698 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_config_flag_cmd);
1699 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_preference_cmd);
1700 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_preference_cmd);
1701 install_element (INTERFACE_NODE, &ipv6_nd_homeagent_lifetime_cmd);
1702 install_element (INTERFACE_NODE, &no_ipv6_nd_homeagent_lifetime_cmd);
1703 install_element (INTERFACE_NODE, &ipv6_nd_adv_interval_config_option_cmd);
1704 install_element (INTERFACE_NODE, &no_ipv6_nd_adv_interval_config_option_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001705 install_element (INTERFACE_NODE, &ipv6_nd_prefix_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001706 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_rtaddr_cmd);
1707 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_nortaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001708 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rev_cmd);
1709 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_noauto_cmd);
1710 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001711 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001712 install_element (INTERFACE_NODE, &ipv6_nd_prefix_val_cmd);
1713 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_cmd);
1714 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rev_cmd);
1715 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_noauto_cmd);
1716 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_offlink_cmd);
vincent7cee1bb2005-03-25 13:08:53 +00001717 install_element (INTERFACE_NODE, &ipv6_nd_prefix_noval_rtaddr_cmd);
hasso3e31cde2004-05-18 11:58:59 +00001718 install_element (INTERFACE_NODE, &ipv6_nd_prefix_prefix_cmd);
1719 install_element (INTERFACE_NODE, &no_ipv6_nd_prefix_cmd);
Chris Caputob60668d2009-05-03 04:40:57 +00001720 install_element (INTERFACE_NODE, &ipv6_nd_router_preference_cmd);
1721 install_element (INTERFACE_NODE, &no_ipv6_nd_router_preference_cmd);
Denis Ovsienko6ae93c02011-12-27 10:45:36 +04001722 install_element (INTERFACE_NODE, &ipv6_nd_mtu_cmd);
1723 install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_cmd);
1724 install_element (INTERFACE_NODE, &no_ipv6_nd_mtu_val_cmd);
paul718e3742002-12-13 20:15:29 +00001725}
1726
paula1ac18c2005-06-28 17:17:12 +00001727static int
paul718e3742002-12-13 20:15:29 +00001728if_join_all_router (int sock, struct interface *ifp)
1729{
1730 int ret;
1731
1732 struct ipv6_mreq mreq;
1733
1734 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1735 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1736 mreq.ipv6mr_interface = ifp->ifindex;
1737
1738 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
1739 (char *) &mreq, sizeof mreq);
1740 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001741 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001742
1743 zlog_info ("rtadv: %s join to all-routers multicast group", ifp->name);
1744
1745 return 0;
1746}
1747
paula1ac18c2005-06-28 17:17:12 +00001748static int
paul718e3742002-12-13 20:15:29 +00001749if_leave_all_router (int sock, struct interface *ifp)
1750{
1751 int ret;
1752
1753 struct ipv6_mreq mreq;
1754
1755 memset (&mreq, 0, sizeof (struct ipv6_mreq));
1756 inet_pton (AF_INET6, ALLROUTER, &mreq.ipv6mr_multiaddr);
1757 mreq.ipv6mr_interface = ifp->ifindex;
1758
1759 ret = setsockopt (sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
1760 (char *) &mreq, sizeof mreq);
1761 if (ret < 0)
ajs6099b3b2004-11-20 02:06:59 +00001762 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001763
1764 zlog_info ("rtadv: %s leave from all-routers multicast group", ifp->name);
1765
1766 return 0;
1767}
1768
1769#else
1770void
paula1ac18c2005-06-28 17:17:12 +00001771rtadv_init (void)
paul718e3742002-12-13 20:15:29 +00001772{
1773 /* Empty.*/;
1774}
1775#endif /* RTADV && HAVE_IPV6 */