blob: 6e32d83c5d0a7df138a89977d67383effb21dff8 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* RIPng daemon
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2, or (at your option) any
9 * later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GNU Zebra; see the file COPYING. If not, write to the Free
18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22#include <zebra.h>
23
paul718e3742002-12-13 20:15:29 +000024#include "prefix.h"
25#include "filter.h"
26#include "log.h"
27#include "thread.h"
28#include "memory.h"
29#include "if.h"
30#include "stream.h"
31#include "table.h"
32#include "command.h"
33#include "sockopt.h"
34#include "distribute.h"
35#include "plist.h"
36#include "routemap.h"
hasso0750d212003-05-24 21:41:49 +000037#include "if_rmap.h"
paul27d47aa2003-11-17 09:04:53 +000038#include "privs.h"
paul718e3742002-12-13 20:15:29 +000039
40#include "ripngd/ripngd.h"
41#include "ripngd/ripng_route.h"
42#include "ripngd/ripng_debug.h"
hassoa94434b2003-05-25 17:10:12 +000043#include "ripngd/ripng_nexthop.h"
paul718e3742002-12-13 20:15:29 +000044
45/* RIPng structure which includes many parameters related to RIPng
46 protocol. If ripng couldn't active or ripng doesn't configured,
47 ripng->fd must be negative value. */
48struct ripng *ripng = NULL;
49
50enum
51{
52 ripng_all_route,
53 ripng_changed_route,
paul718e3742002-12-13 20:15:29 +000054};
55
paul27d47aa2003-11-17 09:04:53 +000056extern struct zebra_privs_t ripngd_privs;
57
paul718e3742002-12-13 20:15:29 +000058/* Prototypes. */
59void
hassoa94434b2003-05-25 17:10:12 +000060ripng_output_process (struct interface *, struct sockaddr_in6 *, int);
paul718e3742002-12-13 20:15:29 +000061
62int
63ripng_triggered_update (struct thread *);
64
65/* RIPng next hop specification. */
66struct ripng_nexthop
67{
68 enum ripng_nexthop_type
69 {
70 RIPNG_NEXTHOP_UNSPEC,
71 RIPNG_NEXTHOP_ADDRESS
72 } flag;
73 struct in6_addr address;
74};
paul718e3742002-12-13 20:15:29 +000075
Paul Jakma6ac29a52008-08-15 13:45:30 +010076static int
hassoa94434b2003-05-25 17:10:12 +000077ripng_route_rte (struct ripng_info *rinfo)
78{
79 return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE);
80}
81
paul718e3742002-12-13 20:15:29 +000082/* Allocate new ripng information. */
83struct ripng_info *
84ripng_info_new ()
85{
86 struct ripng_info *new;
87
88 new = XCALLOC (MTYPE_RIPNG_ROUTE, sizeof (struct ripng_info));
89 return new;
90}
91
92/* Free ripng information. */
93void
94ripng_info_free (struct ripng_info *rinfo)
95{
96 XFREE (MTYPE_RIPNG_ROUTE, rinfo);
97}
98
paul718e3742002-12-13 20:15:29 +000099/* Create ripng socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100100static int
paul718e3742002-12-13 20:15:29 +0000101ripng_make_socket (void)
102{
103 int ret;
104 int sock;
105 struct sockaddr_in6 ripaddr;
106
107 sock = socket (AF_INET6, SOCK_DGRAM, 0);
108 if (sock < 0)
109 {
110 zlog (NULL, LOG_ERR, "Can't make ripng socket");
111 return sock;
112 }
113
114 ret = setsockopt_so_recvbuf (sock, 8096);
115 if (ret < 0)
116 return ret;
117 ret = setsockopt_ipv6_pktinfo (sock, 1);
118 if (ret < 0)
119 return ret;
120 ret = setsockopt_ipv6_multicast_hops (sock, 255);
121 if (ret < 0)
122 return ret;
123 ret = setsockopt_ipv6_multicast_loop (sock, 0);
124 if (ret < 0)
125 return ret;
126 ret = setsockopt_ipv6_hoplimit (sock, 1);
127 if (ret < 0)
128 return ret;
129
130 memset (&ripaddr, 0, sizeof (ripaddr));
131 ripaddr.sin6_family = AF_INET6;
132#ifdef SIN6_LEN
133 ripaddr.sin6_len = sizeof (struct sockaddr_in6);
134#endif /* SIN6_LEN */
135 ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
136
paul27d47aa2003-11-17 09:04:53 +0000137 if (ripngd_privs.change (ZPRIVS_RAISE))
138 zlog_err ("ripng_make_socket: could not raise privs");
139
paul718e3742002-12-13 20:15:29 +0000140 ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
141 if (ret < 0)
paul27d47aa2003-11-17 09:04:53 +0000142 {
ajs6099b3b2004-11-20 02:06:59 +0000143 zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno));
paul27d47aa2003-11-17 09:04:53 +0000144 if (ripngd_privs.change (ZPRIVS_LOWER))
145 zlog_err ("ripng_make_socket: could not lower privs");
146 return ret;
147 }
148 if (ripngd_privs.change (ZPRIVS_LOWER))
149 zlog_err ("ripng_make_socket: could not lower privs");
paul718e3742002-12-13 20:15:29 +0000150 return sock;
151}
152
153/* Send RIPng packet. */
154int
155ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to,
156 struct interface *ifp)
157{
158 int ret;
159 struct msghdr msg;
160 struct iovec iov;
161 struct cmsghdr *cmsgptr;
162 char adata [256];
163 struct in6_pktinfo *pkt;
164 struct sockaddr_in6 addr;
165
hassoa94434b2003-05-25 17:10:12 +0000166 if (IS_RIPNG_DEBUG_SEND) {
167 if (to)
hasso3a2ce6a2005-04-08 01:30:51 +0000168 zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr));
ajsc6106812004-12-08 19:51:16 +0000169 zlog_debug (" send interface %s", ifp->name);
170 zlog_debug (" send packet size %d", bufsize);
hassoa94434b2003-05-25 17:10:12 +0000171 }
paul718e3742002-12-13 20:15:29 +0000172
173 memset (&addr, 0, sizeof (struct sockaddr_in6));
174 addr.sin6_family = AF_INET6;
175#ifdef SIN6_LEN
176 addr.sin6_len = sizeof (struct sockaddr_in6);
177#endif /* SIN6_LEN */
178 addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
179
180 /* When destination is specified. */
181 if (to != NULL)
182 {
183 addr.sin6_addr = to->sin6_addr;
184 addr.sin6_port = to->sin6_port;
185 }
186 else
187 {
188 inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
189 addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
190 }
191
192 msg.msg_name = (void *) &addr;
193 msg.msg_namelen = sizeof (struct sockaddr_in6);
194 msg.msg_iov = &iov;
195 msg.msg_iovlen = 1;
196 msg.msg_control = (void *) adata;
197 msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
198
199 iov.iov_base = buf;
200 iov.iov_len = bufsize;
201
202 cmsgptr = (struct cmsghdr *)adata;
203 cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
204 cmsgptr->cmsg_level = IPPROTO_IPV6;
205 cmsgptr->cmsg_type = IPV6_PKTINFO;
206
207 pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
208 memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
209 pkt->ipi6_ifindex = ifp->ifindex;
210
211 ret = sendmsg (ripng->sock, &msg, 0);
212
hassoa94434b2003-05-25 17:10:12 +0000213 if (ret < 0) {
214 if (to)
215 zlog_err ("RIPng send fail on %s to %s: %s", ifp->name,
hasso3a2ce6a2005-04-08 01:30:51 +0000216 inet6_ntoa (to->sin6_addr), safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000217 else
ajs6099b3b2004-11-20 02:06:59 +0000218 zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno));
hassoa94434b2003-05-25 17:10:12 +0000219 }
paul718e3742002-12-13 20:15:29 +0000220
221 return ret;
222}
223
224/* Receive UDP RIPng packet from socket. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100225static int
paul718e3742002-12-13 20:15:29 +0000226ripng_recv_packet (int sock, u_char *buf, int bufsize,
227 struct sockaddr_in6 *from, unsigned int *ifindex,
228 int *hoplimit)
229{
230 int ret;
231 struct msghdr msg;
232 struct iovec iov;
233 struct cmsghdr *cmsgptr;
234 struct in6_addr dst;
235
236 /* Ancillary data. This store cmsghdr and in6_pktinfo. But at this
237 point I can't determine size of cmsghdr */
238 char adata[1024];
239
240 /* Fill in message and iovec. */
241 msg.msg_name = (void *) from;
242 msg.msg_namelen = sizeof (struct sockaddr_in6);
243 msg.msg_iov = &iov;
244 msg.msg_iovlen = 1;
245 msg.msg_control = (void *) adata;
246 msg.msg_controllen = sizeof adata;
247 iov.iov_base = buf;
248 iov.iov_len = bufsize;
249
250 /* If recvmsg fail return minus value. */
251 ret = recvmsg (sock, &msg, 0);
252 if (ret < 0)
253 return ret;
254
ajsb99760a2005-01-04 16:24:43 +0000255 for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
paul718e3742002-12-13 20:15:29 +0000256 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr))
257 {
258 /* I want interface index which this packet comes from. */
259 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
260 cmsgptr->cmsg_type == IPV6_PKTINFO)
261 {
262 struct in6_pktinfo *ptr;
263
264 ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
265 *ifindex = ptr->ipi6_ifindex;
266 dst = ptr->ipi6_addr;
267
268 if (*ifindex == 0)
269 zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
270 }
271
272 /* Incoming packet's multicast hop limit. */
273 if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
274 cmsgptr->cmsg_type == IPV6_HOPLIMIT)
Stephen Hemminger5eb9d112009-12-10 15:52:33 +0300275 {
276 int *phoplimit = (int *) CMSG_DATA (cmsgptr);
277 *hoplimit = *phoplimit;
278 }
paul718e3742002-12-13 20:15:29 +0000279 }
280
281 /* Hoplimit check shold be done when destination address is
282 multicast address. */
283 if (! IN6_IS_ADDR_MULTICAST (&dst))
284 *hoplimit = -1;
285
286 return ret;
287}
288
289/* Dump rip packet */
290void
hasso7a1d5832004-10-08 06:32:23 +0000291ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv)
paul718e3742002-12-13 20:15:29 +0000292{
293 caddr_t lim;
294 struct rte *rte;
hasso7a1d5832004-10-08 06:32:23 +0000295 const char *command_str;
paul718e3742002-12-13 20:15:29 +0000296
297 /* Set command string. */
298 if (packet->command == RIPNG_REQUEST)
299 command_str = "request";
300 else if (packet->command == RIPNG_RESPONSE)
301 command_str = "response";
302 else
303 command_str = "unknown";
304
305 /* Dump packet header. */
ajsc6106812004-12-08 19:51:16 +0000306 zlog_debug ("%s %s version %d packet size %d",
paul718e3742002-12-13 20:15:29 +0000307 sndrcv, command_str, packet->version, size);
308
309 /* Dump each routing table entry. */
310 rte = packet->rte;
311
312 for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
313 {
314 if (rte->metric == RIPNG_METRIC_NEXTHOP)
hasso3a2ce6a2005-04-08 01:30:51 +0000315 zlog_debug (" nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000316 else
ajsc6106812004-12-08 19:51:16 +0000317 zlog_debug (" %s/%d metric %d tag %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000318 inet6_ntoa (rte->addr), rte->prefixlen,
paul718e3742002-12-13 20:15:29 +0000319 rte->metric, ntohs (rte->tag));
320 }
321}
322
323/* RIPng next hop address RTE (Route Table Entry). */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100324static void
paul718e3742002-12-13 20:15:29 +0000325ripng_nexthop_rte (struct rte *rte,
326 struct sockaddr_in6 *from,
327 struct ripng_nexthop *nexthop)
328{
329 char buf[INET6_BUFSIZ];
330
331 /* Logging before checking RTE. */
332 if (IS_RIPNG_DEBUG_RECV)
ajsc6106812004-12-08 19:51:16 +0000333 zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d",
hasso3a2ce6a2005-04-08 01:30:51 +0000334 inet6_ntoa (rte->addr), ntohs (rte->tag), rte->prefixlen);
paul718e3742002-12-13 20:15:29 +0000335
336 /* RFC2080 2.1.1 Next Hop:
337 The route tag and prefix length in the next hop RTE must be
338 set to zero on sending and ignored on receiption. */
339 if (ntohs (rte->tag) != 0)
340 zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000341 ntohs (rte->tag), inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000342
343 if (rte->prefixlen != 0)
344 zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000345 rte->prefixlen, inet6_ntoa (from->sin6_addr));
paul718e3742002-12-13 20:15:29 +0000346
347 /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
348 next hop RTE indicates that the next hop address should be the
349 originator of the RIPng advertisement. An address specified as a
350 next hop must be a link-local address. */
351 if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
352 {
353 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
354 memset (&nexthop->address, 0, sizeof (struct in6_addr));
355 return;
356 }
357
358 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
359 {
360 nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
361 IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
362 return;
363 }
364
365 /* The purpose of the next hop RTE is to eliminate packets being
366 routed through extra hops in the system. It is particularly useful
367 when RIPng is not being run on all of the routers on a network.
368 Note that next hop RTE is "advisory". That is, if the provided
369 information is ignored, a possibly sub-optimal, but absolutely
370 valid, route may be taken. If the received next hop address is not
371 a link-local address, it should be treated as 0:0:0:0:0:0:0:0. */
372 zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
hasso3a2ce6a2005-04-08 01:30:51 +0000373 inet6_ntoa (rte->addr),
paul718e3742002-12-13 20:15:29 +0000374 inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
375
376 nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
377 memset (&nexthop->address, 0, sizeof (struct in6_addr));
378
379 return;
380}
381
382/* If ifp has same link-local address then return 1. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100383static int
paul718e3742002-12-13 20:15:29 +0000384ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
385{
paul1eb8ef22005-04-07 07:30:20 +0000386 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000387 struct connected *connected;
388 struct prefix *p;
389
paul1eb8ef22005-04-07 07:30:20 +0000390 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
391 {
392 p = connected->address;
paul718e3742002-12-13 20:15:29 +0000393
paul1eb8ef22005-04-07 07:30:20 +0000394 if (p->family == AF_INET6 &&
395 IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
396 IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
397 return 1;
398 }
paul718e3742002-12-13 20:15:29 +0000399 return 0;
400}
401
402/* RIPng route garbage collect timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100403static int
paul718e3742002-12-13 20:15:29 +0000404ripng_garbage_collect (struct thread *t)
405{
406 struct ripng_info *rinfo;
407 struct route_node *rp;
408
409 rinfo = THREAD_ARG (t);
410 rinfo->t_garbage_collect = NULL;
411
412 /* Off timeout timer. */
413 RIPNG_TIMER_OFF (rinfo->t_timeout);
414
415 /* Get route_node pointer. */
416 rp = rinfo->rp;
417
paul718e3742002-12-13 20:15:29 +0000418 /* Unlock route_node. */
419 rp->info = NULL;
420 route_unlock_node (rp);
421
422 /* Free RIPng routing information. */
423 ripng_info_free (rinfo);
424
425 return 0;
426}
427
428/* Timeout RIPng routes. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100429static int
paul718e3742002-12-13 20:15:29 +0000430ripng_timeout (struct thread *t)
431{
432 struct ripng_info *rinfo;
433 struct route_node *rp;
434
435 rinfo = THREAD_ARG (t);
436 rinfo->t_timeout = NULL;
437
438 /* Get route_node pointer. */
439 rp = rinfo->rp;
440
441 /* - The garbage-collection timer is set for 120 seconds. */
442 RIPNG_TIMER_ON (rinfo->t_garbage_collect, ripng_garbage_collect,
443 ripng->garbage_time);
444
hassoa94434b2003-05-25 17:10:12 +0000445 /* Delete this route from the kernel. */
446 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
447 rinfo->ifindex);
paul718e3742002-12-13 20:15:29 +0000448 /* - The metric for the route is set to 16 (infinity). This causes
449 the route to be removed from service. */
450 rinfo->metric = RIPNG_METRIC_INFINITY;
hassoa94434b2003-05-25 17:10:12 +0000451 rinfo->flags &= ~RIPNG_RTF_FIB;
452
453 /* Aggregate count decrement. */
454 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +0000455
456 /* - The route change flag is to indicate that this entry has been
457 changed. */
458 rinfo->flags |= RIPNG_RTF_CHANGED;
459
460 /* - The output process is signalled to trigger a response. */
461 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
462
463 return 0;
464}
465
Paul Jakma6ac29a52008-08-15 13:45:30 +0100466static void
paul718e3742002-12-13 20:15:29 +0000467ripng_timeout_update (struct ripng_info *rinfo)
468{
469 if (rinfo->metric != RIPNG_METRIC_INFINITY)
470 {
471 RIPNG_TIMER_OFF (rinfo->t_timeout);
472 RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
473 }
474}
475
Paul Jakma6ac29a52008-08-15 13:45:30 +0100476static int
hassoa94434b2003-05-25 17:10:12 +0000477ripng_incoming_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
478{
479 struct distribute *dist;
480 struct access_list *alist;
481 struct prefix_list *plist;
482
483 /* Input distribute-list filtering. */
484 if (ri->list[RIPNG_FILTER_IN])
485 {
486 if (access_list_apply (ri->list[RIPNG_FILTER_IN],
487 (struct prefix *) p) == FILTER_DENY)
488 {
489 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000490 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000491 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000492 return -1;
493 }
494 }
495 if (ri->prefix[RIPNG_FILTER_IN])
496 {
497 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_IN],
498 (struct prefix *) p) == PREFIX_DENY)
499 {
500 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000501 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000502 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000503 return -1;
504 }
505 }
506
507 /* All interface filter check. */
508 dist = distribute_lookup (NULL);
509 if (dist)
510 {
511 if (dist->list[DISTRIBUTE_IN])
512 {
513 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
514
515 if (alist)
516 {
517 if (access_list_apply (alist,
518 (struct prefix *) p) == FILTER_DENY)
519 {
520 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000521 zlog_debug ("%s/%d filtered by distribute in",
hasso3a2ce6a2005-04-08 01:30:51 +0000522 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000523 return -1;
524 }
525 }
526 }
527 if (dist->prefix[DISTRIBUTE_IN])
528 {
529 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
530
531 if (plist)
532 {
533 if (prefix_list_apply (plist,
534 (struct prefix *) p) == PREFIX_DENY)
535 {
536 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000537 zlog_debug ("%s/%d filtered by prefix-list in",
hasso3a2ce6a2005-04-08 01:30:51 +0000538 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000539 return -1;
540 }
541 }
542 }
543 }
544 return 0;
545}
546
Paul Jakma6ac29a52008-08-15 13:45:30 +0100547static int
hassoa94434b2003-05-25 17:10:12 +0000548ripng_outgoing_filter (struct prefix_ipv6 *p, struct ripng_interface *ri)
549{
550 struct distribute *dist;
551 struct access_list *alist;
552 struct prefix_list *plist;
553
554 if (ri->list[RIPNG_FILTER_OUT])
555 {
556 if (access_list_apply (ri->list[RIPNG_FILTER_OUT],
557 (struct prefix *) p) == FILTER_DENY)
558 {
559 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000560 zlog_debug ("%s/%d is filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000561 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000562 return -1;
563 }
564 }
565 if (ri->prefix[RIPNG_FILTER_OUT])
566 {
567 if (prefix_list_apply (ri->prefix[RIPNG_FILTER_OUT],
568 (struct prefix *) p) == PREFIX_DENY)
569 {
570 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000571 zlog_debug ("%s/%d is filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000572 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000573 return -1;
574 }
575 }
576
577 /* All interface filter check. */
578 dist = distribute_lookup (NULL);
579 if (dist)
580 {
581 if (dist->list[DISTRIBUTE_OUT])
582 {
583 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
584
585 if (alist)
586 {
587 if (access_list_apply (alist,
588 (struct prefix *) p) == FILTER_DENY)
589 {
590 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000591 zlog_debug ("%s/%d filtered by distribute out",
hasso3a2ce6a2005-04-08 01:30:51 +0000592 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000593 return -1;
594 }
595 }
596 }
597 if (dist->prefix[DISTRIBUTE_OUT])
598 {
599 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
600
601 if (plist)
602 {
603 if (prefix_list_apply (plist,
604 (struct prefix *) p) == PREFIX_DENY)
605 {
606 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000607 zlog_debug ("%s/%d filtered by prefix-list out",
hasso3a2ce6a2005-04-08 01:30:51 +0000608 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +0000609 return -1;
610 }
611 }
612 }
613 }
614 return 0;
615}
616
paul718e3742002-12-13 20:15:29 +0000617/* Process RIPng route according to RFC2080. */
Paul Jakma6ac29a52008-08-15 13:45:30 +0100618static void
paul718e3742002-12-13 20:15:29 +0000619ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
620 struct ripng_nexthop *ripng_nexthop,
621 struct interface *ifp)
622{
hassoa94434b2003-05-25 17:10:12 +0000623 int ret;
paul718e3742002-12-13 20:15:29 +0000624 struct prefix_ipv6 p;
625 struct route_node *rp;
626 struct ripng_info *rinfo;
627 struct ripng_interface *ri;
628 struct in6_addr *nexthop;
629 u_char oldmetric;
630 int same = 0;
631
632 /* Make prefix structure. */
633 memset (&p, 0, sizeof (struct prefix_ipv6));
634 p.family = AF_INET6;
635 /* p.prefix = rte->addr; */
636 IPV6_ADDR_COPY (&p.prefix, &rte->addr);
637 p.prefixlen = rte->prefixlen;
638
639 /* Make sure mask is applied. */
640 /* XXX We have to check the prefix is valid or not before call
641 apply_mask_ipv6. */
642 apply_mask_ipv6 (&p);
643
644 /* Apply input filters. */
645 ri = ifp->info;
646
hassoa94434b2003-05-25 17:10:12 +0000647 ret = ripng_incoming_filter (&p, ri);
648 if (ret < 0)
649 return;
paul718e3742002-12-13 20:15:29 +0000650
651 /* Modify entry. */
652 if (ri->routemap[RIPNG_FILTER_IN])
653 {
654 int ret;
655 struct ripng_info newinfo;
656
paul41ce9262003-04-19 15:54:03 +0000657 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +0000658 newinfo.type = ZEBRA_ROUTE_RIPNG;
659 newinfo.sub_type = RIPNG_ROUTE_RTE;
660 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
661 newinfo.nexthop = ripng_nexthop->address;
662 else
663 newinfo.nexthop = from->sin6_addr;
664 newinfo.from = from->sin6_addr;
665 newinfo.ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000666 newinfo.metric = rte->metric;
hassoa94434b2003-05-25 17:10:12 +0000667 newinfo.metric_out = rte->metric; /* XXX */
668 newinfo.tag = ntohs(rte->tag); /* XXX */
paul718e3742002-12-13 20:15:29 +0000669
670 ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN],
671 (struct prefix *)&p, RMAP_RIPNG, &newinfo);
672
673 if (ret == RMAP_DENYMATCH)
674 {
675 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +0000676 zlog_debug ("RIPng %s/%d is filtered by route-map in",
hasso3a2ce6a2005-04-08 01:30:51 +0000677 inet6_ntoa (p.prefix), p.prefixlen);
paul718e3742002-12-13 20:15:29 +0000678 return;
679 }
680
hassoa94434b2003-05-25 17:10:12 +0000681 /* Get back the object */
682 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
683 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
684 /* the nexthop get changed by the routemap */
685 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
686 ripng_nexthop->address = newinfo.nexthop;
687 else
688 ripng_nexthop->address = in6addr_any;
689 }
690 } else {
691 if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
692 /* the nexthop get changed by the routemap */
693 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
694 ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
695 ripng_nexthop->address = newinfo.nexthop;
696 }
697 }
698 }
699 rte->tag = htons(newinfo.tag_out); /* XXX */
700 rte->metric = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
paul718e3742002-12-13 20:15:29 +0000701 }
702
hassoa94434b2003-05-25 17:10:12 +0000703 /* Once the entry has been validated, update the metric by
704 * adding the cost of the network on wich the message
705 * arrived. If the result is greater than infinity, use infinity
706 * (RFC2453 Sec. 3.9.2)
707 **/
708
709 /* Zebra ripngd can handle offset-list in. */
710 ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
711
712 /* If offset-list does not modify the metric use interface's
713 * one. */
714 if (! ret)
715 rte->metric += ifp->metric;
716
717 if (rte->metric > RIPNG_METRIC_INFINITY)
718 rte->metric = RIPNG_METRIC_INFINITY;
719
paul718e3742002-12-13 20:15:29 +0000720 /* Set nexthop pointer. */
721 if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
722 nexthop = &ripng_nexthop->address;
723 else
724 nexthop = &from->sin6_addr;
725
726 /* Lookup RIPng routing table. */
727 rp = route_node_get (ripng->table, (struct prefix *) &p);
728
hassoa94434b2003-05-25 17:10:12 +0000729 /* Sanity check */
730 rinfo = rp->info;
731 if (rinfo)
732 {
733 /* Redistributed route check. */
734 if (rinfo->type != ZEBRA_ROUTE_RIPNG
735 && rinfo->metric != RIPNG_METRIC_INFINITY)
736 return;
737
738 /* Local static route. */
739 if (rinfo->type == ZEBRA_ROUTE_RIPNG
740 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
741 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
742 && rinfo->metric != RIPNG_METRIC_INFINITY)
743 return;
744 }
745
paul718e3742002-12-13 20:15:29 +0000746 if (rp->info == NULL)
747 {
748 /* Now, check to see whether there is already an explicit route
749 for the destination prefix. If there is no such route, add
750 this route to the routing table, unless the metric is
751 infinity (there is no point in adding a route which
752 unusable). */
753 if (rte->metric != RIPNG_METRIC_INFINITY)
754 {
755 rinfo = ripng_info_new ();
756
757 /* - Setting the destination prefix and length to those in
758 the RTE. */
759 rp->info = rinfo;
760 rinfo->rp = rp;
761
762 /* - Setting the metric to the newly calculated metric (as
763 described above). */
764 rinfo->metric = rte->metric;
765 rinfo->tag = ntohs (rte->tag);
766
767 /* - Set the next hop address to be the address of the router
768 from which the datagram came or the next hop address
769 specified by a next hop RTE. */
770 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
771 IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
772 rinfo->ifindex = ifp->ifindex;
773
774 /* - Initialize the timeout for the route. If the
775 garbage-collection timer is running for this route, stop it. */
776 ripng_timeout_update (rinfo);
777
778 /* - Set the route change flag. */
779 rinfo->flags |= RIPNG_RTF_CHANGED;
780
781 /* - Signal the output process to trigger an update (see section
782 2.5). */
783 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
784
785 /* Finally, route goes into the kernel. */
786 rinfo->type = ZEBRA_ROUTE_RIPNG;
787 rinfo->sub_type = RIPNG_ROUTE_RTE;
788
hassodeba3552005-08-27 06:19:39 +0000789 ripng_zebra_ipv6_add (&p, &rinfo->nexthop, rinfo->ifindex,
790 rinfo->metric);
paul718e3742002-12-13 20:15:29 +0000791 rinfo->flags |= RIPNG_RTF_FIB;
792
793 /* Aggregate check. */
794 ripng_aggregate_increment (rp, rinfo);
795 }
796 }
797 else
798 {
799 rinfo = rp->info;
800
801 /* If there is an existing route, compare the next hop address
802 to the address of the router from which the datagram came.
803 If this datagram is from the same router as the existing
804 route, reinitialize the timeout. */
805 same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr)
806 && (rinfo->ifindex == ifp->ifindex));
807
808 if (same)
809 ripng_timeout_update (rinfo);
810
811 /* Next, compare the metrics. If the datagram is from the same
812 router as the existing route, and the new metric is different
813 than the old one; or, if the new metric is lower than the old
814 one; do the following actions: */
815 if ((same && rinfo->metric != rte->metric) ||
816 rte->metric < rinfo->metric)
817 {
818 /* - Adopt the route from the datagram. That is, put the
819 new metric in, and adjust the next hop address (if
820 necessary). */
821 oldmetric = rinfo->metric;
822 rinfo->metric = rte->metric;
823 rinfo->tag = ntohs (rte->tag);
hassoa94434b2003-05-25 17:10:12 +0000824 IPV6_ADDR_COPY (&rinfo->from, &from->sin6_addr);
825 rinfo->ifindex = ifp->ifindex;
paul718e3742002-12-13 20:15:29 +0000826
hassoa94434b2003-05-25 17:10:12 +0000827 /* Should a new route to this network be established
828 while the garbage-collection timer is running, the
829 new route will replace the one that is about to be
830 deleted. In this case the garbage-collection timer
831 must be cleared. */
832
833 if (oldmetric == RIPNG_METRIC_INFINITY &&
834 rinfo->metric < RIPNG_METRIC_INFINITY)
835 {
836 rinfo->type = ZEBRA_ROUTE_RIPNG;
837 rinfo->sub_type = RIPNG_ROUTE_RTE;
838
839 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
840
841 if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
hassodeba3552005-08-27 06:19:39 +0000842 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
hassoa94434b2003-05-25 17:10:12 +0000843
hassodeba3552005-08-27 06:19:39 +0000844 ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
hassoa94434b2003-05-25 17:10:12 +0000845 rinfo->flags |= RIPNG_RTF_FIB;
846
847 /* The aggregation counter needs to be updated because
848 the prefixes, which are into the gc, have been
849 removed from the aggregator (see ripng_timout). */
850 ripng_aggregate_increment (rp, rinfo);
851 }
852
853 /* Update nexthop and/or metric value. */
854 if (oldmetric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +0000855 {
856 ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
hassodeba3552005-08-27 06:19:39 +0000857 ripng_zebra_ipv6_add (&p, nexthop, ifp->ifindex, rinfo->metric);
paul718e3742002-12-13 20:15:29 +0000858 rinfo->flags |= RIPNG_RTF_FIB;
859
hassoa94434b2003-05-25 17:10:12 +0000860 if (! IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
861 IPV6_ADDR_COPY (&rinfo->nexthop, nexthop);
paul718e3742002-12-13 20:15:29 +0000862 }
paul718e3742002-12-13 20:15:29 +0000863
864 /* - Set the route change flag and signal the output process
865 to trigger an update. */
866 rinfo->flags |= RIPNG_RTF_CHANGED;
867 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
868
869 /* - If the new metric is infinity, start the deletion
870 process (described above); */
871 if (rinfo->metric == RIPNG_METRIC_INFINITY)
872 {
873 /* If the new metric is infinity, the deletion process
874 begins for the route, which is no longer used for
875 routing packets. Note that the deletion process is
876 started only when the metric is first set to
877 infinity. If the metric was already infinity, then a
878 new deletion process is not started. */
879 if (oldmetric != RIPNG_METRIC_INFINITY)
880 {
881 /* - The garbage-collection timer is set for 120 seconds. */
882 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
883 ripng_garbage_collect, ripng->garbage_time);
884 RIPNG_TIMER_OFF (rinfo->t_timeout);
885
886 /* - The metric for the route is set to 16
887 (infinity). This causes the route to be removed
888 from service.*/
hassoa94434b2003-05-25 17:10:12 +0000889 ripng_zebra_ipv6_delete (&p, &rinfo->nexthop, rinfo->ifindex);
890 rinfo->flags &= ~RIPNG_RTF_FIB;
891
892 /* Aggregate count decrement. */
893 ripng_aggregate_decrement (rp, rinfo);
894
paul718e3742002-12-13 20:15:29 +0000895 /* - The route change flag is to indicate that this
896 entry has been changed. */
897 /* - The output process is signalled to trigger a
898 response. */
899 ; /* Above processes are already done previously. */
900 }
901 }
902 else
903 {
904 /* otherwise, re-initialize the timeout. */
905 ripng_timeout_update (rinfo);
paul718e3742002-12-13 20:15:29 +0000906 }
907 }
908 /* Unlock tempolary lock of the route. */
909 route_unlock_node (rp);
910 }
911}
912
913/* Add redistributed route to RIPng table. */
914void
915ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +0000916 unsigned int ifindex, struct in6_addr *nexthop)
paul718e3742002-12-13 20:15:29 +0000917{
918 struct route_node *rp;
919 struct ripng_info *rinfo;
920
921 /* Redistribute route */
922 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
923 return;
924 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
925 return;
hassoa94434b2003-05-25 17:10:12 +0000926#if defined (MUSICA) || defined (LINUX)
927 /* XXX As long as the RIPng redistribution is applied to all the connected
928 * routes, one needs to filter the ::/96 prefixes.
929 * However it could be a wanted case, it will be removed soon.
930 */
931 if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
932 (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
933 return;
934#endif /* MUSICA or LINUX */
paul718e3742002-12-13 20:15:29 +0000935
936 rp = route_node_get (ripng->table, (struct prefix *) p);
937 rinfo = rp->info;
938
939 if (rinfo)
940 {
hassoa94434b2003-05-25 17:10:12 +0000941 if (rinfo->type == ZEBRA_ROUTE_CONNECT
942 && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
943 && rinfo->metric != RIPNG_METRIC_INFINITY) {
944 route_unlock_node (rp);
945 return;
946 }
947
948 /* Manually configured RIPng route check.
949 * They have the precedence on all the other entries.
950 **/
951 if (rinfo->type == ZEBRA_ROUTE_RIPNG
952 && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
953 (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
954 if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
955 (sub_type != RIPNG_ROUTE_DEFAULT))) {
956 route_unlock_node (rp);
957 return;
958 }
959 }
960
paul718e3742002-12-13 20:15:29 +0000961 RIPNG_TIMER_OFF (rinfo->t_timeout);
962 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
hassoa94434b2003-05-25 17:10:12 +0000963
964 /* Tells the other daemons about the deletion of
965 * this RIPng route
966 **/
967 if (ripng_route_rte (rinfo))
968 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p, &rinfo->nexthop,
969 rinfo->metric);
970
971 rp->info = NULL;
972 ripng_info_free (rinfo);
973
paul718e3742002-12-13 20:15:29 +0000974 route_unlock_node (rp);
hassoa94434b2003-05-25 17:10:12 +0000975
paul718e3742002-12-13 20:15:29 +0000976 }
hassoa94434b2003-05-25 17:10:12 +0000977
978 rinfo = ripng_info_new ();
paul718e3742002-12-13 20:15:29 +0000979
980 rinfo->type = type;
981 rinfo->sub_type = sub_type;
982 rinfo->ifindex = ifindex;
983 rinfo->metric = 1;
paul718e3742002-12-13 20:15:29 +0000984 rinfo->rp = rp;
hassoa94434b2003-05-25 17:10:12 +0000985
986 if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
987 rinfo->nexthop = *nexthop;
988
989 rinfo->flags |= RIPNG_RTF_FIB;
paul718e3742002-12-13 20:15:29 +0000990 rp->info = rinfo;
hassoa94434b2003-05-25 17:10:12 +0000991
992 /* Aggregate check. */
993 ripng_aggregate_increment (rp, rinfo);
994
995 rinfo->flags |= RIPNG_RTF_CHANGED;
996
997 if (IS_RIPNG_DEBUG_EVENT) {
998 if (!nexthop)
ajsc6106812004-12-08 19:51:16 +0000999 zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001000 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001001 ifindex2ifname(ifindex));
1002 else
ajsc6106812004-12-08 19:51:16 +00001003 zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001004 inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
hassoa94434b2003-05-25 17:10:12 +00001005 ifindex2ifname(ifindex));
1006 }
1007
1008 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001009}
1010
1011/* Delete redistributed route to RIPng table. */
1012void
1013ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p,
1014 unsigned int ifindex)
1015{
1016 struct route_node *rp;
1017 struct ripng_info *rinfo;
1018
1019 if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
1020 return;
1021 if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
1022 return;
hassoa94434b2003-05-25 17:10:12 +00001023#if defined (MUSICA) || defined (LINUX)
1024 /* XXX As long as the RIPng redistribution is applied to all the connected
1025 * routes, one needs to filter the ::/96 prefixes.
1026 * However it could be a wanted case, it will be removed soon.
1027 */
1028 if ((IN6_IS_ADDR_V4COMPAT(&p->prefix)) ||
1029 (IN6_IS_ADDR_UNSPECIFIED (&p->prefix) && (p->prefixlen == 96)))
1030 return;
1031#endif /* MUSICA or LINUX */
paul718e3742002-12-13 20:15:29 +00001032
1033 rp = route_node_lookup (ripng->table, (struct prefix *) p);
1034
1035 if (rp)
1036 {
1037 rinfo = rp->info;
1038
1039 if (rinfo != NULL
1040 && rinfo->type == type
1041 && rinfo->sub_type == sub_type
1042 && rinfo->ifindex == ifindex)
1043 {
hassoa94434b2003-05-25 17:10:12 +00001044 /* Perform poisoned reverse. */
1045 rinfo->metric = RIPNG_METRIC_INFINITY;
1046 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1047 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001048 RIPNG_TIMER_OFF (rinfo->t_timeout);
hassoa94434b2003-05-25 17:10:12 +00001049
1050 /* Aggregate count decrement. */
1051 ripng_aggregate_decrement (rp, rinfo);
1052
1053 rinfo->flags |= RIPNG_RTF_CHANGED;
paul718e3742002-12-13 20:15:29 +00001054
hassoa94434b2003-05-25 17:10:12 +00001055 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001056 zlog_debug ("Poisone %s/%d on the interface %s with an infinity metric [delete]",
hasso3a2ce6a2005-04-08 01:30:51 +00001057 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001058 ifindex2ifname(ifindex));
paul718e3742002-12-13 20:15:29 +00001059
hassoa94434b2003-05-25 17:10:12 +00001060 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001061 }
paul718e3742002-12-13 20:15:29 +00001062 }
1063}
1064
1065/* Withdraw redistributed route. */
1066void
1067ripng_redistribute_withdraw (int type)
1068{
1069 struct route_node *rp;
1070 struct ripng_info *rinfo;
1071
hassoa94434b2003-05-25 17:10:12 +00001072 if (!ripng)
1073 return;
1074
paul718e3742002-12-13 20:15:29 +00001075 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1076 if ((rinfo = rp->info) != NULL)
1077 {
hassoa94434b2003-05-25 17:10:12 +00001078 if ((rinfo->type == type)
1079 && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
paul718e3742002-12-13 20:15:29 +00001080 {
hassoa94434b2003-05-25 17:10:12 +00001081 /* Perform poisoned reverse. */
1082 rinfo->metric = RIPNG_METRIC_INFINITY;
1083 RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1084 ripng_garbage_collect, ripng->garbage_time);
paul718e3742002-12-13 20:15:29 +00001085 RIPNG_TIMER_OFF (rinfo->t_timeout);
paul718e3742002-12-13 20:15:29 +00001086
hassoa94434b2003-05-25 17:10:12 +00001087 /* Aggregate count decrement. */
1088 ripng_aggregate_decrement (rp, rinfo);
paul718e3742002-12-13 20:15:29 +00001089
hassoa94434b2003-05-25 17:10:12 +00001090 rinfo->flags |= RIPNG_RTF_CHANGED;
1091
1092 if (IS_RIPNG_DEBUG_EVENT) {
1093 struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
1094
ajsc6106812004-12-08 19:51:16 +00001095 zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
hasso3a2ce6a2005-04-08 01:30:51 +00001096 inet6_ntoa(p->prefix), p->prefixlen,
hassoa94434b2003-05-25 17:10:12 +00001097 ifindex2ifname(rinfo->ifindex));
1098 }
1099
1100 ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
paul718e3742002-12-13 20:15:29 +00001101 }
1102 }
1103}
1104
1105/* RIP routing information. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001106static void
paul718e3742002-12-13 20:15:29 +00001107ripng_response_process (struct ripng_packet *packet, int size,
1108 struct sockaddr_in6 *from, struct interface *ifp,
1109 int hoplimit)
1110{
1111 caddr_t lim;
1112 struct rte *rte;
1113 struct ripng_nexthop nexthop;
1114
1115 /* RFC2080 2.4.2 Response Messages:
1116 The Response must be ignored if it is not from the RIPng port. */
1117 if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1118 {
1119 zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001120 ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001121 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001122 return;
1123 }
1124
1125 /* The datagram's IPv6 source address should be checked to see
1126 whether the datagram is from a valid neighbor; the source of the
1127 datagram must be a link-local address. */
1128 if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1129 {
1130 zlog_warn ("RIPng packet comes from non link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001131 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001132 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001133 return;
1134 }
1135
1136 /* It is also worth checking to see whether the response is from one
1137 of the router's own addresses. Interfaces on broadcast networks
1138 may receive copies of their own multicasts immediately. If a
1139 router processes its own output as new input, confusion is likely,
1140 and such datagrams must be ignored. */
1141 if (ripng_lladdr_check (ifp, &from->sin6_addr))
1142 {
1143 zlog_warn ("RIPng packet comes from my own link local address %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001144 inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001145 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001146 return;
1147 }
1148
1149 /* As an additional check, periodic advertisements must have their
1150 hop counts set to 255, and inbound, multicast packets sent from the
1151 RIPng port (i.e. periodic advertisement or triggered update
1152 packets) must be examined to ensure that the hop count is 255. */
1153 if (hoplimit >= 0 && hoplimit != 255)
1154 {
1155 zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001156 hoplimit, inet6_ntoa (from->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001157 ripng_peer_bad_packet (from);
paul718e3742002-12-13 20:15:29 +00001158 return;
1159 }
1160
hassoa94434b2003-05-25 17:10:12 +00001161 /* Update RIPng peer. */
1162 ripng_peer_update (from, packet->version);
1163
paul718e3742002-12-13 20:15:29 +00001164 /* Reset nexthop. */
1165 memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1166 nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1167
1168 /* Set RTE pointer. */
1169 rte = packet->rte;
1170
1171 for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++)
1172 {
1173 /* First of all, we have to check this RTE is next hop RTE or
1174 not. Next hop RTE is completely different with normal RTE so
1175 we need special treatment. */
1176 if (rte->metric == RIPNG_METRIC_NEXTHOP)
1177 {
1178 ripng_nexthop_rte (rte, from, &nexthop);
1179 continue;
1180 }
1181
1182 /* RTE information validation. */
1183
1184 /* - is the destination prefix valid (e.g., not a multicast
1185 prefix and not a link-local address) A link-local address
1186 should never be present in an RTE. */
1187 if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1188 {
1189 zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001190 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001191 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001192 continue;
1193 }
1194 if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1195 {
1196 zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001197 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001198 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001199 continue;
1200 }
1201 if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1202 {
1203 zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
hasso3a2ce6a2005-04-08 01:30:51 +00001204 inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
hassoa94434b2003-05-25 17:10:12 +00001205 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001206 continue;
1207 }
1208
1209 /* - is the prefix length valid (i.e., between 0 and 128,
1210 inclusive) */
1211 if (rte->prefixlen > 128)
1212 {
1213 zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
hasso3a2ce6a2005-04-08 01:30:51 +00001214 inet6_ntoa (rte->addr), rte->prefixlen,
1215 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001216 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001217 continue;
1218 }
1219
1220 /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1221 if (! (rte->metric >= 1 && rte->metric <= 16))
1222 {
1223 zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
hasso3a2ce6a2005-04-08 01:30:51 +00001224 inet6_ntoa (from->sin6_addr), ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001225 ripng_peer_bad_route (from);
paul718e3742002-12-13 20:15:29 +00001226 continue;
1227 }
1228
hassoa94434b2003-05-25 17:10:12 +00001229 /* Vincent: XXX Should we compute the direclty reachable nexthop
1230 * for our RIPng network ?
1231 **/
paul718e3742002-12-13 20:15:29 +00001232
1233 /* Routing table updates. */
1234 ripng_route_process (rte, from, &nexthop, ifp);
1235 }
1236}
1237
1238/* Response to request message. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001239static void
paul718e3742002-12-13 20:15:29 +00001240ripng_request_process (struct ripng_packet *packet,int size,
1241 struct sockaddr_in6 *from, struct interface *ifp)
1242{
1243 caddr_t lim;
1244 struct rte *rte;
1245 struct prefix_ipv6 p;
1246 struct route_node *rp;
1247 struct ripng_info *rinfo;
1248 struct ripng_interface *ri;
1249
hassoa94434b2003-05-25 17:10:12 +00001250 /* Does not reponse to the requests on the loopback interfaces */
1251 if (if_is_loopback (ifp))
1252 return;
1253
paul718e3742002-12-13 20:15:29 +00001254 /* Check RIPng process is enabled on this interface. */
1255 ri = ifp->info;
1256 if (! ri->running)
1257 return;
1258
1259 /* When passive interface is specified, suppress responses */
1260 if (ri->passive)
1261 return;
1262
hassoa94434b2003-05-25 17:10:12 +00001263 /* RIPng peer update. */
1264 ripng_peer_update (from, packet->version);
1265
paul718e3742002-12-13 20:15:29 +00001266 lim = ((caddr_t) packet) + size;
1267 rte = packet->rte;
1268
1269 /* The Request is processed entry by entry. If there are no
1270 entries, no response is given. */
1271 if (lim == (caddr_t) rte)
1272 return;
1273
1274 /* There is one special case. If there is exactly one entry in the
1275 request, and it has a destination prefix of zero, a prefix length
1276 of zero, and a metric of infinity (i.e., 16), then this is a
1277 request to send the entire routing table. In that case, a call
1278 is made to the output process to send the routing table to the
1279 requesting address/port. */
1280 if (lim == ((caddr_t) (rte + 1)) &&
1281 IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1282 rte->prefixlen == 0 &&
1283 rte->metric == RIPNG_METRIC_INFINITY)
1284 {
1285 /* All route with split horizon */
hassoa94434b2003-05-25 17:10:12 +00001286 ripng_output_process (ifp, from, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001287 }
1288 else
1289 {
1290 /* Except for this special case, processing is quite simple.
1291 Examine the list of RTEs in the Request one by one. For each
1292 entry, look up the destination in the router's routing
1293 database and, if there is a route, put that route's metric in
1294 the metric field of the RTE. If there is no explicit route
1295 to the specified destination, put infinity in the metric
1296 field. Once all the entries have been filled in, change the
1297 command from Request to Response and send the datagram back
1298 to the requestor. */
1299 memset (&p, 0, sizeof (struct prefix_ipv6));
1300 p.family = AF_INET6;
1301
1302 for (; ((caddr_t) rte) < lim; rte++)
1303 {
1304 p.prefix = rte->addr;
1305 p.prefixlen = rte->prefixlen;
1306 apply_mask_ipv6 (&p);
1307
1308 rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1309
1310 if (rp)
1311 {
1312 rinfo = rp->info;
1313 rte->metric = rinfo->metric;
1314 route_unlock_node (rp);
1315 }
1316 else
1317 rte->metric = RIPNG_METRIC_INFINITY;
1318 }
1319 packet->command = RIPNG_RESPONSE;
1320
1321 ripng_send_packet ((caddr_t) packet, size, from, ifp);
1322 }
1323}
1324
1325/* First entry point of reading RIPng packet. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001326static int
paul718e3742002-12-13 20:15:29 +00001327ripng_read (struct thread *thread)
1328{
1329 int len;
1330 int sock;
1331 struct sockaddr_in6 from;
1332 struct ripng_packet *packet;
1333 unsigned int ifindex;
1334 struct interface *ifp;
1335 int hoplimit = -1;
1336
1337 /* Check ripng is active and alive. */
1338 assert (ripng != NULL);
1339 assert (ripng->sock >= 0);
1340
1341 /* Fetch thread data and set read pointer to empty for event
1342 managing. `sock' sould be same as ripng->sock. */
1343 sock = THREAD_FD (thread);
1344 ripng->t_read = NULL;
1345
1346 /* Add myself to the next event. */
1347 ripng_event (RIPNG_READ, sock);
1348
1349 /* Read RIPng packet. */
1350 len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf),
1351 STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1352 &hoplimit);
1353 if (len < 0)
1354 {
ajs6099b3b2004-11-20 02:06:59 +00001355 zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
paul718e3742002-12-13 20:15:29 +00001356 return len;
1357 }
1358
1359 /* Check RTE boundary. RTE size (Packet length - RIPng header size
1360 (4)) must be multiple size of one RTE size (20). */
1361 if (((len - 4) % 20) != 0)
1362 {
1363 zlog_warn ("RIPng invalid packet size %d from %s", len,
hasso3a2ce6a2005-04-08 01:30:51 +00001364 inet6_ntoa (from.sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001365 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001366 return 0;
1367 }
1368
1369 packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1370 ifp = if_lookup_by_index (ifindex);
1371
1372 /* RIPng packet received. */
1373 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001374 zlog_debug ("RIPng packet received from %s port %d on %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001375 inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port),
paul718e3742002-12-13 20:15:29 +00001376 ifp ? ifp->name : "unknown");
1377
1378 /* Logging before packet checking. */
1379 if (IS_RIPNG_DEBUG_RECV)
1380 ripng_packet_dump (packet, len, "RECV");
1381
1382 /* Packet comes from unknown interface. */
1383 if (ifp == NULL)
1384 {
1385 zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1386 return 0;
1387 }
1388
1389 /* Packet version mismatch checking. */
1390 if (packet->version != ripng->version)
1391 {
1392 zlog_warn ("RIPng packet version %d doesn't fit to my version %d",
1393 packet->version, ripng->version);
hassoa94434b2003-05-25 17:10:12 +00001394 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001395 return 0;
1396 }
1397
1398 /* Process RIPng packet. */
1399 switch (packet->command)
1400 {
1401 case RIPNG_REQUEST:
1402 ripng_request_process (packet, len, &from, ifp);
1403 break;
1404 case RIPNG_RESPONSE:
1405 ripng_response_process (packet, len, &from, ifp, hoplimit);
1406 break;
1407 default:
1408 zlog_warn ("Invalid RIPng command %d", packet->command);
hassoa94434b2003-05-25 17:10:12 +00001409 ripng_peer_bad_packet (&from);
paul718e3742002-12-13 20:15:29 +00001410 break;
1411 }
1412 return 0;
1413}
1414
1415/* Walk down the RIPng routing table then clear changed flag. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001416static void
1417ripng_clear_changed_flag (void)
paul718e3742002-12-13 20:15:29 +00001418{
1419 struct route_node *rp;
1420 struct ripng_info *rinfo;
1421
1422 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1423 if ((rinfo = rp->info) != NULL)
1424 if (rinfo->flags & RIPNG_RTF_CHANGED)
1425 rinfo->flags &= ~RIPNG_RTF_CHANGED;
1426}
1427
1428/* Regular update of RIPng route. Send all routing formation to RIPng
1429 enabled interface. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001430static int
paul718e3742002-12-13 20:15:29 +00001431ripng_update (struct thread *t)
1432{
hasso52dc7ee2004-09-23 19:18:23 +00001433 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001434 struct interface *ifp;
1435 struct ripng_interface *ri;
1436
1437 /* Clear update timer thread. */
1438 ripng->t_update = NULL;
1439
1440 /* Logging update event. */
1441 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001442 zlog_debug ("RIPng update timer expired!");
paul718e3742002-12-13 20:15:29 +00001443
1444 /* Supply routes to each interface. */
paul1eb8ef22005-04-07 07:30:20 +00001445 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001446 {
paul718e3742002-12-13 20:15:29 +00001447 ri = ifp->info;
1448
1449 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1450 continue;
1451
1452 if (! ri->running)
1453 continue;
1454
1455 /* When passive interface is specified, suppress announce to the
1456 interface. */
1457 if (ri->passive)
1458 continue;
1459
1460#if RIPNG_ADVANCED
1461 if (ri->ri_send == RIPNG_SEND_OFF)
1462 {
1463 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001464 zlog (NULL, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001465 "[Event] RIPng send to if %d is suppressed by config",
1466 ifp->ifindex);
1467 continue;
1468 }
1469#endif /* RIPNG_ADVANCED */
1470
hassoa94434b2003-05-25 17:10:12 +00001471 ripng_output_process (ifp, NULL, ripng_all_route);
paul718e3742002-12-13 20:15:29 +00001472 }
1473
1474 /* Triggered updates may be suppressed if a regular update is due by
1475 the time the triggered update would be sent. */
1476 if (ripng->t_triggered_interval)
1477 {
1478 thread_cancel (ripng->t_triggered_interval);
1479 ripng->t_triggered_interval = NULL;
1480 }
1481 ripng->trigger = 0;
1482
1483 /* Reset flush event. */
1484 ripng_event (RIPNG_UPDATE_EVENT, 0);
1485
1486 return 0;
1487}
1488
1489/* Triggered update interval timer. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001490static int
paul718e3742002-12-13 20:15:29 +00001491ripng_triggered_interval (struct thread *t)
1492{
1493 ripng->t_triggered_interval = NULL;
1494
1495 if (ripng->trigger)
1496 {
1497 ripng->trigger = 0;
1498 ripng_triggered_update (t);
1499 }
1500 return 0;
1501}
1502
1503/* Execute triggered update. */
1504int
1505ripng_triggered_update (struct thread *t)
1506{
hasso52dc7ee2004-09-23 19:18:23 +00001507 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00001508 struct interface *ifp;
1509 struct ripng_interface *ri;
1510 int interval;
1511
1512 ripng->t_triggered_update = NULL;
1513
1514 /* Cancel interval timer. */
1515 if (ripng->t_triggered_interval)
1516 {
1517 thread_cancel (ripng->t_triggered_interval);
1518 ripng->t_triggered_interval = NULL;
1519 }
1520 ripng->trigger = 0;
1521
1522 /* Logging triggered update. */
1523 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001524 zlog_debug ("RIPng triggered update!");
paul718e3742002-12-13 20:15:29 +00001525
1526 /* Split Horizon processing is done when generating triggered
1527 updates as well as normal updates (see section 2.6). */
paul1eb8ef22005-04-07 07:30:20 +00001528 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
paul718e3742002-12-13 20:15:29 +00001529 {
paul718e3742002-12-13 20:15:29 +00001530 ri = ifp->info;
1531
1532 if (if_is_loopback (ifp) || ! if_is_up (ifp))
1533 continue;
1534
1535 if (! ri->running)
1536 continue;
1537
1538 /* When passive interface is specified, suppress announce to the
1539 interface. */
1540 if (ri->passive)
1541 continue;
1542
hassoa94434b2003-05-25 17:10:12 +00001543 ripng_output_process (ifp, NULL, ripng_changed_route);
paul718e3742002-12-13 20:15:29 +00001544 }
1545
1546 /* Once all of the triggered updates have been generated, the route
1547 change flags should be cleared. */
1548 ripng_clear_changed_flag ();
1549
1550 /* After a triggered update is sent, a timer should be set for a
1551 random interval between 1 and 5 seconds. If other changes that
1552 would trigger updates occur before the timer expires, a single
1553 update is triggered when the timer expires. */
1554 interval = (random () % 5) + 1;
1555
1556 ripng->t_triggered_interval =
1557 thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1558
1559 return 0;
1560}
1561
1562/* Write routing table entry to the stream and return next index of
1563 the routing table entry in the stream. */
1564int
1565ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
hassoa94434b2003-05-25 17:10:12 +00001566 struct in6_addr *nexthop, u_int16_t tag, u_char metric)
paul718e3742002-12-13 20:15:29 +00001567{
1568 /* RIPng packet header. */
1569 if (num == 0)
1570 {
1571 stream_putc (s, RIPNG_RESPONSE);
1572 stream_putc (s, RIPNG_V1);
1573 stream_putw (s, 0);
1574 }
1575
1576 /* Write routing table entry. */
hassoa94434b2003-05-25 17:10:12 +00001577 if (!nexthop)
hassoc9e52be2004-09-26 16:09:34 +00001578 stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
hassoa94434b2003-05-25 17:10:12 +00001579 else
hassoc9e52be2004-09-26 16:09:34 +00001580 stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
paul718e3742002-12-13 20:15:29 +00001581 stream_putw (s, tag);
hassoa94434b2003-05-25 17:10:12 +00001582 if (p)
1583 stream_putc (s, p->prefixlen);
1584 else
1585 stream_putc (s, 0);
paul718e3742002-12-13 20:15:29 +00001586 stream_putc (s, metric);
1587
1588 return ++num;
1589}
1590
1591/* Send RESPONSE message to specified destination. */
1592void
1593ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
hassoa94434b2003-05-25 17:10:12 +00001594 int route_type)
paul718e3742002-12-13 20:15:29 +00001595{
1596 int ret;
paul718e3742002-12-13 20:15:29 +00001597 struct route_node *rp;
1598 struct ripng_info *rinfo;
1599 struct ripng_interface *ri;
1600 struct ripng_aggregate *aggregate;
1601 struct prefix_ipv6 *p;
hassoa94434b2003-05-25 17:10:12 +00001602 struct list * ripng_rte_list;
paul718e3742002-12-13 20:15:29 +00001603
hassoa94434b2003-05-25 17:10:12 +00001604 if (IS_RIPNG_DEBUG_EVENT) {
1605 if (to)
ajsc6106812004-12-08 19:51:16 +00001606 zlog_debug ("RIPng update routes to neighbor %s",
hasso3a2ce6a2005-04-08 01:30:51 +00001607 inet6_ntoa(to->sin6_addr));
hassoa94434b2003-05-25 17:10:12 +00001608 else
ajsc6106812004-12-08 19:51:16 +00001609 zlog_debug ("RIPng update routes on interface %s", ifp->name);
hassoa94434b2003-05-25 17:10:12 +00001610 }
paul718e3742002-12-13 20:15:29 +00001611
paul718e3742002-12-13 20:15:29 +00001612 /* Get RIPng interface. */
1613 ri = ifp->info;
hassoa94434b2003-05-25 17:10:12 +00001614
1615 ripng_rte_list = ripng_rte_new();
1616
paul718e3742002-12-13 20:15:29 +00001617 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1618 {
1619 if ((rinfo = rp->info) != NULL && rinfo->suppress == 0)
1620 {
hassoa94434b2003-05-25 17:10:12 +00001621 /* If no route-map are applied, the RTE will be these following
1622 * informations.
1623 */
paul718e3742002-12-13 20:15:29 +00001624 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001625 rinfo->metric_out = rinfo->metric;
1626 rinfo->tag_out = rinfo->tag;
1627 memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1628 /* In order to avoid some local loops,
1629 * if the RIPng route has a nexthop via this interface, keep the nexthop,
1630 * otherwise set it to 0. The nexthop should not be propagated
1631 * beyond the local broadcast/multicast area in order
1632 * to avoid an IGP multi-level recursive look-up.
1633 */
1634 if (rinfo->ifindex == ifp->ifindex)
1635 rinfo->nexthop_out = rinfo->nexthop;
1636
1637 /* Apply output filters. */
1638 ret = ripng_outgoing_filter (p, ri);
1639 if (ret < 0)
1640 continue;
paul718e3742002-12-13 20:15:29 +00001641
1642 /* Changed route only output. */
1643 if (route_type == ripng_changed_route &&
1644 (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1645 continue;
1646
1647 /* Split horizon. */
hassoa94434b2003-05-25 17:10:12 +00001648 if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1649 {
1650 /* We perform split horizon for RIPng routes. */
1651 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1652 rinfo->ifindex == ifp->ifindex)
1653 continue;
1654 }
paul718e3742002-12-13 20:15:29 +00001655
1656 /* Preparation for route-map. */
hassoa94434b2003-05-25 17:10:12 +00001657 rinfo->metric_set = 0;
1658 /* nexthop_out,
1659 * metric_out
1660 * and tag_out are already initialized.
1661 */
paul718e3742002-12-13 20:15:29 +00001662
hassoa94434b2003-05-25 17:10:12 +00001663 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001664 if (ri->routemap[RIPNG_FILTER_OUT])
1665 {
1666 int ret;
paul718e3742002-12-13 20:15:29 +00001667
1668 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1669 (struct prefix *) p, RMAP_RIPNG,
hassoa94434b2003-05-25 17:10:12 +00001670 rinfo);
paul718e3742002-12-13 20:15:29 +00001671
1672 if (ret == RMAP_DENYMATCH)
1673 {
1674 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001675 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001676 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001677 continue;
paul718e3742002-12-13 20:15:29 +00001678 }
1679
paul718e3742002-12-13 20:15:29 +00001680 }
1681
hassoa94434b2003-05-25 17:10:12 +00001682 /* Redistribute route-map. */
1683 if (ripng->route_map[rinfo->type].name)
paul718e3742002-12-13 20:15:29 +00001684 {
hassoa94434b2003-05-25 17:10:12 +00001685 int ret;
1686
1687 ret = route_map_apply (ripng->route_map[rinfo->type].map,
1688 (struct prefix *) p, RMAP_RIPNG,
hassobb3a0232003-06-02 10:38:15 +00001689 rinfo);
hassoa94434b2003-05-25 17:10:12 +00001690
1691 if (ret == RMAP_DENYMATCH)
paul718e3742002-12-13 20:15:29 +00001692 {
hassoa94434b2003-05-25 17:10:12 +00001693 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001694 zlog_debug ("RIPng %s/%d is filtered by route-map",
hasso3a2ce6a2005-04-08 01:30:51 +00001695 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001696 continue;
paul718e3742002-12-13 20:15:29 +00001697 }
hassoa94434b2003-05-25 17:10:12 +00001698 }
paul718e3742002-12-13 20:15:29 +00001699
hassoa94434b2003-05-25 17:10:12 +00001700 /* When the route-map does not set metric. */
1701 if (! rinfo->metric_set)
1702 {
1703 /* If the redistribute metric is set. */
1704 if (ripng->route_map[rinfo->type].metric_config
1705 && rinfo->metric != RIPNG_METRIC_INFINITY)
paul718e3742002-12-13 20:15:29 +00001706 {
hassoa94434b2003-05-25 17:10:12 +00001707 rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1708 }
1709 else
1710 {
1711 /* If the route is not connected or localy generated
1712 one, use default-metric value */
1713 if (rinfo->type != ZEBRA_ROUTE_RIPNG
1714 && rinfo->type != ZEBRA_ROUTE_CONNECT
paul718e3742002-12-13 20:15:29 +00001715 && rinfo->metric != RIPNG_METRIC_INFINITY)
hassoa94434b2003-05-25 17:10:12 +00001716 rinfo->metric_out = ripng->default_metric;
paul718e3742002-12-13 20:15:29 +00001717 }
1718 }
1719
hassoa94434b2003-05-25 17:10:12 +00001720 /* Apply offset-list */
1721 if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1722 ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
paul718e3742002-12-13 20:15:29 +00001723
hassoa94434b2003-05-25 17:10:12 +00001724 if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1725 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1726
1727 /* Perform split-horizon with poisoned reverse
1728 * for RIPng routes.
1729 **/
1730 if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
1731 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1732 rinfo->ifindex == ifp->ifindex)
1733 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1734 }
1735
1736 /* Add RTE to the list */
1737 ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
paul718e3742002-12-13 20:15:29 +00001738 }
hassoa94434b2003-05-25 17:10:12 +00001739
1740 /* Process the aggregated RTE entry */
paul718e3742002-12-13 20:15:29 +00001741 if ((aggregate = rp->aggregate) != NULL &&
1742 aggregate->count > 0 &&
1743 aggregate->suppress == 0)
1744 {
hassoa94434b2003-05-25 17:10:12 +00001745 /* If no route-map are applied, the RTE will be these following
1746 * informations.
1747 */
paul718e3742002-12-13 20:15:29 +00001748 p = (struct prefix_ipv6 *) &rp->p;
hassoa94434b2003-05-25 17:10:12 +00001749 aggregate->metric_set = 0;
1750 aggregate->metric_out = aggregate->metric;
1751 aggregate->tag_out = aggregate->tag;
1752 memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
paul718e3742002-12-13 20:15:29 +00001753
1754 /* Apply output filters.*/
hassoa94434b2003-05-25 17:10:12 +00001755 ret = ripng_outgoing_filter (p, ri);
1756 if (ret < 0)
1757 continue;
paul718e3742002-12-13 20:15:29 +00001758
hassoa94434b2003-05-25 17:10:12 +00001759 /* Interface route-map */
paul718e3742002-12-13 20:15:29 +00001760 if (ri->routemap[RIPNG_FILTER_OUT])
1761 {
1762 int ret;
1763 struct ripng_info newinfo;
1764
hassoa94434b2003-05-25 17:10:12 +00001765 /* let's cast the aggregate structure to ripng_info */
paul718e3742002-12-13 20:15:29 +00001766 memset (&newinfo, 0, sizeof (struct ripng_info));
hassoa94434b2003-05-25 17:10:12 +00001767 /* the nexthop is :: */
1768 newinfo.metric = aggregate->metric;
1769 newinfo.metric_out = aggregate->metric_out;
1770 newinfo.tag = aggregate->tag;
1771 newinfo.tag_out = aggregate->tag_out;
paul718e3742002-12-13 20:15:29 +00001772
1773 ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT],
1774 (struct prefix *) p, RMAP_RIPNG,
1775 &newinfo);
1776
1777 if (ret == RMAP_DENYMATCH)
1778 {
1779 if (IS_RIPNG_DEBUG_PACKET)
ajsc6106812004-12-08 19:51:16 +00001780 zlog_debug ("RIPng %s/%d is filtered by route-map out",
hasso3a2ce6a2005-04-08 01:30:51 +00001781 inet6_ntoa (p->prefix), p->prefixlen);
hassoa94434b2003-05-25 17:10:12 +00001782 continue;
paul718e3742002-12-13 20:15:29 +00001783 }
1784
hassoa94434b2003-05-25 17:10:12 +00001785 aggregate->metric_out = newinfo.metric_out;
1786 aggregate->tag_out = newinfo.tag_out;
1787 if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1788 aggregate->nexthop_out = newinfo.nexthop_out;
paul718e3742002-12-13 20:15:29 +00001789 }
1790
hassoa94434b2003-05-25 17:10:12 +00001791 /* There is no redistribute routemap for the aggregated RTE */
1792
paul718e3742002-12-13 20:15:29 +00001793 /* Changed route only output. */
hassoa94434b2003-05-25 17:10:12 +00001794 /* XXX, vincent, in order to increase time convergence,
1795 * it should be announced if a child has changed.
1796 */
paul718e3742002-12-13 20:15:29 +00001797 if (route_type == ripng_changed_route)
1798 continue;
1799
hassoa94434b2003-05-25 17:10:12 +00001800 /* Apply offset-list */
1801 if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1802 ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
paul718e3742002-12-13 20:15:29 +00001803
hassoa94434b2003-05-25 17:10:12 +00001804 if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1805 aggregate->metric_out = RIPNG_METRIC_INFINITY;
1806
1807 /* Add RTE to the list */
1808 ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
paul718e3742002-12-13 20:15:29 +00001809 }
1810
1811 }
paul718e3742002-12-13 20:15:29 +00001812
hassoa94434b2003-05-25 17:10:12 +00001813 /* Flush the list */
1814 ripng_rte_send(ripng_rte_list, ifp, to);
1815 ripng_rte_free(ripng_rte_list);
paul718e3742002-12-13 20:15:29 +00001816}
1817
1818/* Create new RIPng instance and set it to global variable. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01001819static int
1820ripng_create (void)
paul718e3742002-12-13 20:15:29 +00001821{
1822 /* ripng should be NULL. */
1823 assert (ripng == NULL);
1824
1825 /* Allocaste RIPng instance. */
Stephen Hemminger393deb92008-08-18 14:13:29 -07001826 ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
paul718e3742002-12-13 20:15:29 +00001827
1828 /* Default version and timer values. */
1829 ripng->version = RIPNG_V1;
1830 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1831 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1832 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1833 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1834
1835 /* Make buffer. */
1836 ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1837 ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1838
1839 /* Initialize RIPng routig table. */
1840 ripng->table = route_table_init ();
1841 ripng->route = route_table_init ();
1842 ripng->aggregate = route_table_init ();
1843
1844 /* Make socket. */
1845 ripng->sock = ripng_make_socket ();
1846 if (ripng->sock < 0)
1847 return ripng->sock;
1848
1849 /* Threads. */
1850 ripng_event (RIPNG_READ, ripng->sock);
1851 ripng_event (RIPNG_UPDATE_EVENT, 1);
1852
1853 return 0;
1854}
1855
hassoa94434b2003-05-25 17:10:12 +00001856/* Send RIPng request to the interface. */
paul718e3742002-12-13 20:15:29 +00001857int
1858ripng_request (struct interface *ifp)
1859{
1860 struct rte *rte;
1861 struct ripng_packet ripng_packet;
1862
hassoa94434b2003-05-25 17:10:12 +00001863 /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1864 if (if_is_loopback(ifp))
1865 return 0;
1866
1867 /* If interface is down, don't send RIP packet. */
1868 if (! if_is_up (ifp))
1869 return 0;
1870
paul718e3742002-12-13 20:15:29 +00001871 if (IS_RIPNG_DEBUG_EVENT)
ajsc6106812004-12-08 19:51:16 +00001872 zlog_debug ("RIPng send request to %s", ifp->name);
paul718e3742002-12-13 20:15:29 +00001873
1874 memset (&ripng_packet, 0, sizeof (ripng_packet));
1875 ripng_packet.command = RIPNG_REQUEST;
1876 ripng_packet.version = RIPNG_V1;
1877 rte = ripng_packet.rte;
1878 rte->metric = RIPNG_METRIC_INFINITY;
1879
1880 return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet),
1881 NULL, ifp);
1882}
1883
paul718e3742002-12-13 20:15:29 +00001884
Paul Jakma6ac29a52008-08-15 13:45:30 +01001885static int
paul718e3742002-12-13 20:15:29 +00001886ripng_update_jitter (int time)
1887{
1888 return ((rand () % (time + 1)) - (time / 2));
1889}
1890
1891void
1892ripng_event (enum ripng_event event, int sock)
1893{
paul718e3742002-12-13 20:15:29 +00001894 int jitter = 0;
1895
1896 switch (event)
1897 {
1898 case RIPNG_READ:
1899 if (!ripng->t_read)
1900 ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1901 break;
1902 case RIPNG_UPDATE_EVENT:
1903 if (ripng->t_update)
1904 {
1905 thread_cancel (ripng->t_update);
1906 ripng->t_update = NULL;
1907 }
1908 /* Update timer jitter. */
1909 jitter = ripng_update_jitter (ripng->update_time);
1910
1911 ripng->t_update =
1912 thread_add_timer (master, ripng_update, NULL,
1913 sock ? 2 : ripng->update_time + jitter);
1914 break;
1915 case RIPNG_TRIGGERED_UPDATE:
1916 if (ripng->t_triggered_interval)
1917 ripng->trigger = 1;
1918 else if (! ripng->t_triggered_update)
1919 ripng->t_triggered_update =
1920 thread_add_event (master, ripng_triggered_update, NULL, 0);
1921 break;
1922 default:
1923 break;
1924 }
1925}
1926
paul718e3742002-12-13 20:15:29 +00001927
paul718e3742002-12-13 20:15:29 +00001928/* Print out routes update time. */
1929static void
1930ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1931{
paul718e3742002-12-13 20:15:29 +00001932 time_t clock;
1933 struct tm *tm;
1934#define TIME_BUF 25
1935 char timebuf [TIME_BUF];
1936 struct thread *thread;
1937
paul718e3742002-12-13 20:15:29 +00001938 if ((thread = rinfo->t_timeout) != NULL)
1939 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001940 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001941 tm = gmtime (&clock);
1942 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1943 vty_out (vty, "%5s", timebuf);
1944 }
1945 else if ((thread = rinfo->t_garbage_collect) != NULL)
1946 {
Vincent Jardin6dfa8272007-04-12 07:43:49 +00001947 clock = thread_timer_remain_second (thread);
paul718e3742002-12-13 20:15:29 +00001948 tm = gmtime (&clock);
1949 strftime (timebuf, TIME_BUF, "%M:%S", tm);
1950 vty_out (vty, "%5s", timebuf);
1951 }
1952}
1953
Paul Jakma6ac29a52008-08-15 13:45:30 +01001954static char *
hassoa94434b2003-05-25 17:10:12 +00001955ripng_route_subtype_print (struct ripng_info *rinfo)
1956{
1957 static char str[3];
1958 memset(str, 0, 3);
1959
1960 if (rinfo->suppress)
1961 strcat(str, "S");
1962
1963 switch (rinfo->sub_type)
1964 {
1965 case RIPNG_ROUTE_RTE:
1966 strcat(str, "n");
1967 break;
1968 case RIPNG_ROUTE_STATIC:
1969 strcat(str, "s");
1970 break;
1971 case RIPNG_ROUTE_DEFAULT:
1972 strcat(str, "d");
1973 break;
1974 case RIPNG_ROUTE_REDISTRIBUTE:
1975 strcat(str, "r");
1976 break;
1977 case RIPNG_ROUTE_INTERFACE:
1978 strcat(str, "i");
1979 break;
1980 default:
1981 strcat(str, "?");
1982 break;
1983 }
1984
1985 return str;
1986}
1987
paul718e3742002-12-13 20:15:29 +00001988DEFUN (show_ipv6_ripng,
1989 show_ipv6_ripng_cmd,
1990 "show ipv6 ripng",
1991 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00001992 IPV6_STR
paul718e3742002-12-13 20:15:29 +00001993 "Show RIPng routes\n")
1994{
1995 struct route_node *rp;
1996 struct ripng_info *rinfo;
1997 struct ripng_aggregate *aggregate;
1998 struct prefix_ipv6 *p;
1999 int len;
2000
hassoa94434b2003-05-25 17:10:12 +00002001 if (! ripng)
2002 return CMD_SUCCESS;
2003
paul718e3742002-12-13 20:15:29 +00002004 /* Header of display. */
hassoa94434b2003-05-25 17:10:12 +00002005 vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
2006 "Sub-codes:%s"
2007 " (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
2008 " (i) - interface, (a/S) - aggregated/Suppressed%s%s"
2009 " Network Next Hop Via Metric Tag Time%s",
2010 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
paul718e3742002-12-13 20:15:29 +00002011 VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2012
2013 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2014 {
2015 if ((aggregate = rp->aggregate) != NULL)
2016 {
2017 p = (struct prefix_ipv6 *) &rp->p;
2018
2019#ifdef DEBUG
hassoa94434b2003-05-25 17:10:12 +00002020 len = vty_out (vty, "R(a) %d/%d %s/%d ",
paul718e3742002-12-13 20:15:29 +00002021 aggregate->count, aggregate->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002022 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002023#else
hassoa94434b2003-05-25 17:10:12 +00002024 len = vty_out (vty, "R(a) %s/%d ",
hasso3a2ce6a2005-04-08 01:30:51 +00002025 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002026#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002027 vty_out (vty, "%s", VTY_NEWLINE);
2028 vty_out (vty, "%*s", 18, " ");
paul718e3742002-12-13 20:15:29 +00002029
hassoa94434b2003-05-25 17:10:12 +00002030 vty_out (vty, "%*s", 28, " ");
2031 vty_out (vty, "self %2d %3d%s", aggregate->metric,
paul718e3742002-12-13 20:15:29 +00002032 aggregate->tag,
2033 VTY_NEWLINE);
2034 }
2035
2036 if ((rinfo = rp->info) != NULL)
2037 {
2038 p = (struct prefix_ipv6 *) &rp->p;
2039
2040#ifdef DEBUG
ajsf52d13c2005-10-01 17:38:06 +00002041 len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
2042 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002043 ripng_route_subtype_print(rinfo),
paul718e3742002-12-13 20:15:29 +00002044 rinfo->suppress,
hasso3a2ce6a2005-04-08 01:30:51 +00002045 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002046#else
ajsf52d13c2005-10-01 17:38:06 +00002047 len = vty_out (vty, "%c(%s) %s/%d ",
2048 zebra_route_char(rinfo->type),
hassoa94434b2003-05-25 17:10:12 +00002049 ripng_route_subtype_print(rinfo),
hasso3a2ce6a2005-04-08 01:30:51 +00002050 inet6_ntoa (p->prefix), p->prefixlen);
paul718e3742002-12-13 20:15:29 +00002051#endif /* DEBUG */
hassoa94434b2003-05-25 17:10:12 +00002052 vty_out (vty, "%s", VTY_NEWLINE);
2053 vty_out (vty, "%*s", 18, " ");
hasso3a2ce6a2005-04-08 01:30:51 +00002054 len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
paul718e3742002-12-13 20:15:29 +00002055
hassoa94434b2003-05-25 17:10:12 +00002056 len = 28 - len;
2057 if (len > 0)
2058 len = vty_out (vty, "%*s", len, " ");
2059
2060 /* from */
2061 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2062 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2063 {
2064 len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
2065 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2066 {
2067 len = vty_out (vty, "kill");
2068 } else
2069 len = vty_out (vty, "self");
2070
2071 len = 9 - len;
paul718e3742002-12-13 20:15:29 +00002072 if (len > 0)
2073 vty_out (vty, "%*s", len, " ");
2074
hassoa94434b2003-05-25 17:10:12 +00002075 vty_out (vty, " %2d %3d ",
2076 rinfo->metric, rinfo->tag);
paul718e3742002-12-13 20:15:29 +00002077
hassoa94434b2003-05-25 17:10:12 +00002078 /* time */
2079 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2080 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2081 {
2082 /* RTE from remote RIP routers */
paul718e3742002-12-13 20:15:29 +00002083 ripng_vty_out_uptime (vty, rinfo);
hassoa94434b2003-05-25 17:10:12 +00002084 } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2085 {
2086 /* poisonous reversed routes (gc) */
2087 ripng_vty_out_uptime (vty, rinfo);
2088 }
paul718e3742002-12-13 20:15:29 +00002089
2090 vty_out (vty, "%s", VTY_NEWLINE);
2091 }
2092 }
2093
2094 return CMD_SUCCESS;
2095}
2096
hassoa94434b2003-05-25 17:10:12 +00002097DEFUN (show_ipv6_ripng_status,
2098 show_ipv6_ripng_status_cmd,
2099 "show ipv6 ripng status",
2100 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002101 IPV6_STR
hassoa94434b2003-05-25 17:10:12 +00002102 "Show RIPng routes\n"
2103 "IPv6 routing protocol process parameters and statistics\n")
2104{
hasso52dc7ee2004-09-23 19:18:23 +00002105 struct listnode *node;
paul1eb8ef22005-04-07 07:30:20 +00002106 struct interface *ifp;
hassoa94434b2003-05-25 17:10:12 +00002107
2108 if (! ripng)
2109 return CMD_SUCCESS;
2110
2111 vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2112 vty_out (vty, " Sending updates every %ld seconds with +/-50%%,",
2113 ripng->update_time);
Vincent Jardin6dfa8272007-04-12 07:43:49 +00002114 vty_out (vty, " next due in %lu seconds%s",
2115 thread_timer_remain_second (ripng->t_update),
hassoa94434b2003-05-25 17:10:12 +00002116 VTY_NEWLINE);
2117 vty_out (vty, " Timeout after %ld seconds,", ripng->timeout_time);
2118 vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2119 VTY_NEWLINE);
2120
2121 /* Filtering status show. */
2122 config_show_distribute (vty);
2123
2124 /* Default metric information. */
2125 vty_out (vty, " Default redistribution metric is %d%s",
2126 ripng->default_metric, VTY_NEWLINE);
2127
2128 /* Redistribute information. */
2129 vty_out (vty, " Redistributing:");
2130 ripng_redistribute_write (vty, 0);
2131 vty_out (vty, "%s", VTY_NEWLINE);
2132
2133 vty_out (vty, " Default version control: send version %d,", ripng->version);
2134 vty_out (vty, " receive version %d %s", ripng->version,
2135 VTY_NEWLINE);
2136
2137 vty_out (vty, " Interface Send Recv%s", VTY_NEWLINE);
2138
paul1eb8ef22005-04-07 07:30:20 +00002139 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
hassoa94434b2003-05-25 17:10:12 +00002140 {
2141 struct ripng_interface *ri;
paul1eb8ef22005-04-07 07:30:20 +00002142
hassoa94434b2003-05-25 17:10:12 +00002143 ri = ifp->info;
2144
2145 if (ri->enable_network || ri->enable_interface)
2146 {
2147
2148 vty_out (vty, " %-17s%-3d %-3d%s", ifp->name,
2149 ripng->version,
2150 ripng->version,
2151 VTY_NEWLINE);
2152 }
2153 }
2154
2155 vty_out (vty, " Routing for Networks:%s", VTY_NEWLINE);
2156 ripng_network_write (vty, 0);
2157
2158 vty_out (vty, " Routing Information Sources:%s", VTY_NEWLINE);
2159 vty_out (vty, " Gateway BadPackets BadRoutes Distance Last Update%s", VTY_NEWLINE);
2160 ripng_peer_display (vty);
2161
2162 return CMD_SUCCESS;
2163}
2164
paul718e3742002-12-13 20:15:29 +00002165DEFUN (router_ripng,
2166 router_ripng_cmd,
2167 "router ripng",
2168 "Enable a routing process\n"
2169 "Make RIPng instance command\n")
2170{
2171 int ret;
2172
2173 vty->node = RIPNG_NODE;
2174
2175 if (!ripng)
2176 {
2177 ret = ripng_create ();
2178
2179 /* Notice to user we couldn't create RIPng. */
2180 if (ret < 0)
2181 {
2182 zlog_warn ("can't create RIPng");
2183 return CMD_WARNING;
2184 }
2185 }
2186
2187 return CMD_SUCCESS;
2188}
2189
hassoa94434b2003-05-25 17:10:12 +00002190DEFUN (no_router_ripng,
2191 no_router_ripng_cmd,
2192 "no router ripng",
2193 NO_STR
2194 "Enable a routing process\n"
2195 "Make RIPng instance command\n")
2196{
2197 if(ripng)
2198 ripng_clean();
2199 return CMD_SUCCESS;
2200}
2201
paul718e3742002-12-13 20:15:29 +00002202DEFUN (ripng_route,
2203 ripng_route_cmd,
2204 "route IPV6ADDR",
2205 "Static route setup\n"
2206 "Set static RIPng route announcement\n")
2207{
2208 int ret;
2209 struct prefix_ipv6 p;
2210 struct route_node *rp;
2211
2212 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2213 if (ret <= 0)
2214 {
2215 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2216 return CMD_WARNING;
2217 }
2218 apply_mask_ipv6 (&p);
2219
2220 rp = route_node_get (ripng->route, (struct prefix *) &p);
2221 if (rp->info)
2222 {
2223 vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2224 route_unlock_node (rp);
2225 return CMD_WARNING;
2226 }
2227 rp->info = (void *)1;
2228
hassoa94434b2003-05-25 17:10:12 +00002229 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL);
paul718e3742002-12-13 20:15:29 +00002230
2231 return CMD_SUCCESS;
2232}
2233
2234DEFUN (no_ripng_route,
2235 no_ripng_route_cmd,
2236 "no route IPV6ADDR",
2237 NO_STR
2238 "Static route setup\n"
2239 "Delete static RIPng route announcement\n")
2240{
2241 int ret;
2242 struct prefix_ipv6 p;
2243 struct route_node *rp;
2244
2245 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2246 if (ret <= 0)
2247 {
2248 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2249 return CMD_WARNING;
2250 }
2251 apply_mask_ipv6 (&p);
2252
2253 rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2254 if (! rp)
2255 {
2256 vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2257 return CMD_WARNING;
2258 }
2259
2260 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2261 route_unlock_node (rp);
2262
2263 rp->info = NULL;
2264 route_unlock_node (rp);
2265
2266 return CMD_SUCCESS;
2267}
2268
2269DEFUN (ripng_aggregate_address,
2270 ripng_aggregate_address_cmd,
2271 "aggregate-address X:X::X:X/M",
2272 "Set aggregate RIPng route announcement\n"
2273 "Aggregate network\n")
2274{
2275 int ret;
2276 struct prefix p;
2277 struct route_node *node;
2278
2279 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2280 if (ret <= 0)
2281 {
2282 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2283 return CMD_WARNING;
2284 }
2285
2286 /* Check aggregate alredy exist or not. */
2287 node = route_node_get (ripng->aggregate, &p);
2288 if (node->info)
2289 {
2290 vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2291 route_unlock_node (node);
2292 return CMD_WARNING;
2293 }
2294 node->info = (void *)1;
2295
2296 ripng_aggregate_add (&p);
2297
2298 return CMD_SUCCESS;
2299}
2300
2301DEFUN (no_ripng_aggregate_address,
2302 no_ripng_aggregate_address_cmd,
2303 "no aggregate-address X:X::X:X/M",
2304 NO_STR
2305 "Delete aggregate RIPng route announcement\n"
2306 "Aggregate network")
2307{
2308 int ret;
2309 struct prefix p;
2310 struct route_node *rn;
2311
2312 ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
2313 if (ret <= 0)
2314 {
2315 vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2316 return CMD_WARNING;
2317 }
2318
2319 rn = route_node_lookup (ripng->aggregate, &p);
2320 if (! rn)
2321 {
2322 vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2323 return CMD_WARNING;
2324 }
2325 route_unlock_node (rn);
2326 rn->info = NULL;
2327 route_unlock_node (rn);
2328
2329 ripng_aggregate_delete (&p);
2330
2331 return CMD_SUCCESS;
2332}
2333
2334DEFUN (ripng_default_metric,
2335 ripng_default_metric_cmd,
2336 "default-metric <1-16>",
2337 "Set a metric of redistribute routes\n"
2338 "Default metric\n")
2339{
2340 if (ripng)
2341 {
2342 ripng->default_metric = atoi (argv[0]);
2343 }
2344 return CMD_SUCCESS;
2345}
2346
2347DEFUN (no_ripng_default_metric,
2348 no_ripng_default_metric_cmd,
2349 "no default-metric",
2350 NO_STR
2351 "Set a metric of redistribute routes\n"
2352 "Default metric\n")
2353{
2354 if (ripng)
2355 {
2356 ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2357 }
2358 return CMD_SUCCESS;
2359}
2360
2361ALIAS (no_ripng_default_metric,
2362 no_ripng_default_metric_val_cmd,
2363 "no default-metric <1-16>",
2364 NO_STR
2365 "Set a metric of redistribute routes\n"
2366 "Default metric\n")
2367
2368#if 0
2369/* RIPng update timer setup. */
2370DEFUN (ripng_update_timer,
2371 ripng_update_timer_cmd,
2372 "update-timer SECOND",
2373 "Set RIPng update timer in seconds\n"
2374 "Seconds\n")
2375{
2376 unsigned long update;
2377 char *endptr = NULL;
2378
2379 update = strtoul (argv[0], &endptr, 10);
2380 if (update == ULONG_MAX || *endptr != '\0')
2381 {
2382 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2383 return CMD_WARNING;
2384 }
2385
2386 ripng->update_time = update;
2387
2388 ripng_event (RIPNG_UPDATE_EVENT, 0);
2389 return CMD_SUCCESS;
2390}
2391
2392DEFUN (no_ripng_update_timer,
2393 no_ripng_update_timer_cmd,
2394 "no update-timer SECOND",
2395 NO_STR
2396 "Unset RIPng update timer in seconds\n"
2397 "Seconds\n")
2398{
2399 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2400 ripng_event (RIPNG_UPDATE_EVENT, 0);
2401 return CMD_SUCCESS;
2402}
2403
2404/* RIPng timeout timer setup. */
2405DEFUN (ripng_timeout_timer,
2406 ripng_timeout_timer_cmd,
2407 "timeout-timer SECOND",
2408 "Set RIPng timeout timer in seconds\n"
2409 "Seconds\n")
2410{
2411 unsigned long timeout;
2412 char *endptr = NULL;
2413
2414 timeout = strtoul (argv[0], &endptr, 10);
2415 if (timeout == ULONG_MAX || *endptr != '\0')
2416 {
2417 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2418 return CMD_WARNING;
2419 }
2420
2421 ripng->timeout_time = timeout;
2422
2423 return CMD_SUCCESS;
2424}
2425
2426DEFUN (no_ripng_timeout_timer,
2427 no_ripng_timeout_timer_cmd,
2428 "no timeout-timer SECOND",
2429 NO_STR
2430 "Unset RIPng timeout timer in seconds\n"
2431 "Seconds\n")
2432{
2433 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2434 return CMD_SUCCESS;
2435}
2436
2437/* RIPng garbage timer setup. */
2438DEFUN (ripng_garbage_timer,
2439 ripng_garbage_timer_cmd,
2440 "garbage-timer SECOND",
2441 "Set RIPng garbage timer in seconds\n"
2442 "Seconds\n")
2443{
2444 unsigned long garbage;
2445 char *endptr = NULL;
2446
2447 garbage = strtoul (argv[0], &endptr, 10);
2448 if (garbage == ULONG_MAX || *endptr != '\0')
2449 {
2450 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2451 return CMD_WARNING;
2452 }
2453
2454 ripng->garbage_time = garbage;
2455
2456 return CMD_SUCCESS;
2457}
2458
2459DEFUN (no_ripng_garbage_timer,
2460 no_ripng_garbage_timer_cmd,
2461 "no garbage-timer SECOND",
2462 NO_STR
2463 "Unset RIPng garbage timer in seconds\n"
2464 "Seconds\n")
2465{
2466 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2467 return CMD_SUCCESS;
2468}
2469#endif /* 0 */
2470
2471DEFUN (ripng_timers,
2472 ripng_timers_cmd,
2473 "timers basic <0-65535> <0-65535> <0-65535>",
2474 "RIPng timers setup\n"
2475 "Basic timer\n"
2476 "Routing table update timer value in second. Default is 30.\n"
2477 "Routing information timeout timer. Default is 180.\n"
2478 "Garbage collection timer. Default is 120.\n")
2479{
2480 unsigned long update;
2481 unsigned long timeout;
2482 unsigned long garbage;
2483 char *endptr = NULL;
2484
2485 update = strtoul (argv[0], &endptr, 10);
2486 if (update == ULONG_MAX || *endptr != '\0')
2487 {
2488 vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2489 return CMD_WARNING;
2490 }
2491
2492 timeout = strtoul (argv[1], &endptr, 10);
2493 if (timeout == ULONG_MAX || *endptr != '\0')
2494 {
2495 vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2496 return CMD_WARNING;
2497 }
2498
2499 garbage = strtoul (argv[2], &endptr, 10);
2500 if (garbage == ULONG_MAX || *endptr != '\0')
2501 {
2502 vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2503 return CMD_WARNING;
2504 }
2505
2506 /* Set each timer value. */
2507 ripng->update_time = update;
2508 ripng->timeout_time = timeout;
2509 ripng->garbage_time = garbage;
2510
2511 /* Reset update timer thread. */
2512 ripng_event (RIPNG_UPDATE_EVENT, 0);
2513
2514 return CMD_SUCCESS;
2515}
2516
2517DEFUN (no_ripng_timers,
2518 no_ripng_timers_cmd,
2519 "no timers basic",
2520 NO_STR
2521 "RIPng timers setup\n"
2522 "Basic timer\n")
2523{
2524 /* Set each timer value to the default. */
2525 ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2526 ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2527 ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2528
2529 /* Reset update timer thread. */
2530 ripng_event (RIPNG_UPDATE_EVENT, 0);
2531
2532 return CMD_SUCCESS;
2533}
2534
hassoa94434b2003-05-25 17:10:12 +00002535ALIAS (no_ripng_timers,
2536 no_ripng_timers_val_cmd,
2537 "no timers basic <0-65535> <0-65535> <0-65535>",
2538 NO_STR
2539 "RIPng timers setup\n"
2540 "Basic timer\n"
2541 "Routing table update timer value in second. Default is 30.\n"
2542 "Routing information timeout timer. Default is 180.\n"
2543 "Garbage collection timer. Default is 120.\n")
paul718e3742002-12-13 20:15:29 +00002544
2545DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2546 "show ipv6 protocols",
2547 SHOW_STR
hasso8d0f15f2004-09-11 16:33:28 +00002548 IPV6_STR
paul718e3742002-12-13 20:15:29 +00002549 "Routing protocol information")
2550{
2551 if (! ripng)
2552 return CMD_SUCCESS;
2553
2554 vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2555
2556 vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2557 ripng->update_time, 0,
2558 VTY_NEWLINE);
2559
2560 vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2561 ripng->timeout_time,
2562 ripng->garbage_time,
2563 VTY_NEWLINE);
2564
2565 vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2566 vty_out (vty, "Incoming update filter list for all interfaces is not set");
2567
2568 return CMD_SUCCESS;
2569}
2570
2571/* Please be carefull to use this command. */
paula2c62832003-04-23 17:01:31 +00002572DEFUN (ripng_default_information_originate,
2573 ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002574 "default-information originate",
2575 "Default route information\n"
2576 "Distribute default route\n")
2577{
2578 struct prefix_ipv6 p;
2579
hassoa94434b2003-05-25 17:10:12 +00002580 if (! ripng ->default_information) {
2581 ripng->default_information = 1;
paul718e3742002-12-13 20:15:29 +00002582
hassoa94434b2003-05-25 17:10:12 +00002583 str2prefix_ipv6 ("::/0", &p);
2584 ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL);
2585 }
paul718e3742002-12-13 20:15:29 +00002586
2587 return CMD_SUCCESS;
2588}
2589
paula2c62832003-04-23 17:01:31 +00002590DEFUN (no_ripng_default_information_originate,
2591 no_ripng_default_information_originate_cmd,
paul718e3742002-12-13 20:15:29 +00002592 "no default-information originate",
2593 NO_STR
2594 "Default route information\n"
2595 "Distribute default route\n")
2596{
2597 struct prefix_ipv6 p;
2598
hassoa94434b2003-05-25 17:10:12 +00002599 if (ripng->default_information) {
2600 ripng->default_information = 0;
paul718e3742002-12-13 20:15:29 +00002601
hassoa94434b2003-05-25 17:10:12 +00002602 str2prefix_ipv6 ("::/0", &p);
2603 ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2604 }
paul718e3742002-12-13 20:15:29 +00002605
2606 return CMD_SUCCESS;
2607}
2608
2609/* RIPng configuration write function. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002610static int
paul718e3742002-12-13 20:15:29 +00002611ripng_config_write (struct vty *vty)
2612{
hassoa94434b2003-05-25 17:10:12 +00002613 int ripng_network_write (struct vty *, int);
2614 void ripng_redistribute_write (struct vty *, int);
paul718e3742002-12-13 20:15:29 +00002615 int write = 0;
2616 struct route_node *rp;
2617
2618 if (ripng)
2619 {
2620
2621 /* RIPng router. */
2622 vty_out (vty, "router ripng%s", VTY_NEWLINE);
2623
2624 if (ripng->default_information)
2625 vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2626
hassoa94434b2003-05-25 17:10:12 +00002627 ripng_network_write (vty, 1);
paul718e3742002-12-13 20:15:29 +00002628
2629 /* RIPng default metric configuration */
2630 if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2631 vty_out (vty, " default-metric %d%s",
2632 ripng->default_metric, VTY_NEWLINE);
2633
hassoa94434b2003-05-25 17:10:12 +00002634 ripng_redistribute_write (vty, 1);
2635
2636 /* RIP offset-list configuration. */
2637 config_write_ripng_offset_list (vty);
paul718e3742002-12-13 20:15:29 +00002638
2639 /* RIPng aggregate routes. */
2640 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2641 if (rp->info != NULL)
2642 vty_out (vty, " aggregate-address %s/%d%s",
hasso3a2ce6a2005-04-08 01:30:51 +00002643 inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002644 rp->p.prefixlen,
2645
2646 VTY_NEWLINE);
2647
2648 /* RIPng static routes. */
2649 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2650 if (rp->info != NULL)
hasso3a2ce6a2005-04-08 01:30:51 +00002651 vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
paul718e3742002-12-13 20:15:29 +00002652 rp->p.prefixlen,
2653 VTY_NEWLINE);
2654
2655 /* RIPng timers configuration. */
2656 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2657 ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2658 ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2659 {
2660 vty_out (vty, " timers basic %ld %ld %ld%s",
2661 ripng->update_time,
2662 ripng->timeout_time,
2663 ripng->garbage_time,
2664 VTY_NEWLINE);
2665 }
2666#if 0
2667 if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2668 vty_out (vty, " update-timer %d%s", ripng->update_time,
2669 VTY_NEWLINE);
2670 if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2671 vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2672 VTY_NEWLINE);
2673 if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2674 vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2675 VTY_NEWLINE);
2676#endif /* 0 */
2677
2678 write += config_write_distribute (vty);
2679
2680 write += config_write_if_rmap (vty);
2681
2682 write++;
2683 }
2684 return write;
2685}
2686
2687/* RIPng node structure. */
Stephen Hemminger7fc626d2008-12-01 11:10:34 -08002688static struct cmd_node cmd_ripng_node =
paul718e3742002-12-13 20:15:29 +00002689{
2690 RIPNG_NODE,
2691 "%s(config-router)# ",
2692 1,
2693};
2694
Paul Jakma6ac29a52008-08-15 13:45:30 +01002695static void
paul718e3742002-12-13 20:15:29 +00002696ripng_distribute_update (struct distribute *dist)
2697{
2698 struct interface *ifp;
2699 struct ripng_interface *ri;
2700 struct access_list *alist;
2701 struct prefix_list *plist;
2702
2703 if (! dist->ifname)
2704 return;
2705
2706 ifp = if_lookup_by_name (dist->ifname);
2707 if (ifp == NULL)
2708 return;
2709
2710 ri = ifp->info;
2711
2712 if (dist->list[DISTRIBUTE_IN])
2713 {
2714 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]);
2715 if (alist)
2716 ri->list[RIPNG_FILTER_IN] = alist;
2717 else
2718 ri->list[RIPNG_FILTER_IN] = NULL;
2719 }
2720 else
2721 ri->list[RIPNG_FILTER_IN] = NULL;
2722
2723 if (dist->list[DISTRIBUTE_OUT])
2724 {
2725 alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]);
2726 if (alist)
2727 ri->list[RIPNG_FILTER_OUT] = alist;
2728 else
2729 ri->list[RIPNG_FILTER_OUT] = NULL;
2730 }
2731 else
2732 ri->list[RIPNG_FILTER_OUT] = NULL;
2733
2734 if (dist->prefix[DISTRIBUTE_IN])
2735 {
2736 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]);
2737 if (plist)
2738 ri->prefix[RIPNG_FILTER_IN] = plist;
2739 else
2740 ri->prefix[RIPNG_FILTER_IN] = NULL;
2741 }
2742 else
2743 ri->prefix[RIPNG_FILTER_IN] = NULL;
2744
2745 if (dist->prefix[DISTRIBUTE_OUT])
2746 {
2747 plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]);
2748 if (plist)
2749 ri->prefix[RIPNG_FILTER_OUT] = plist;
2750 else
2751 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2752 }
2753 else
2754 ri->prefix[RIPNG_FILTER_OUT] = NULL;
2755}
hassoa94434b2003-05-25 17:10:12 +00002756
paul718e3742002-12-13 20:15:29 +00002757void
2758ripng_distribute_update_interface (struct interface *ifp)
2759{
2760 struct distribute *dist;
2761
2762 dist = distribute_lookup (ifp->name);
2763 if (dist)
2764 ripng_distribute_update (dist);
2765}
2766
2767/* Update all interface's distribute list. */
Paul Jakma6ac29a52008-08-15 13:45:30 +01002768static void
hassoc9e52be2004-09-26 16:09:34 +00002769ripng_distribute_update_all (struct prefix_list *notused)
paul718e3742002-12-13 20:15:29 +00002770{
2771 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002772 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002773
paul1eb8ef22005-04-07 07:30:20 +00002774 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2775 ripng_distribute_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002776}
hassoc9e52be2004-09-26 16:09:34 +00002777
Paul Jakma6ac29a52008-08-15 13:45:30 +01002778static void
hassoc9e52be2004-09-26 16:09:34 +00002779ripng_distribute_update_all_wrapper (struct access_list *notused)
2780{
2781 ripng_distribute_update_all(NULL);
2782}
hassoa94434b2003-05-25 17:10:12 +00002783
2784/* delete all the added ripng routes. */
2785void
2786ripng_clean()
2787{
2788 int i;
2789 struct route_node *rp;
2790 struct ripng_info *rinfo;
2791
2792 if (ripng) {
2793 /* Clear RIPng routes */
2794 for (rp = route_top (ripng->table); rp; rp = route_next (rp)) {
2795 if ((rinfo = rp->info) != NULL) {
2796 if ((rinfo->type == ZEBRA_ROUTE_RIPNG) &&
2797 (rinfo->sub_type == RIPNG_ROUTE_RTE))
2798 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *)&rp->p,
2799 &rinfo->nexthop, rinfo->metric);
2800
2801 RIPNG_TIMER_OFF (rinfo->t_timeout);
2802 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2803
2804 rp->info = NULL;
2805 route_unlock_node (rp);
2806
2807 ripng_info_free(rinfo);
2808 }
2809 }
2810
2811 /* Cancel the RIPng timers */
2812 RIPNG_TIMER_OFF (ripng->t_update);
2813 RIPNG_TIMER_OFF (ripng->t_triggered_update);
2814 RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2815
2816 /* Cancel the read thread */
2817 if (ripng->t_read) {
2818 thread_cancel (ripng->t_read);
2819 ripng->t_read = NULL;
2820 }
2821
2822 /* Close the RIPng socket */
2823 if (ripng->sock >= 0) {
2824 close(ripng->sock);
2825 ripng->sock = -1;
2826 }
2827
2828 /* Static RIPng route configuration. */
2829 for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2830 if (rp->info) {
2831 rp->info = NULL;
2832 route_unlock_node (rp);
2833 }
2834
2835 /* RIPng aggregated prefixes */
2836 for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2837 if (rp->info) {
2838 rp->info = NULL;
2839 route_unlock_node (rp);
2840 }
2841
2842 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2843 if (ripng->route_map[i].name)
2844 free (ripng->route_map[i].name);
2845
2846 XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2847 XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2848 XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2849
2850 XFREE (MTYPE_RIPNG, ripng);
2851 ripng = NULL;
2852 } /* if (ripng) */
2853
2854 ripng_clean_network();
2855 ripng_passive_interface_clean ();
2856 ripng_offset_clean ();
2857 ripng_interface_clean ();
2858 ripng_redistribute_clean ();
2859}
2860
2861/* Reset all values to the default settings. */
2862void
2863ripng_reset ()
2864{
2865 /* Call ripd related reset functions. */
2866 ripng_debug_reset ();
2867 ripng_route_map_reset ();
2868
2869 /* Call library reset functions. */
2870 vty_reset ();
2871 access_list_reset ();
2872 prefix_list_reset ();
2873
2874 distribute_list_reset ();
2875
2876 ripng_interface_reset ();
2877
2878 ripng_zclient_reset ();
2879}
paul718e3742002-12-13 20:15:29 +00002880
Paul Jakma6ac29a52008-08-15 13:45:30 +01002881static void
paul718e3742002-12-13 20:15:29 +00002882ripng_if_rmap_update (struct if_rmap *if_rmap)
2883{
2884 struct interface *ifp;
2885 struct ripng_interface *ri;
2886 struct route_map *rmap;
2887
2888 ifp = if_lookup_by_name (if_rmap->ifname);
2889 if (ifp == NULL)
2890 return;
2891
2892 ri = ifp->info;
2893
2894 if (if_rmap->routemap[IF_RMAP_IN])
2895 {
2896 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
2897 if (rmap)
2898 ri->routemap[IF_RMAP_IN] = rmap;
2899 else
2900 ri->routemap[IF_RMAP_IN] = NULL;
2901 }
2902 else
2903 ri->routemap[RIPNG_FILTER_IN] = NULL;
2904
2905 if (if_rmap->routemap[IF_RMAP_OUT])
2906 {
2907 rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
2908 if (rmap)
2909 ri->routemap[IF_RMAP_OUT] = rmap;
2910 else
2911 ri->routemap[IF_RMAP_OUT] = NULL;
2912 }
2913 else
2914 ri->routemap[RIPNG_FILTER_OUT] = NULL;
2915}
2916
2917void
2918ripng_if_rmap_update_interface (struct interface *ifp)
2919{
2920 struct if_rmap *if_rmap;
2921
2922 if_rmap = if_rmap_lookup (ifp->name);
2923 if (if_rmap)
2924 ripng_if_rmap_update (if_rmap);
2925}
2926
Paul Jakma6ac29a52008-08-15 13:45:30 +01002927static void
paul718e3742002-12-13 20:15:29 +00002928ripng_routemap_update_redistribute (void)
2929{
2930 int i;
2931
2932 if (ripng)
2933 {
2934 for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2935 {
2936 if (ripng->route_map[i].name)
2937 ripng->route_map[i].map =
2938 route_map_lookup_by_name (ripng->route_map[i].name);
2939 }
2940 }
2941}
2942
Paul Jakma6ac29a52008-08-15 13:45:30 +01002943static void
hasso98b718a2004-10-11 12:57:57 +00002944ripng_routemap_update (const char *unused)
paul718e3742002-12-13 20:15:29 +00002945{
2946 struct interface *ifp;
hasso52dc7ee2004-09-23 19:18:23 +00002947 struct listnode *node;
paul718e3742002-12-13 20:15:29 +00002948
paul1eb8ef22005-04-07 07:30:20 +00002949 for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2950 ripng_if_rmap_update_interface (ifp);
paul718e3742002-12-13 20:15:29 +00002951
2952 ripng_routemap_update_redistribute ();
2953}
2954
2955/* Initialize ripng structure and set commands. */
2956void
2957ripng_init ()
2958{
2959 /* Randomize. */
2960 srand (time (NULL));
2961
2962 /* Install RIPNG_NODE. */
2963 install_node (&cmd_ripng_node, ripng_config_write);
2964
2965 /* Install ripng commands. */
2966 install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002967 install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00002968
2969 install_element (ENABLE_NODE, &show_ipv6_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002970 install_element (ENABLE_NODE, &show_ipv6_ripng_status_cmd);
paul718e3742002-12-13 20:15:29 +00002971
2972 install_element (CONFIG_NODE, &router_ripng_cmd);
hassoa94434b2003-05-25 17:10:12 +00002973 install_element (CONFIG_NODE, &no_router_ripng_cmd);
paul718e3742002-12-13 20:15:29 +00002974
2975 install_default (RIPNG_NODE);
2976 install_element (RIPNG_NODE, &ripng_route_cmd);
2977 install_element (RIPNG_NODE, &no_ripng_route_cmd);
2978 install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
2979 install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
2980
2981 install_element (RIPNG_NODE, &ripng_default_metric_cmd);
2982 install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
2983 install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
2984
2985 install_element (RIPNG_NODE, &ripng_timers_cmd);
2986 install_element (RIPNG_NODE, &no_ripng_timers_cmd);
hassoa94434b2003-05-25 17:10:12 +00002987 install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
paul718e3742002-12-13 20:15:29 +00002988#if 0
2989 install_element (RIPNG_NODE, &ripng_update_timer_cmd);
2990 install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
2991 install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
2992 install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
2993 install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
2994 install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
2995#endif /* 0 */
2996
paula2c62832003-04-23 17:01:31 +00002997 install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
2998 install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
paul718e3742002-12-13 20:15:29 +00002999
3000 ripng_if_init ();
3001 ripng_debug_init ();
3002
3003 /* Access list install. */
3004 access_list_init ();
hassoc9e52be2004-09-26 16:09:34 +00003005 access_list_add_hook (ripng_distribute_update_all_wrapper);
3006 access_list_delete_hook (ripng_distribute_update_all_wrapper);
paul718e3742002-12-13 20:15:29 +00003007
3008 /* Prefix list initialize.*/
3009 prefix_list_init ();
3010 prefix_list_add_hook (ripng_distribute_update_all);
3011 prefix_list_delete_hook (ripng_distribute_update_all);
3012
3013 /* Distribute list install. */
3014 distribute_list_init (RIPNG_NODE);
3015 distribute_list_add_hook (ripng_distribute_update);
3016 distribute_list_delete_hook (ripng_distribute_update);
3017
3018 /* Route-map for interface. */
3019 ripng_route_map_init ();
hassoa94434b2003-05-25 17:10:12 +00003020 ripng_offset_init ();
3021
paul718e3742002-12-13 20:15:29 +00003022 route_map_add_hook (ripng_routemap_update);
3023 route_map_delete_hook (ripng_routemap_update);
3024
hasso0750d212003-05-24 21:41:49 +00003025 if_rmap_init (RIPNG_NODE);
paul718e3742002-12-13 20:15:29 +00003026 if_rmap_hook_add (ripng_if_rmap_update);
3027 if_rmap_hook_delete (ripng_if_rmap_update);
3028}