]> git.sommitrealweird.co.uk Git - quagga-debian.git/blob - ripngd/ripngd.c
824b3a4c3ceca3f205bceb0be5892d641fa59120
[quagga-debian.git] / ripngd / ripngd.c
1 /* 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
24 #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"
37 #include "if_rmap.h"
38 #include "privs.h"
39
40 #include "ripngd/ripngd.h"
41 #include "ripngd/ripng_route.h"
42 #include "ripngd/ripng_debug.h"
43 #include "ripngd/ripng_nexthop.h"
44
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. */
48 struct ripng *ripng = NULL;
49
50 enum
51 {
52   ripng_all_route,
53   ripng_changed_route,
54 };
55
56 extern struct zebra_privs_t ripngd_privs;
57
58 /* Prototypes. */
59 void
60 ripng_output_process (struct interface *, struct sockaddr_in6 *, int);
61
62 int
63 ripng_triggered_update (struct thread *);
64
65 /* RIPng next hop specification. */
66 struct 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 };
75
76 static int
77 ripng_route_rte (struct ripng_info *rinfo)
78 {
79   return (rinfo->type == ZEBRA_ROUTE_RIPNG && rinfo->sub_type == RIPNG_ROUTE_RTE);
80 }
81
82 /* Allocate new ripng information. */
83 struct ripng_info *
84 ripng_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. */
93 void
94 ripng_info_free (struct ripng_info *rinfo)
95 {
96   XFREE (MTYPE_RIPNG_ROUTE, rinfo);
97 }
98
99 /* Create ripng socket. */
100 static int 
101 ripng_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 #ifdef IPTOS_PREC_INTERNETCONTROL
121   ret = setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL);
122   if (ret < 0)
123     return ret;
124 #endif
125   ret = setsockopt_ipv6_multicast_hops (sock, 255);
126   if (ret < 0)
127     return ret;
128   ret = setsockopt_ipv6_multicast_loop (sock, 0);
129   if (ret < 0)
130     return ret;
131   ret = setsockopt_ipv6_hoplimit (sock, 1);
132   if (ret < 0)
133     return ret;
134
135   memset (&ripaddr, 0, sizeof (ripaddr));
136   ripaddr.sin6_family = AF_INET6;
137 #ifdef SIN6_LEN
138   ripaddr.sin6_len = sizeof (struct sockaddr_in6);
139 #endif /* SIN6_LEN */
140   ripaddr.sin6_port = htons (RIPNG_PORT_DEFAULT);
141
142   if (ripngd_privs.change (ZPRIVS_RAISE))
143     zlog_err ("ripng_make_socket: could not raise privs");
144   
145   ret = bind (sock, (struct sockaddr *) &ripaddr, sizeof (ripaddr));
146   if (ret < 0)
147   {
148     zlog (NULL, LOG_ERR, "Can't bind ripng socket: %s.", safe_strerror (errno));
149     if (ripngd_privs.change (ZPRIVS_LOWER))
150       zlog_err ("ripng_make_socket: could not lower privs");
151     return ret;
152   }
153   if (ripngd_privs.change (ZPRIVS_LOWER))
154     zlog_err ("ripng_make_socket: could not lower privs");
155   return sock;
156 }
157
158 /* Send RIPng packet. */
159 int
160 ripng_send_packet (caddr_t buf, int bufsize, struct sockaddr_in6 *to, 
161                    struct interface *ifp)
162 {
163   int ret;
164   struct msghdr msg;
165   struct iovec iov;
166   struct cmsghdr  *cmsgptr;
167   char adata [256];
168   struct in6_pktinfo *pkt;
169   struct sockaddr_in6 addr;
170
171   if (IS_RIPNG_DEBUG_SEND) {
172     if (to)
173       zlog_debug ("send to %s", inet6_ntoa (to->sin6_addr));
174     zlog_debug ("  send interface %s", ifp->name);
175     zlog_debug ("  send packet size %d", bufsize);
176   }
177
178   memset (&addr, 0, sizeof (struct sockaddr_in6));
179   addr.sin6_family = AF_INET6;
180 #ifdef SIN6_LEN
181   addr.sin6_len = sizeof (struct sockaddr_in6);
182 #endif /* SIN6_LEN */
183   addr.sin6_flowinfo = htonl (RIPNG_PRIORITY_DEFAULT);
184
185   /* When destination is specified. */
186   if (to != NULL)
187     {
188       addr.sin6_addr = to->sin6_addr;
189       addr.sin6_port = to->sin6_port;
190     }
191   else
192     {
193       inet_pton(AF_INET6, RIPNG_GROUP, &addr.sin6_addr);
194       addr.sin6_port = htons (RIPNG_PORT_DEFAULT);
195     }
196
197   msg.msg_name = (void *) &addr;
198   msg.msg_namelen = sizeof (struct sockaddr_in6);
199   msg.msg_iov = &iov;
200   msg.msg_iovlen = 1;
201   msg.msg_control = (void *) adata;
202   msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
203
204   iov.iov_base = buf;
205   iov.iov_len = bufsize;
206
207   cmsgptr = (struct cmsghdr *)adata;
208   cmsgptr->cmsg_len = CMSG_LEN(sizeof (struct in6_pktinfo));
209   cmsgptr->cmsg_level = IPPROTO_IPV6;
210   cmsgptr->cmsg_type = IPV6_PKTINFO;
211
212   pkt = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
213   memset (&pkt->ipi6_addr, 0, sizeof (struct in6_addr));
214   pkt->ipi6_ifindex = ifp->ifindex;
215
216   ret = sendmsg (ripng->sock, &msg, 0);
217
218   if (ret < 0) {
219     if (to)
220       zlog_err ("RIPng send fail on %s to %s: %s", ifp->name, 
221                 inet6_ntoa (to->sin6_addr), safe_strerror (errno));
222     else
223       zlog_err ("RIPng send fail on %s: %s", ifp->name, safe_strerror (errno));
224   }
225
226   return ret;
227 }
228
229 /* Receive UDP RIPng packet from socket. */
230 static int
231 ripng_recv_packet (int sock, u_char *buf, int bufsize,
232                    struct sockaddr_in6 *from, ifindex_t *ifindex, 
233                    int *hoplimit)
234 {
235   int ret;
236   struct msghdr msg;
237   struct iovec iov;
238   struct cmsghdr  *cmsgptr;
239   struct in6_addr dst = { .s6_addr = { 0 } };
240
241   /* Ancillary data.  This store cmsghdr and in6_pktinfo.  But at this
242      point I can't determine size of cmsghdr */
243   char adata[1024];
244
245   /* Fill in message and iovec. */
246   msg.msg_name = (void *) from;
247   msg.msg_namelen = sizeof (struct sockaddr_in6);
248   msg.msg_iov = &iov;
249   msg.msg_iovlen = 1;
250   msg.msg_control = (void *) adata;
251   msg.msg_controllen = sizeof adata;
252   iov.iov_base = buf;
253   iov.iov_len = bufsize;
254
255   /* If recvmsg fail return minus value. */
256   ret = recvmsg (sock, &msg, 0);
257   if (ret < 0)
258     return ret;
259
260   for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
261        cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) 
262     {
263       /* I want interface index which this packet comes from. */
264       if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
265           cmsgptr->cmsg_type == IPV6_PKTINFO) 
266         {
267           struct in6_pktinfo *ptr;
268           
269           ptr = (struct in6_pktinfo *) CMSG_DATA (cmsgptr);
270           *ifindex = ptr->ipi6_ifindex;
271           dst = ptr->ipi6_addr;
272
273           if (*ifindex == 0)
274             zlog_warn ("Interface index returned by IPV6_PKTINFO is zero");
275         }
276
277       /* Incoming packet's multicast hop limit. */
278       if (cmsgptr->cmsg_level == IPPROTO_IPV6 &&
279           cmsgptr->cmsg_type == IPV6_HOPLIMIT)
280         {
281           int *phoplimit = (int *) CMSG_DATA (cmsgptr);
282           *hoplimit = *phoplimit;
283         }
284     }
285
286   /* Hoplimit check shold be done when destination address is
287      multicast address. */
288   if (! IN6_IS_ADDR_MULTICAST (&dst))
289     *hoplimit = -1;
290
291   return ret;
292 }
293
294 /* Dump rip packet */
295 void
296 ripng_packet_dump (struct ripng_packet *packet, int size, const char *sndrcv)
297 {
298   caddr_t lim;
299   struct rte *rte;
300   const char *command_str;
301
302   /* Set command string. */
303   if (packet->command == RIPNG_REQUEST)
304     command_str = "request";
305   else if (packet->command == RIPNG_RESPONSE)
306     command_str = "response";
307   else
308     command_str = "unknown";
309
310   /* Dump packet header. */
311   zlog_debug ("%s %s version %d packet size %d", 
312              sndrcv, command_str, packet->version, size);
313
314   /* Dump each routing table entry. */
315   rte = packet->rte;
316
317   for (lim = (caddr_t) packet + size; (caddr_t) rte < lim; rte++)
318     {
319       if (rte->metric == RIPNG_METRIC_NEXTHOP)
320         zlog_debug ("  nexthop %s/%d", inet6_ntoa (rte->addr), rte->prefixlen);
321       else
322         zlog_debug ("  %s/%d metric %d tag %d", 
323                    inet6_ntoa (rte->addr), rte->prefixlen, 
324                    rte->metric, ntohs (rte->tag));
325     }
326 }
327
328 /* RIPng next hop address RTE (Route Table Entry). */
329 static void
330 ripng_nexthop_rte (struct rte *rte,
331                    struct sockaddr_in6 *from,
332                    struct ripng_nexthop *nexthop)
333 {
334   char buf[INET6_BUFSIZ];
335
336   /* Logging before checking RTE. */
337   if (IS_RIPNG_DEBUG_RECV)
338     zlog_debug ("RIPng nexthop RTE address %s tag %d prefixlen %d",
339                inet6_ntoa (rte->addr), ntohs (rte->tag), rte->prefixlen);
340
341   /* RFC2080 2.1.1 Next Hop: 
342    The route tag and prefix length in the next hop RTE must be
343    set to zero on sending and ignored on receiption.  */
344   if (ntohs (rte->tag) != 0)
345     zlog_warn ("RIPng nexthop RTE with non zero tag value %d from %s",
346                ntohs (rte->tag), inet6_ntoa (from->sin6_addr));
347
348   if (rte->prefixlen != 0)
349     zlog_warn ("RIPng nexthop RTE with non zero prefixlen value %d from %s",
350                rte->prefixlen, inet6_ntoa (from->sin6_addr));
351
352   /* Specifying a value of 0:0:0:0:0:0:0:0 in the prefix field of a
353    next hop RTE indicates that the next hop address should be the
354    originator of the RIPng advertisement.  An address specified as a
355    next hop must be a link-local address.  */
356   if (IN6_IS_ADDR_UNSPECIFIED (&rte->addr))
357     {
358       nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
359       memset (&nexthop->address, 0, sizeof (struct in6_addr));
360       return;
361     }
362
363   if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
364     {
365       nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
366       IPV6_ADDR_COPY (&nexthop->address, &rte->addr);
367       return;
368     }
369
370   /* The purpose of the next hop RTE is to eliminate packets being
371    routed through extra hops in the system.  It is particularly useful
372    when RIPng is not being run on all of the routers on a network.
373    Note that next hop RTE is "advisory".  That is, if the provided
374    information is ignored, a possibly sub-optimal, but absolutely
375    valid, route may be taken.  If the received next hop address is not
376    a link-local address, it should be treated as 0:0:0:0:0:0:0:0.  */
377   zlog_warn ("RIPng nexthop RTE with non link-local address %s from %s",
378              inet6_ntoa (rte->addr),
379              inet_ntop (AF_INET6, &from->sin6_addr, buf, INET6_BUFSIZ));
380
381   nexthop->flag = RIPNG_NEXTHOP_UNSPEC;
382   memset (&nexthop->address, 0, sizeof (struct in6_addr));
383
384   return;
385 }
386
387 /* If ifp has same link-local address then return 1. */
388 static int
389 ripng_lladdr_check (struct interface *ifp, struct in6_addr *addr)
390 {
391   struct listnode *node;
392   struct connected *connected;
393   struct prefix *p;
394
395   for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
396     {
397       p = connected->address;
398
399       if (p->family == AF_INET6 &&
400           IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6) &&
401           IN6_ARE_ADDR_EQUAL (&p->u.prefix6, addr))
402         return 1;
403     }
404   return 0;
405 }
406
407 /* RIPng route garbage collect timer. */
408 static int
409 ripng_garbage_collect (struct thread *t)
410 {
411   struct ripng_info *rinfo;
412   struct route_node *rp;
413
414   rinfo = THREAD_ARG (t);
415   rinfo->t_garbage_collect = NULL;
416
417   /* Off timeout timer. */
418   RIPNG_TIMER_OFF (rinfo->t_timeout);
419   
420   /* Get route_node pointer. */
421   rp = rinfo->rp;
422
423   /* Unlock route_node. */
424   listnode_delete (rp->info, rinfo);
425   if (list_isempty ((struct list *)rp->info))
426     {
427       list_free (rp->info);
428       rp->info = NULL;
429       route_unlock_node (rp);
430     }
431
432   /* Free RIPng routing information. */
433   ripng_info_free (rinfo);
434
435   return 0;
436 }
437
438 static void ripng_timeout_update (struct ripng_info *rinfo);
439
440 /* Add new route to the ECMP list.
441  * RETURN: the new entry added in the list, or NULL if it is not the first
442  *         entry and ECMP is not allowed.
443  */
444 struct ripng_info *
445 ripng_ecmp_add (struct ripng_info *rinfo_new)
446 {
447   struct route_node *rp = rinfo_new->rp;
448   struct ripng_info *rinfo = NULL;
449   struct list *list = NULL;
450
451   if (rp->info == NULL)
452     rp->info = list_new ();
453   list = (struct list *)rp->info;
454
455   /* If ECMP is not allowed and some entry already exists in the list,
456    * do nothing. */
457   if (listcount (list) && !ripng->ecmp)
458     return NULL;
459
460   rinfo = ripng_info_new ();
461   memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
462   listnode_add (list, rinfo);
463
464   if (ripng_route_rte (rinfo))
465     {
466       ripng_timeout_update (rinfo);
467       ripng_zebra_ipv6_add (rp);
468     }
469
470   ripng_aggregate_increment (rp, rinfo);
471
472   /* Set the route change flag on the first entry. */
473   rinfo = listgetdata (listhead (list));
474   SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
475
476   /* Signal the output process to trigger an update. */
477   ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
478
479   return rinfo;
480 }
481
482 /* Replace the ECMP list with the new route.
483  * RETURN: the new entry added in the list
484  */
485 struct ripng_info *
486 ripng_ecmp_replace (struct ripng_info *rinfo_new)
487 {
488   struct route_node *rp = rinfo_new->rp;
489   struct list *list = (struct list *)rp->info;
490   struct ripng_info *rinfo = NULL, *tmp_rinfo = NULL;
491   struct listnode *node = NULL, *nextnode = NULL;
492
493   if (list == NULL || listcount (list) == 0)
494     return ripng_ecmp_add (rinfo_new);
495
496   /* Get the first entry */
497   rinfo = listgetdata (listhead (list));
498
499   /* Learnt route replaced by a local one. Delete it from zebra. */
500   if (ripng_route_rte (rinfo) && !ripng_route_rte (rinfo_new))
501     if (CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
502       ripng_zebra_ipv6_delete (rp);
503
504   if (rinfo->metric != RIPNG_METRIC_INFINITY)
505     ripng_aggregate_decrement_list (rp, list);
506
507   /* Re-use the first entry, and delete the others. */
508   for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
509     if (tmp_rinfo != rinfo)
510       {
511         RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
512         RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
513         list_delete_node (list, node);
514         ripng_info_free (tmp_rinfo);
515       }
516
517   RIPNG_TIMER_OFF (rinfo->t_timeout);
518   RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
519   memcpy (rinfo, rinfo_new, sizeof (struct ripng_info));
520
521   if (ripng_route_rte (rinfo))
522     {
523       ripng_timeout_update (rinfo);
524       /* The ADD message implies an update. */
525       ripng_zebra_ipv6_add (rp);
526     }
527
528   ripng_aggregate_increment (rp, rinfo);
529
530   /* Set the route change flag. */
531   SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
532
533   /* Signal the output process to trigger an update. */
534   ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
535
536   return rinfo;
537 }
538
539 /* Delete one route from the ECMP list.
540  * RETURN:
541  *  null - the entry is freed, and other entries exist in the list
542  *  the entry - the entry is the last one in the list; its metric is set
543  *              to INFINITY, and the garbage collector is started for it
544  */
545 struct ripng_info *
546 ripng_ecmp_delete (struct ripng_info *rinfo)
547 {
548   struct route_node *rp = rinfo->rp;
549   struct list *list = (struct list *)rp->info;
550
551   RIPNG_TIMER_OFF (rinfo->t_timeout);
552
553   if (rinfo->metric != RIPNG_METRIC_INFINITY)
554     ripng_aggregate_decrement (rp, rinfo);
555
556   if (listcount (list) > 1)
557     {
558       /* Some other ECMP entries still exist. Just delete this entry. */
559       RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
560       listnode_delete (list, rinfo);
561       if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
562         /* The ADD message implies the update. */
563         ripng_zebra_ipv6_add (rp);
564       ripng_info_free (rinfo);
565       rinfo = NULL;
566     }
567   else
568     {
569       assert (rinfo == listgetdata (listhead (list)));
570
571       /* This is the only entry left in the list. We must keep it in
572        * the list for garbage collection time, with INFINITY metric. */
573
574       rinfo->metric = RIPNG_METRIC_INFINITY;
575       RIPNG_TIMER_ON (rinfo->t_garbage_collect,
576                       ripng_garbage_collect, ripng->garbage_time);
577
578       if (ripng_route_rte (rinfo) && CHECK_FLAG (rinfo->flags, RIPNG_RTF_FIB))
579         ripng_zebra_ipv6_delete (rp);
580     }
581
582   /* Set the route change flag on the first entry. */
583   rinfo = listgetdata (listhead (list));
584   SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
585
586   /* Signal the output process to trigger an update. */
587   ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
588
589   return rinfo;
590 }
591
592 /* Timeout RIPng routes. */
593 static int
594 ripng_timeout (struct thread *t)
595 {
596   ripng_ecmp_delete ((struct ripng_info *)THREAD_ARG (t));
597   return 0;
598 }
599
600 static void
601 ripng_timeout_update (struct ripng_info *rinfo)
602 {
603   if (rinfo->metric != RIPNG_METRIC_INFINITY)
604     {
605       RIPNG_TIMER_OFF (rinfo->t_timeout);
606       RIPNG_TIMER_ON (rinfo->t_timeout, ripng_timeout, ripng->timeout_time);
607     }
608 }
609
610 static int
611 ripng_filter (int ripng_distribute, struct prefix_ipv6 *p,
612               struct ripng_interface *ri)
613 {
614   struct distribute *dist;
615   struct access_list *alist;
616   struct prefix_list *plist;
617   int distribute = ripng_distribute == RIPNG_FILTER_OUT ?
618       DISTRIBUTE_V6_OUT : DISTRIBUTE_V6_IN;
619   const char *inout = ripng_distribute == RIPNG_FILTER_OUT ? "out" : "in";
620
621   /* Input distribute-list filtering. */
622   if (ri->list[ripng_distribute])
623     {
624       if (access_list_apply (ri->list[ripng_distribute],
625                              (struct prefix *) p) == FILTER_DENY)
626         {
627           if (IS_RIPNG_DEBUG_PACKET)
628             zlog_debug ("%s/%d filtered by distribute %s",
629                         inet6_ntoa (p->prefix), p->prefixlen, inout);
630           return -1;
631         }
632     }
633   if (ri->prefix[ripng_distribute])
634     {
635       if (prefix_list_apply (ri->prefix[ripng_distribute],
636                              (struct prefix *) p) == PREFIX_DENY)
637         {
638           if (IS_RIPNG_DEBUG_PACKET)
639             zlog_debug ("%s/%d filtered by prefix-list %s",
640                         inet6_ntoa (p->prefix), p->prefixlen, inout);
641           return -1;
642         }
643     }
644
645   /* All interface filter check. */
646   dist = distribute_lookup (NULL);
647   if (dist)
648     {
649       if (dist->list[distribute])
650         {
651           alist = access_list_lookup (AFI_IP6, dist->list[distribute]);
652
653           if (alist)
654             {
655               if (access_list_apply (alist,
656                                      (struct prefix *) p) == FILTER_DENY)
657                 {
658                   if (IS_RIPNG_DEBUG_PACKET)
659                     zlog_debug ("%s/%d filtered by distribute %s",
660                                 inet6_ntoa (p->prefix), p->prefixlen, inout);
661                   return -1;
662                 }
663             }
664         }
665       if (dist->prefix[distribute])
666         {
667           plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]);
668
669           if (plist)
670             {
671               if (prefix_list_apply (plist,
672                                      (struct prefix *) p) == PREFIX_DENY)
673                 {
674                   if (IS_RIPNG_DEBUG_PACKET)
675                     zlog_debug ("%s/%d filtered by prefix-list %s",
676                                 inet6_ntoa (p->prefix), p->prefixlen, inout);
677                   return -1;
678                 }
679             }
680         }
681     }
682   return 0;
683 }
684
685 /* Process RIPng route according to RFC2080. */
686 static void
687 ripng_route_process (struct rte *rte, struct sockaddr_in6 *from,
688                      struct ripng_nexthop *ripng_nexthop,
689                      struct interface *ifp)
690 {
691   int ret;
692   struct prefix_ipv6 p;
693   struct route_node *rp;
694   struct ripng_info *rinfo = NULL, newinfo;
695   struct ripng_interface *ri;
696   struct in6_addr *nexthop;
697   int same = 0;
698   struct list *list = NULL;
699   struct listnode *node = NULL;
700
701   /* Make prefix structure. */
702   memset (&p, 0, sizeof (struct prefix_ipv6));
703   p.family = AF_INET6;
704   /* p.prefix = rte->addr; */
705   IPV6_ADDR_COPY (&p.prefix, &rte->addr);
706   p.prefixlen = rte->prefixlen;
707
708   /* Make sure mask is applied. */
709   /* XXX We have to check the prefix is valid or not before call
710      apply_mask_ipv6. */
711   apply_mask_ipv6 (&p);
712
713   /* Apply input filters. */
714   ri = ifp->info;
715
716   ret = ripng_filter (RIPNG_FILTER_IN, &p, ri);
717   if (ret < 0)
718     return;
719
720   memset (&newinfo, 0, sizeof (newinfo));
721   newinfo.type = ZEBRA_ROUTE_RIPNG;
722   newinfo.sub_type = RIPNG_ROUTE_RTE;
723   if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
724     newinfo.nexthop = ripng_nexthop->address;
725   else
726     newinfo.nexthop = from->sin6_addr;
727   newinfo.from = from->sin6_addr;
728   newinfo.ifindex = ifp->ifindex;
729   newinfo.metric = rte->metric;
730   newinfo.metric_out = rte->metric; /* XXX */
731   newinfo.tag = ntohs (rte->tag);   /* XXX */
732
733   /* Modify entry. */
734   if (ri->routemap[RIPNG_FILTER_IN])
735     {
736       int ret;
737
738       ret = route_map_apply (ri->routemap[RIPNG_FILTER_IN], 
739                              (struct prefix *)&p, RMAP_RIPNG, &newinfo);
740
741       if (ret == RMAP_DENYMATCH)
742         {
743           if (IS_RIPNG_DEBUG_PACKET)
744             zlog_debug ("RIPng %s/%d is filtered by route-map in",
745                        inet6_ntoa (p.prefix), p.prefixlen);
746           return;
747         }
748
749       /* Get back the object */
750       if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS) {
751         if (! IPV6_ADDR_SAME(&newinfo.nexthop, &ripng_nexthop->address) ) {
752           /* the nexthop get changed by the routemap */
753           if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop))
754             ripng_nexthop->address = newinfo.nexthop;
755           else
756             ripng_nexthop->address = in6addr_any;
757         }
758       } else {
759         if (! IPV6_ADDR_SAME(&newinfo.nexthop, &from->sin6_addr) ) {
760           /* the nexthop get changed by the routemap */
761           if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop)) {
762             ripng_nexthop->flag = RIPNG_NEXTHOP_ADDRESS;
763             ripng_nexthop->address = newinfo.nexthop;
764           }
765         }
766       }
767       rte->tag     = htons(newinfo.tag_out); /* XXX */
768       rte->metric  = newinfo.metric_out; /* XXX: the routemap uses the metric_out field */
769     }
770
771   /* Once the entry has been validated, update the metric by
772    * adding the cost of the network on wich the message
773    * arrived. If the result is greater than infinity, use infinity
774    * (RFC2453 Sec. 3.9.2)
775    **/
776  
777   /* Zebra ripngd can handle offset-list in. */
778   ret = ripng_offset_list_apply_in (&p, ifp, &rte->metric);
779
780   /* If offset-list does not modify the metric use interface's
781    * one. */
782   if (! ret)
783     rte->metric += ifp->metric ? ifp->metric : 1;
784
785   if (rte->metric > RIPNG_METRIC_INFINITY)
786     rte->metric = RIPNG_METRIC_INFINITY;
787
788   /* Set nexthop pointer. */
789   if (ripng_nexthop->flag == RIPNG_NEXTHOP_ADDRESS)
790     nexthop = &ripng_nexthop->address;
791   else
792     nexthop = &from->sin6_addr;
793
794   /* Lookup RIPng routing table. */
795   rp = route_node_get (ripng->table, (struct prefix *) &p);
796
797   newinfo.rp = rp;
798   newinfo.nexthop = *nexthop;
799   newinfo.metric = rte->metric;
800   newinfo.tag = ntohs (rte->tag);
801
802   /* Check to see whether there is already RIPng route on the table. */
803   if ((list = rp->info) != NULL)
804     for (ALL_LIST_ELEMENTS_RO (list, node, rinfo))
805       {
806         /* Need to compare with redistributed entry or local entry */
807         if (!ripng_route_rte (rinfo))
808           break;
809
810         if (IPV6_ADDR_SAME (&rinfo->from, &from->sin6_addr) &&
811             IPV6_ADDR_SAME (&rinfo->nexthop, nexthop))
812           break;
813
814         if (!listnextnode (node))
815           {
816             /* Not found in the list */
817
818             if (rte->metric > rinfo->metric)
819               {
820                 /* New route has a greater metric. Discard it. */
821                 route_unlock_node (rp);
822                 return;
823               }
824
825             if (rte->metric < rinfo->metric)
826               /* New route has a smaller metric. Replace the ECMP list
827                * with the new one in below. */
828               break;
829
830             /* Metrics are same. Keep "rinfo" null and the new route
831              * is added in the ECMP list in below. */
832           }
833       }
834
835   if (rinfo)
836     {
837       /* Redistributed route check. */
838       if (rinfo->type != ZEBRA_ROUTE_RIPNG
839           && rinfo->metric != RIPNG_METRIC_INFINITY)
840         {
841           route_unlock_node (rp);
842           return;
843         }
844
845       /* Local static route. */
846       if (rinfo->type == ZEBRA_ROUTE_RIPNG
847           && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
848               (rinfo->sub_type == RIPNG_ROUTE_DEFAULT))
849           && rinfo->metric != RIPNG_METRIC_INFINITY)
850         {
851           route_unlock_node (rp);
852           return;
853         }
854     }
855
856   if (!rinfo)
857     {
858       /* Now, check to see whether there is already an explicit route
859          for the destination prefix.  If there is no such route, add
860          this route to the routing table, unless the metric is
861          infinity (there is no point in adding a route which
862          unusable). */
863       if (rte->metric != RIPNG_METRIC_INFINITY)
864         ripng_ecmp_add (&newinfo);
865     }
866   else
867     {
868       /* If there is an existing route, compare the next hop address
869          to the address of the router from which the datagram came.
870          If this datagram is from the same router as the existing
871          route, reinitialize the timeout.  */
872       same = (IN6_ARE_ADDR_EQUAL (&rinfo->from, &from->sin6_addr) 
873               && (rinfo->ifindex == ifp->ifindex));
874
875       /* Next, compare the metrics.  If the datagram is from the same
876          router as the existing route, and the new metric is different
877          than the old one; or, if the new metric is lower than the old
878          one; do the following actions: */
879       if ((same && rinfo->metric != rte->metric) ||
880           rte->metric < rinfo->metric)
881         {
882           if (listcount (list) == 1)
883             {
884               if (newinfo.metric != RIPNG_METRIC_INFINITY)
885                 ripng_ecmp_replace (&newinfo);
886               else
887                 ripng_ecmp_delete (rinfo);
888             }
889           else
890             {
891               if (newinfo.metric < rinfo->metric)
892                 ripng_ecmp_replace (&newinfo);
893               else /* newinfo.metric > rinfo->metric */
894                 ripng_ecmp_delete (rinfo);
895             }
896         }
897       else /* same & no change */
898         ripng_timeout_update (rinfo);
899
900       /* Unlock tempolary lock of the route. */
901       route_unlock_node (rp);
902     }
903 }
904
905 /* Add redistributed route to RIPng table. */
906 void
907 ripng_redistribute_add (int type, int sub_type, struct prefix_ipv6 *p, 
908                         ifindex_t ifindex, struct in6_addr *nexthop,
909                         route_tag_t tag)
910 {
911   struct route_node *rp;
912   struct ripng_info *rinfo = NULL, newinfo;
913   struct list *list = NULL;
914
915   /* Redistribute route  */
916   if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
917     return;
918   if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
919     return;
920
921   rp = route_node_get (ripng->table, (struct prefix *) p);
922
923   memset (&newinfo, 0, sizeof (struct ripng_info));
924   newinfo.type = type;
925   newinfo.sub_type = sub_type;
926   newinfo.ifindex = ifindex;
927   newinfo.metric = 1;
928   if (tag <= UINT16_MAX) /* RIPng only supports 16 bit tags */
929     newinfo.tag = tag;
930   newinfo.rp = rp;
931   if (nexthop && IN6_IS_ADDR_LINKLOCAL(nexthop))
932     newinfo.nexthop = *nexthop;
933
934   if ((list = rp->info) != NULL && listcount (list) != 0)
935     {
936       rinfo = listgetdata (listhead (list));
937
938       if (rinfo->type == ZEBRA_ROUTE_CONNECT
939           && rinfo->sub_type == RIPNG_ROUTE_INTERFACE
940           && rinfo->metric != RIPNG_METRIC_INFINITY) {
941         route_unlock_node (rp);
942            return;
943       }
944
945       /* Manually configured RIPng route check.
946        * They have the precedence on all the other entries.
947        **/
948       if (rinfo->type == ZEBRA_ROUTE_RIPNG
949           && ((rinfo->sub_type == RIPNG_ROUTE_STATIC) ||
950               (rinfo->sub_type == RIPNG_ROUTE_DEFAULT)) ) {
951         if (type != ZEBRA_ROUTE_RIPNG || ((sub_type != RIPNG_ROUTE_STATIC) &&
952                                           (sub_type != RIPNG_ROUTE_DEFAULT))) {
953           route_unlock_node (rp);
954           return;
955         }
956       }
957
958       rinfo = ripng_ecmp_replace (&newinfo);
959       route_unlock_node (rp);
960     }
961   else
962     rinfo = ripng_ecmp_add (&newinfo);
963
964   if (IS_RIPNG_DEBUG_EVENT) {
965     if (!nexthop)
966       zlog_debug ("Redistribute new prefix %s/%d on the interface %s",
967                  inet6_ntoa(p->prefix), p->prefixlen,
968                  ifindex2ifname(ifindex));
969     else
970       zlog_debug ("Redistribute new prefix %s/%d with nexthop %s on the interface %s",
971                  inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop),
972                  ifindex2ifname(ifindex));
973   }
974
975   ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
976 }
977
978 /* Delete redistributed route to RIPng table. */
979 void
980 ripng_redistribute_delete (int type, int sub_type, struct prefix_ipv6 *p, 
981                            ifindex_t ifindex)
982 {
983   struct route_node *rp;
984   struct ripng_info *rinfo;
985
986   if (IN6_IS_ADDR_LINKLOCAL (&p->prefix))
987     return;
988   if (IN6_IS_ADDR_LOOPBACK (&p->prefix))
989     return;
990
991   rp = route_node_lookup (ripng->table, (struct prefix *) p);
992
993   if (rp)
994     {
995       struct list *list = rp->info;
996
997       if (list != NULL && listcount (list) != 0)
998         {
999           rinfo = listgetdata (listhead (list));
1000           if (rinfo != NULL
1001               && rinfo->type == type
1002               && rinfo->sub_type == sub_type
1003               && rinfo->ifindex == ifindex)
1004             {
1005               /* Perform poisoned reverse. */
1006               rinfo->metric = RIPNG_METRIC_INFINITY;
1007               RIPNG_TIMER_ON (rinfo->t_garbage_collect,
1008                               ripng_garbage_collect, ripng->garbage_time);
1009               RIPNG_TIMER_OFF (rinfo->t_timeout);
1010
1011               /* Aggregate count decrement. */
1012               ripng_aggregate_decrement (rp, rinfo);
1013
1014               rinfo->flags |= RIPNG_RTF_CHANGED;
1015
1016               if (IS_RIPNG_DEBUG_EVENT)
1017                 zlog_debug ("Poisone %s/%d on the interface %s with an "
1018                             "infinity metric [delete]",
1019                             inet6_ntoa (p->prefix), p->prefixlen,
1020                             ifindex2ifname (ifindex));
1021
1022               ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
1023             }
1024         }
1025       route_unlock_node (rp);
1026     }
1027 }
1028
1029 /* Withdraw redistributed route. */
1030 void
1031 ripng_redistribute_withdraw (int type)
1032 {
1033   struct route_node *rp;
1034   struct ripng_info *rinfo = NULL;
1035   struct list *list = NULL;
1036
1037   if (!ripng)
1038     return;
1039   
1040   for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1041     if ((list = rp->info) != NULL)
1042       {
1043         rinfo = listgetdata (listhead (list));
1044         if ((rinfo->type == type)
1045             && (rinfo->sub_type != RIPNG_ROUTE_INTERFACE))
1046           {
1047             /* Perform poisoned reverse. */
1048             rinfo->metric = RIPNG_METRIC_INFINITY;
1049             RIPNG_TIMER_ON (rinfo->t_garbage_collect, 
1050                           ripng_garbage_collect, ripng->garbage_time);
1051             RIPNG_TIMER_OFF (rinfo->t_timeout);
1052
1053             /* Aggregate count decrement. */
1054             ripng_aggregate_decrement (rp, rinfo);
1055
1056             rinfo->flags |= RIPNG_RTF_CHANGED;
1057
1058             if (IS_RIPNG_DEBUG_EVENT) {
1059               struct prefix_ipv6 *p = (struct prefix_ipv6 *) &rp->p;
1060
1061               zlog_debug ("Poisone %s/%d on the interface %s [withdraw]",
1062                          inet6_ntoa(p->prefix), p->prefixlen,
1063                          ifindex2ifname(rinfo->ifindex));
1064             }
1065
1066             ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
1067           }
1068       }
1069 }
1070
1071 /* RIP routing information. */
1072 static void
1073 ripng_response_process (struct ripng_packet *packet, int size, 
1074                         struct sockaddr_in6 *from, struct interface *ifp,
1075                         int hoplimit)
1076 {
1077   caddr_t lim;
1078   struct rte *rte;
1079   struct ripng_nexthop nexthop;
1080
1081   /* RFC2080 2.4.2  Response Messages:
1082    The Response must be ignored if it is not from the RIPng port.  */
1083   if (ntohs (from->sin6_port) != RIPNG_PORT_DEFAULT)
1084     {
1085       zlog_warn ("RIPng packet comes from non RIPng port %d from %s",
1086                  ntohs (from->sin6_port), inet6_ntoa (from->sin6_addr));
1087       ripng_peer_bad_packet (from);
1088       return;
1089     }
1090
1091   /* The datagram's IPv6 source address should be checked to see
1092    whether the datagram is from a valid neighbor; the source of the
1093    datagram must be a link-local address.  */
1094   if (! IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr))
1095    {
1096       zlog_warn ("RIPng packet comes from non link local address %s",
1097                  inet6_ntoa (from->sin6_addr));
1098       ripng_peer_bad_packet (from);
1099       return;
1100     }
1101
1102   /* It is also worth checking to see whether the response is from one
1103    of the router's own addresses.  Interfaces on broadcast networks
1104    may receive copies of their own multicasts immediately.  If a
1105    router processes its own output as new input, confusion is likely,
1106    and such datagrams must be ignored. */
1107   if (ripng_lladdr_check (ifp, &from->sin6_addr))
1108     {
1109       zlog_warn ("RIPng packet comes from my own link local address %s",
1110                  inet6_ntoa (from->sin6_addr));
1111       ripng_peer_bad_packet (from);
1112       return;
1113     }
1114
1115   /* As an additional check, periodic advertisements must have their
1116    hop counts set to 255, and inbound, multicast packets sent from the
1117    RIPng port (i.e. periodic advertisement or triggered update
1118    packets) must be examined to ensure that the hop count is 255. */
1119   if (hoplimit >= 0 && hoplimit != 255)
1120     {
1121       zlog_warn ("RIPng packet comes with non 255 hop count %d from %s",
1122                  hoplimit, inet6_ntoa (from->sin6_addr));
1123       ripng_peer_bad_packet (from);
1124       return;
1125     }
1126
1127   /* Update RIPng peer. */
1128   ripng_peer_update (from, packet->version);
1129   
1130   /* Reset nexthop. */
1131   memset (&nexthop, 0, sizeof (struct ripng_nexthop));
1132   nexthop.flag = RIPNG_NEXTHOP_UNSPEC;
1133
1134   /* Set RTE pointer. */
1135   rte = packet->rte;
1136
1137   for (lim = ((caddr_t) packet) + size; (caddr_t) rte < lim; rte++) 
1138     {
1139       /* First of all, we have to check this RTE is next hop RTE or
1140          not.  Next hop RTE is completely different with normal RTE so
1141          we need special treatment. */
1142       if (rte->metric == RIPNG_METRIC_NEXTHOP)
1143         {
1144           ripng_nexthop_rte (rte, from, &nexthop);
1145           continue;
1146         }
1147
1148       /* RTE information validation. */
1149
1150       /* - is the destination prefix valid (e.g., not a multicast
1151          prefix and not a link-local address) A link-local address
1152          should never be present in an RTE. */
1153       if (IN6_IS_ADDR_MULTICAST (&rte->addr))
1154         {
1155           zlog_warn ("Destination prefix is a multicast address %s/%d [%d]",
1156                      inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
1157           ripng_peer_bad_route (from);
1158           continue;
1159         }
1160       if (IN6_IS_ADDR_LINKLOCAL (&rte->addr))
1161         {
1162           zlog_warn ("Destination prefix is a link-local address %s/%d [%d]",
1163                      inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
1164           ripng_peer_bad_route (from);
1165           continue;
1166         }
1167       if (IN6_IS_ADDR_LOOPBACK (&rte->addr))
1168         {
1169           zlog_warn ("Destination prefix is a loopback address %s/%d [%d]",
1170                      inet6_ntoa (rte->addr), rte->prefixlen, rte->metric);
1171           ripng_peer_bad_route (from);
1172           continue;
1173         }
1174
1175       /* - is the prefix length valid (i.e., between 0 and 128,
1176          inclusive) */
1177       if (rte->prefixlen > 128)
1178         {
1179           zlog_warn ("Invalid prefix length %s/%d from %s%%%s",
1180                      inet6_ntoa (rte->addr), rte->prefixlen,
1181                      inet6_ntoa (from->sin6_addr), ifp->name);
1182           ripng_peer_bad_route (from);
1183           continue;
1184         }
1185
1186       /* - is the metric valid (i.e., between 1 and 16, inclusive) */
1187       if (! (rte->metric >= 1 && rte->metric <= 16))
1188         {
1189           zlog_warn ("Invalid metric %d from %s%%%s", rte->metric,
1190                      inet6_ntoa (from->sin6_addr), ifp->name);
1191           ripng_peer_bad_route (from);
1192           continue;
1193         }
1194
1195       /* Vincent: XXX Should we compute the direclty reachable nexthop
1196        * for our RIPng network ?
1197        **/
1198
1199       /* Routing table updates. */
1200       ripng_route_process (rte, from, &nexthop, ifp);
1201     }
1202 }
1203
1204 /* Response to request message. */
1205 static void
1206 ripng_request_process (struct ripng_packet *packet,int size, 
1207                        struct sockaddr_in6 *from, struct interface *ifp)
1208 {
1209   caddr_t lim;
1210   struct rte *rte;
1211   struct prefix_ipv6 p;
1212   struct route_node *rp;
1213   struct ripng_info *rinfo;
1214   struct ripng_interface *ri;
1215
1216   /* Does not reponse to the requests on the loopback interfaces */
1217   if (if_is_loopback (ifp))
1218     return;
1219
1220   /* Check RIPng process is enabled on this interface. */
1221   ri = ifp->info;
1222   if (! ri->running)
1223     return;
1224
1225   /* When passive interface is specified, suppress responses */
1226   if (ri->passive)
1227     return;
1228
1229   /* RIPng peer update. */
1230   ripng_peer_update (from, packet->version);
1231
1232   lim = ((caddr_t) packet) + size;
1233   rte = packet->rte;
1234
1235   /* The Request is processed entry by entry.  If there are no
1236      entries, no response is given. */
1237   if (lim == (caddr_t) rte)
1238     return;
1239
1240   /* There is one special case.  If there is exactly one entry in the
1241      request, and it has a destination prefix of zero, a prefix length
1242      of zero, and a metric of infinity (i.e., 16), then this is a
1243      request to send the entire routing table.  In that case, a call
1244      is made to the output process to send the routing table to the
1245      requesting address/port. */
1246   if (lim == ((caddr_t) (rte + 1)) &&
1247       IN6_IS_ADDR_UNSPECIFIED (&rte->addr) &&
1248       rte->prefixlen == 0 &&
1249       rte->metric == RIPNG_METRIC_INFINITY)
1250     {   
1251       /* All route with split horizon */
1252       ripng_output_process (ifp, from, ripng_all_route);
1253     }
1254   else
1255     {
1256       /* Except for this special case, processing is quite simple.
1257          Examine the list of RTEs in the Request one by one.  For each
1258          entry, look up the destination in the router's routing
1259          database and, if there is a route, put that route's metric in
1260          the metric field of the RTE.  If there is no explicit route
1261          to the specified destination, put infinity in the metric
1262          field.  Once all the entries have been filled in, change the
1263          command from Request to Response and send the datagram back
1264          to the requestor. */
1265       memset (&p, 0, sizeof (struct prefix_ipv6));
1266       p.family = AF_INET6;
1267
1268       for (; ((caddr_t) rte) < lim; rte++)
1269         {
1270           p.prefix = rte->addr;
1271           p.prefixlen = rte->prefixlen;
1272           apply_mask_ipv6 (&p);
1273           
1274           rp = route_node_lookup (ripng->table, (struct prefix *) &p);
1275
1276           if (rp)
1277             {
1278               rinfo = listgetdata (listhead ((struct list *)rp->info));
1279               rte->metric = rinfo->metric;
1280               route_unlock_node (rp);
1281             }
1282           else
1283             rte->metric = RIPNG_METRIC_INFINITY;
1284         }
1285       packet->command = RIPNG_RESPONSE;
1286
1287       ripng_send_packet ((caddr_t) packet, size, from, ifp);
1288     }
1289 }
1290
1291 /* First entry point of reading RIPng packet. */
1292 static int
1293 ripng_read (struct thread *thread)
1294 {
1295   int len;
1296   int sock;
1297   struct sockaddr_in6 from;
1298   struct ripng_packet *packet;
1299   ifindex_t ifindex = 0;
1300   struct interface *ifp;
1301   int hoplimit = -1;
1302
1303   /* Check ripng is active and alive. */
1304   assert (ripng != NULL);
1305   assert (ripng->sock >= 0);
1306
1307   /* Fetch thread data and set read pointer to empty for event
1308      managing.  `sock' sould be same as ripng->sock. */
1309   sock = THREAD_FD (thread);
1310   ripng->t_read = NULL;
1311
1312   /* Add myself to the next event. */
1313   ripng_event (RIPNG_READ, sock);
1314
1315   /* Read RIPng packet. */
1316   len = ripng_recv_packet (sock, STREAM_DATA (ripng->ibuf), 
1317                            STREAM_SIZE (ripng->ibuf), &from, &ifindex,
1318                            &hoplimit);
1319   if (len < 0) 
1320     {
1321       zlog_warn ("RIPng recvfrom failed: %s.", safe_strerror (errno));
1322       return len;
1323     }
1324
1325   /* Check RTE boundary.  RTE size (Packet length - RIPng header size
1326      (4)) must be multiple size of one RTE size (20). */
1327   if (((len - 4) % 20) != 0)
1328     {
1329       zlog_warn ("RIPng invalid packet size %d from %s", len,
1330                  inet6_ntoa (from.sin6_addr));
1331       ripng_peer_bad_packet (&from);
1332       return 0;
1333     }
1334
1335   packet = (struct ripng_packet *) STREAM_DATA (ripng->ibuf);
1336   ifp = if_lookup_by_index (ifindex);
1337
1338   /* RIPng packet received. */
1339   if (IS_RIPNG_DEBUG_EVENT)
1340     zlog_debug ("RIPng packet received from %s port %d on %s",
1341                inet6_ntoa (from.sin6_addr), ntohs (from.sin6_port), 
1342                ifp ? ifp->name : "unknown");
1343
1344   /* Logging before packet checking. */
1345   if (IS_RIPNG_DEBUG_RECV)
1346     ripng_packet_dump (packet, len, "RECV");
1347
1348   /* Packet comes from unknown interface. */
1349   if (ifp == NULL)
1350     {
1351       zlog_warn ("RIPng packet comes from unknown interface %d", ifindex);
1352       return 0;
1353     }
1354
1355   /* Packet version mismatch checking. */
1356   if (packet->version != ripng->version) 
1357     {
1358       zlog_warn ("RIPng packet version %d doesn't fit to my version %d", 
1359                  packet->version, ripng->version);
1360       ripng_peer_bad_packet (&from);
1361       return 0;
1362     }
1363
1364   /* Process RIPng packet. */
1365   switch (packet->command)
1366     {
1367     case RIPNG_REQUEST:
1368       ripng_request_process (packet, len, &from, ifp);
1369       break;
1370     case RIPNG_RESPONSE:
1371       ripng_response_process (packet, len, &from, ifp, hoplimit);
1372       break;
1373     default:
1374       zlog_warn ("Invalid RIPng command %d", packet->command);
1375       ripng_peer_bad_packet (&from);
1376       break;
1377     }
1378   return 0;
1379 }
1380
1381 /* Walk down the RIPng routing table then clear changed flag. */
1382 static void
1383 ripng_clear_changed_flag (void)
1384 {
1385   struct route_node *rp;
1386   struct ripng_info *rinfo = NULL;
1387   struct list *list = NULL;
1388   struct listnode *listnode = NULL;
1389
1390   for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1391     if ((list = rp->info) != NULL)
1392       for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
1393         {
1394           UNSET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
1395           /* This flag can be set only on the first entry. */
1396           break;
1397         }
1398 }
1399
1400 /* Regular update of RIPng route.  Send all routing formation to RIPng
1401    enabled interface. */
1402 static int
1403 ripng_update (struct thread *t)
1404 {
1405   struct listnode *node;
1406   struct interface *ifp;
1407   struct ripng_interface *ri;
1408
1409   /* Clear update timer thread. */
1410   ripng->t_update = NULL;
1411
1412   /* Logging update event. */
1413   if (IS_RIPNG_DEBUG_EVENT)
1414     zlog_debug ("RIPng update timer expired!");
1415
1416   /* Supply routes to each interface. */
1417   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
1418     {
1419       ri = ifp->info;
1420
1421       if (if_is_loopback (ifp) || ! if_is_up (ifp))
1422         continue;
1423
1424       if (! ri->running)
1425         continue;
1426
1427       /* When passive interface is specified, suppress announce to the
1428          interface. */
1429       if (ri->passive)
1430         continue;
1431
1432 #if RIPNG_ADVANCED
1433       if (ri->ri_send == RIPNG_SEND_OFF)
1434         {
1435           if (IS_RIPNG_DEBUG_EVENT)
1436             zlog (NULL, LOG_DEBUG, 
1437                   "[Event] RIPng send to if %d is suppressed by config",
1438                  ifp->ifindex);
1439           continue;
1440         }
1441 #endif /* RIPNG_ADVANCED */
1442
1443       ripng_output_process (ifp, NULL, ripng_all_route);
1444     }
1445
1446   /* Triggered updates may be suppressed if a regular update is due by
1447      the time the triggered update would be sent. */
1448   if (ripng->t_triggered_interval)
1449     {
1450       thread_cancel (ripng->t_triggered_interval);
1451       ripng->t_triggered_interval = NULL;
1452     }
1453   ripng->trigger = 0;
1454
1455   /* Reset flush event. */
1456   ripng_event (RIPNG_UPDATE_EVENT, 0);
1457
1458   return 0;
1459 }
1460
1461 /* Triggered update interval timer. */
1462 static int
1463 ripng_triggered_interval (struct thread *t)
1464 {
1465   ripng->t_triggered_interval = NULL;
1466
1467   if (ripng->trigger)
1468     {
1469       ripng->trigger = 0;
1470       ripng_triggered_update (t);
1471     }
1472   return 0;
1473 }     
1474
1475 /* Execute triggered update. */
1476 int
1477 ripng_triggered_update (struct thread *t)
1478 {
1479   struct listnode *node;
1480   struct interface *ifp;
1481   struct ripng_interface *ri;
1482   int interval;
1483
1484   ripng->t_triggered_update = NULL;
1485
1486   /* Cancel interval timer. */
1487   if (ripng->t_triggered_interval)
1488     {
1489       thread_cancel (ripng->t_triggered_interval);
1490       ripng->t_triggered_interval = NULL;
1491     }
1492   ripng->trigger = 0;
1493
1494   /* Logging triggered update. */
1495   if (IS_RIPNG_DEBUG_EVENT)
1496     zlog_debug ("RIPng triggered update!");
1497
1498   /* Split Horizon processing is done when generating triggered
1499      updates as well as normal updates (see section 2.6). */
1500   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
1501     {
1502       ri = ifp->info;
1503
1504       if (if_is_loopback (ifp) || ! if_is_up (ifp))
1505         continue;
1506
1507       if (! ri->running)
1508         continue;
1509
1510       /* When passive interface is specified, suppress announce to the
1511          interface. */
1512       if (ri->passive)
1513         continue;
1514
1515       ripng_output_process (ifp, NULL, ripng_changed_route);
1516     }
1517
1518   /* Once all of the triggered updates have been generated, the route
1519      change flags should be cleared. */
1520   ripng_clear_changed_flag ();
1521
1522   /* After a triggered update is sent, a timer should be set for a
1523      random interval between 1 and 5 seconds.  If other changes that
1524      would trigger updates occur before the timer expires, a single
1525      update is triggered when the timer expires. */
1526   interval = (random () % 5) + 1;
1527
1528   ripng->t_triggered_interval = 
1529     thread_add_timer (master, ripng_triggered_interval, NULL, interval);
1530
1531   return 0;
1532 }
1533
1534 /* Write routing table entry to the stream and return next index of
1535    the routing table entry in the stream. */
1536 int
1537 ripng_write_rte (int num, struct stream *s, struct prefix_ipv6 *p,
1538                  struct in6_addr *nexthop, u_int16_t tag, u_char metric)
1539 {
1540   /* RIPng packet header. */
1541   if (num == 0)
1542     {
1543       stream_putc (s, RIPNG_RESPONSE);
1544       stream_putc (s, RIPNG_V1);
1545       stream_putw (s, 0);
1546     }
1547
1548   /* Write routing table entry. */
1549   if (!nexthop)
1550     stream_write (s, (u_char *) &p->prefix, sizeof (struct in6_addr));
1551   else
1552     stream_write (s, (u_char *) nexthop, sizeof (struct in6_addr));
1553   stream_putw (s, tag);
1554   if (p)
1555     stream_putc (s, p->prefixlen);
1556   else
1557     stream_putc (s, 0);
1558   stream_putc (s, metric);
1559
1560   return ++num;
1561 }
1562
1563 /* Send RESPONSE message to specified destination. */
1564 void
1565 ripng_output_process (struct interface *ifp, struct sockaddr_in6 *to,
1566                       int route_type)
1567 {
1568   int ret;
1569   struct route_node *rp;
1570   struct ripng_info *rinfo;
1571   struct ripng_interface *ri;
1572   struct ripng_aggregate *aggregate;
1573   struct prefix_ipv6 *p;
1574   struct list * ripng_rte_list;
1575   struct list *list = NULL;
1576   struct listnode *listnode = NULL;
1577
1578   if (IS_RIPNG_DEBUG_EVENT) {
1579     if (to)
1580       zlog_debug ("RIPng update routes to neighbor %s",
1581                  inet6_ntoa(to->sin6_addr));
1582     else
1583       zlog_debug ("RIPng update routes on interface %s", ifp->name);
1584   }
1585
1586   /* Get RIPng interface. */
1587   ri = ifp->info;
1588  
1589   ripng_rte_list = ripng_rte_new();
1590  
1591   for (rp = route_top (ripng->table); rp; rp = route_next (rp))
1592     {
1593       if ((list = rp->info) != NULL &&
1594           (rinfo = listgetdata (listhead (list))) != NULL &&
1595           rinfo->suppress == 0)
1596         {
1597           /* If no route-map are applied, the RTE will be these following
1598            * informations.
1599            */
1600           p = (struct prefix_ipv6 *) &rp->p;
1601           rinfo->metric_out = rinfo->metric;
1602           rinfo->tag_out    = rinfo->tag;
1603           memset(&rinfo->nexthop_out, 0, sizeof(rinfo->nexthop_out));
1604           /* In order to avoid some local loops,
1605            * if the RIPng route has a nexthop via this interface, keep the nexthop,
1606            * otherwise set it to 0. The nexthop should not be propagated
1607            * beyond the local broadcast/multicast area in order
1608            * to avoid an IGP multi-level recursive look-up.
1609            */
1610           if (rinfo->ifindex == ifp->ifindex)
1611             rinfo->nexthop_out = rinfo->nexthop;
1612
1613           /* Apply output filters. */
1614           ret = ripng_filter (RIPNG_FILTER_OUT, p, ri);
1615           if (ret < 0)
1616             continue;
1617
1618           /* Changed route only output. */
1619           if (route_type == ripng_changed_route &&
1620               (! (rinfo->flags & RIPNG_RTF_CHANGED)))
1621             continue;
1622
1623           /* Split horizon. */
1624           if (ri->split_horizon == RIPNG_SPLIT_HORIZON)
1625           {
1626             /* We perform split horizon for RIPng routes. */
1627             int suppress = 0;
1628             struct ripng_info *tmp_rinfo = NULL;
1629
1630             for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1631               if (tmp_rinfo->type == ZEBRA_ROUTE_RIPNG &&
1632                   tmp_rinfo->ifindex == ifp->ifindex)
1633                 {
1634                   suppress = 1;
1635                   break;
1636                 }
1637             if (suppress)
1638               continue;
1639           }
1640
1641           /* Preparation for route-map. */
1642           rinfo->metric_set = 0;
1643           /* nexthop_out,
1644            * metric_out
1645            * and tag_out are already initialized.
1646            */
1647
1648           /* Interface route-map */
1649           if (ri->routemap[RIPNG_FILTER_OUT])
1650             {
1651               int ret;
1652
1653               ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], 
1654                                      (struct prefix *) p, RMAP_RIPNG, 
1655                                      rinfo);
1656
1657               if (ret == RMAP_DENYMATCH)
1658                 {
1659                   if (IS_RIPNG_DEBUG_PACKET)
1660                     zlog_debug ("RIPng %s/%d is filtered by route-map out",
1661                                inet6_ntoa (p->prefix), p->prefixlen);
1662                   continue;
1663                 }
1664
1665             }
1666
1667           /* Redistribute route-map. */
1668           if (ripng->route_map[rinfo->type].name)
1669             {
1670               int ret;
1671
1672               ret = route_map_apply (ripng->route_map[rinfo->type].map,
1673                                      (struct prefix *) p, RMAP_RIPNG,
1674                                      rinfo);
1675
1676               if (ret == RMAP_DENYMATCH)
1677                 {
1678                   if (IS_RIPNG_DEBUG_PACKET)
1679                     zlog_debug ("RIPng %s/%d is filtered by route-map",
1680                                inet6_ntoa (p->prefix), p->prefixlen);
1681                   continue;
1682                 }
1683             }
1684
1685           /* When the route-map does not set metric. */
1686           if (! rinfo->metric_set)
1687             {
1688               /* If the redistribute metric is set. */
1689               if (ripng->route_map[rinfo->type].metric_config
1690                   && rinfo->metric != RIPNG_METRIC_INFINITY)
1691                 {
1692                   rinfo->metric_out = ripng->route_map[rinfo->type].metric;
1693                 }
1694               else
1695                 {
1696                   /* If the route is not connected or localy generated
1697                      one, use default-metric value */
1698                   if (rinfo->type != ZEBRA_ROUTE_RIPNG
1699                       && rinfo->type != ZEBRA_ROUTE_CONNECT
1700                       && rinfo->metric != RIPNG_METRIC_INFINITY)
1701                     rinfo->metric_out = ripng->default_metric;
1702                 }
1703             }
1704
1705           /* Apply offset-list */
1706           if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
1707             ripng_offset_list_apply_out (p, ifp, &rinfo->metric_out);
1708
1709           if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
1710             rinfo->metric_out = RIPNG_METRIC_INFINITY;
1711
1712           /* Perform split-horizon with poisoned reverse 
1713            * for RIPng routes.
1714            **/
1715           if (ri->split_horizon == RIPNG_SPLIT_HORIZON_POISONED_REVERSE) {
1716             struct ripng_info *tmp_rinfo = NULL;
1717
1718             for (ALL_LIST_ELEMENTS_RO (list, listnode, tmp_rinfo))
1719               if ((tmp_rinfo->type == ZEBRA_ROUTE_RIPNG) &&
1720                    tmp_rinfo->ifindex == ifp->ifindex)
1721                 rinfo->metric_out = RIPNG_METRIC_INFINITY;
1722           }
1723
1724           /* Add RTE to the list */
1725           ripng_rte_add(ripng_rte_list, p, rinfo, NULL);
1726         }
1727
1728       /* Process the aggregated RTE entry */
1729       if ((aggregate = rp->aggregate) != NULL && 
1730           aggregate->count > 0 && 
1731           aggregate->suppress == 0)
1732         {
1733           /* If no route-map are applied, the RTE will be these following
1734            * informations.
1735            */
1736           p = (struct prefix_ipv6 *) &rp->p;
1737           aggregate->metric_set = 0;
1738           aggregate->metric_out = aggregate->metric;
1739           aggregate->tag_out    = aggregate->tag;
1740           memset(&aggregate->nexthop_out, 0, sizeof(aggregate->nexthop_out));
1741
1742           /* Apply output filters.*/
1743           ret = ripng_filter (RIPNG_FILTER_OUT, p, ri);
1744           if (ret < 0)
1745             continue;
1746
1747           /* Interface route-map */
1748           if (ri->routemap[RIPNG_FILTER_OUT])
1749             {
1750               int ret;
1751               struct ripng_info newinfo;
1752
1753               /* let's cast the aggregate structure to ripng_info */
1754               memset (&newinfo, 0, sizeof (struct ripng_info));
1755               /* the nexthop is :: */
1756               newinfo.metric = aggregate->metric;
1757               newinfo.metric_out = aggregate->metric_out;
1758               newinfo.tag = aggregate->tag;
1759               newinfo.tag_out = aggregate->tag_out;
1760
1761               ret = route_map_apply (ri->routemap[RIPNG_FILTER_OUT], 
1762                                      (struct prefix *) p, RMAP_RIPNG, 
1763                                      &newinfo);
1764
1765               if (ret == RMAP_DENYMATCH)
1766                 {
1767                   if (IS_RIPNG_DEBUG_PACKET)
1768                     zlog_debug ("RIPng %s/%d is filtered by route-map out",
1769                                inet6_ntoa (p->prefix), p->prefixlen);
1770                   continue;
1771                 }
1772
1773               aggregate->metric_out = newinfo.metric_out;
1774               aggregate->tag_out = newinfo.tag_out;
1775               if (IN6_IS_ADDR_LINKLOCAL(&newinfo.nexthop_out))
1776                 aggregate->nexthop_out = newinfo.nexthop_out;
1777             }
1778
1779           /* There is no redistribute routemap for the aggregated RTE */
1780
1781           /* Changed route only output. */
1782           /* XXX, vincent, in order to increase time convergence,
1783            * it should be announced if a child has changed.
1784            */
1785           if (route_type == ripng_changed_route)
1786             continue;
1787
1788           /* Apply offset-list */
1789           if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
1790             ripng_offset_list_apply_out (p, ifp, &aggregate->metric_out);
1791
1792           if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
1793             aggregate->metric_out = RIPNG_METRIC_INFINITY;
1794
1795           /* Add RTE to the list */
1796           ripng_rte_add(ripng_rte_list, p, NULL, aggregate);
1797         }
1798
1799     }
1800
1801   /* Flush the list */
1802   ripng_rte_send(ripng_rte_list, ifp, to);
1803   ripng_rte_free(ripng_rte_list);
1804 }
1805
1806 /* Create new RIPng instance and set it to global variable. */
1807 static int
1808 ripng_create (void)
1809 {
1810   /* ripng should be NULL. */
1811   assert (ripng == NULL);
1812
1813   /* Allocaste RIPng instance. */
1814   ripng = XCALLOC (MTYPE_RIPNG, sizeof (struct ripng));
1815
1816   /* Default version and timer values. */
1817   ripng->version = RIPNG_V1;
1818   ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
1819   ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
1820   ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
1821   ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
1822   
1823   /* Make buffer.  */
1824   ripng->ibuf = stream_new (RIPNG_MAX_PACKET_SIZE * 5);
1825   ripng->obuf = stream_new (RIPNG_MAX_PACKET_SIZE);
1826
1827   /* Initialize RIPng routig table. */
1828   ripng->table = route_table_init ();
1829   ripng->route = route_table_init ();
1830   ripng->aggregate = route_table_init ();
1831  
1832   /* Make socket. */
1833   ripng->sock = ripng_make_socket ();
1834   if (ripng->sock < 0)
1835     return ripng->sock;
1836
1837   /* Threads. */
1838   ripng_event (RIPNG_READ, ripng->sock);
1839   ripng_event (RIPNG_UPDATE_EVENT, 1);
1840
1841   return 0;
1842 }
1843
1844 /* Send RIPng request to the interface. */
1845 int
1846 ripng_request (struct interface *ifp)
1847 {
1848   struct rte *rte;
1849   struct ripng_packet ripng_packet;
1850
1851   /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */
1852   if (if_is_loopback(ifp))
1853     return 0;
1854
1855   /* If interface is down, don't send RIP packet. */
1856   if (! if_is_up (ifp))
1857     return 0;
1858
1859   if (IS_RIPNG_DEBUG_EVENT)
1860     zlog_debug ("RIPng send request to %s", ifp->name);
1861
1862   memset (&ripng_packet, 0, sizeof (ripng_packet));
1863   ripng_packet.command = RIPNG_REQUEST;
1864   ripng_packet.version = RIPNG_V1;
1865   rte = ripng_packet.rte;
1866   rte->metric = RIPNG_METRIC_INFINITY;
1867
1868   return ripng_send_packet ((caddr_t) &ripng_packet, sizeof (ripng_packet), 
1869                             NULL, ifp);
1870 }
1871
1872
1873 static int
1874 ripng_update_jitter (int time)
1875 {
1876   return ((random () % (time + 1)) - (time / 2));
1877 }
1878
1879 void
1880 ripng_event (enum ripng_event event, int sock)
1881 {
1882   int jitter = 0;
1883
1884   switch (event)
1885     {
1886     case RIPNG_READ:
1887       if (!ripng->t_read)
1888         ripng->t_read = thread_add_read (master, ripng_read, NULL, sock);
1889       break;
1890     case RIPNG_UPDATE_EVENT:
1891       if (ripng->t_update)
1892         {
1893           thread_cancel (ripng->t_update);
1894           ripng->t_update = NULL;
1895         }
1896       /* Update timer jitter. */
1897       jitter = ripng_update_jitter (ripng->update_time);
1898
1899       ripng->t_update = 
1900         thread_add_timer (master, ripng_update, NULL, 
1901                           sock ? 2 : ripng->update_time + jitter);
1902       break;
1903     case RIPNG_TRIGGERED_UPDATE:
1904       if (ripng->t_triggered_interval)
1905         ripng->trigger = 1;
1906       else if (! ripng->t_triggered_update)
1907         ripng->t_triggered_update = 
1908           thread_add_event (master, ripng_triggered_update, NULL, 0);
1909       break;
1910     default:
1911       break;
1912     }
1913 }
1914
1915
1916 /* Print out routes update time. */
1917 static void
1918 ripng_vty_out_uptime (struct vty *vty, struct ripng_info *rinfo)
1919 {
1920   time_t clock;
1921   struct tm *tm;
1922 #define TIME_BUF 25
1923   char timebuf [TIME_BUF];
1924   struct thread *thread;
1925   
1926   if ((thread = rinfo->t_timeout) != NULL)
1927     {
1928       clock = thread_timer_remain_second (thread);
1929       tm = gmtime (&clock);
1930       strftime (timebuf, TIME_BUF, "%M:%S", tm);
1931       vty_out (vty, "%5s", timebuf);
1932     }
1933   else if ((thread = rinfo->t_garbage_collect) != NULL)
1934     {
1935       clock = thread_timer_remain_second (thread);
1936       tm = gmtime (&clock);
1937       strftime (timebuf, TIME_BUF, "%M:%S", tm);
1938       vty_out (vty, "%5s", timebuf);
1939     }
1940 }
1941
1942 static char *
1943 ripng_route_subtype_print (struct ripng_info *rinfo)
1944 {
1945   static char str[3];
1946   memset(str, 0, 3);
1947
1948   if (rinfo->suppress)
1949     strcat(str, "S");
1950
1951   switch (rinfo->sub_type)
1952     {
1953        case RIPNG_ROUTE_RTE:
1954          strcat(str, "n");
1955          break;
1956        case RIPNG_ROUTE_STATIC:
1957          strcat(str, "s");
1958          break;
1959        case RIPNG_ROUTE_DEFAULT:
1960          strcat(str, "d");
1961          break;
1962        case RIPNG_ROUTE_REDISTRIBUTE:
1963          strcat(str, "r");
1964          break;
1965        case RIPNG_ROUTE_INTERFACE:
1966          strcat(str, "i");
1967          break;
1968        default:
1969          strcat(str, "?");
1970          break;
1971     }
1972  
1973   return str;
1974 }
1975
1976 DEFUN (show_ipv6_ripng,
1977        show_ipv6_ripng_cmd,
1978        "show ipv6 ripng",
1979        SHOW_STR
1980        IPV6_STR
1981        "Show RIPng routes\n")
1982 {
1983   struct route_node *rp;
1984   struct ripng_info *rinfo;
1985   struct ripng_aggregate *aggregate;
1986   struct prefix_ipv6 *p;
1987   struct list *list = NULL;
1988   struct listnode *listnode = NULL;
1989   int len;
1990
1991   if (! ripng)
1992     return CMD_SUCCESS;
1993
1994   /* Header of display. */ 
1995   vty_out (vty, "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP%s"
1996            "Sub-codes:%s"
1997            "      (n) - normal, (s) - static, (d) - default, (r) - redistribute,%s"
1998            "      (i) - interface, (a/S) - aggregated/Suppressed%s%s"
1999            "   Network      Next Hop                      Via     Metric Tag Time%s",
2000            VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
2001            VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
2002   
2003   for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2004     {
2005       if ((aggregate = rp->aggregate) != NULL)
2006         {
2007           p = (struct prefix_ipv6 *) &rp->p;
2008
2009 #ifdef DEBUG
2010           len = vty_out (vty, "R(a) %d/%d %s/%d ",
2011                          aggregate->count, aggregate->suppress,
2012                          inet6_ntoa (p->prefix), p->prefixlen);
2013 #else
2014           len = vty_out (vty, "R(a) %s/%d ", 
2015                          inet6_ntoa (p->prefix), p->prefixlen);
2016 #endif /* DEBUG */
2017           vty_out (vty, "%s", VTY_NEWLINE);
2018           vty_out (vty, "%*s", 18, " ");
2019
2020           vty_out (vty, "%*s", 28, " ");
2021           vty_out (vty, "self      %2d  %3d%s", aggregate->metric,
2022                    aggregate->tag,
2023                    VTY_NEWLINE);
2024         }
2025
2026       if ((list = rp->info) != NULL)
2027         for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2028         {
2029           p = (struct prefix_ipv6 *) &rp->p;
2030
2031 #ifdef DEBUG
2032           len = vty_out (vty, "%c(%s) 0/%d %s/%d ",
2033                          zebra_route_char(rinfo->type),
2034                          ripng_route_subtype_print(rinfo),
2035                          rinfo->suppress,
2036                          inet6_ntoa (p->prefix), p->prefixlen);
2037 #else
2038           len = vty_out (vty, "%c(%s) %s/%d ",
2039                          zebra_route_char(rinfo->type),
2040                          ripng_route_subtype_print(rinfo),
2041                          inet6_ntoa (p->prefix), p->prefixlen);
2042 #endif /* DEBUG */
2043           vty_out (vty, "%s", VTY_NEWLINE);
2044           vty_out (vty, "%*s", 18, " ");
2045           len = vty_out (vty, "%s", inet6_ntoa (rinfo->nexthop));
2046
2047           len = 28 - len;
2048           if (len > 0)
2049             len = vty_out (vty, "%*s", len, " ");
2050
2051           /* from */
2052           if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && 
2053             (rinfo->sub_type == RIPNG_ROUTE_RTE))
2054           {
2055             len = vty_out (vty, "%s", ifindex2ifname(rinfo->ifindex));
2056           } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2057           {
2058             len = vty_out (vty, "kill");
2059           } else
2060             len = vty_out (vty, "self");
2061
2062           len = 9 - len;
2063           if (len > 0)
2064             vty_out (vty, "%*s", len, " ");
2065
2066           vty_out (vty, " %2d  %3d  ",
2067                    rinfo->metric, rinfo->tag);
2068
2069           /* time */
2070           if ((rinfo->type == ZEBRA_ROUTE_RIPNG) && 
2071             (rinfo->sub_type == RIPNG_ROUTE_RTE))
2072           {
2073             /* RTE from remote RIP routers */
2074             ripng_vty_out_uptime (vty, rinfo);
2075           } else if (rinfo->metric == RIPNG_METRIC_INFINITY)
2076           {
2077             /* poisonous reversed routes (gc) */
2078             ripng_vty_out_uptime (vty, rinfo);
2079           }
2080
2081           vty_out (vty, "%s", VTY_NEWLINE);
2082         }
2083     }
2084
2085   return CMD_SUCCESS;
2086 }
2087
2088 DEFUN (show_ipv6_ripng_status,
2089        show_ipv6_ripng_status_cmd,
2090        "show ipv6 ripng status",
2091        SHOW_STR
2092        IPV6_STR
2093        "Show RIPng routes\n"
2094        "IPv6 routing protocol process parameters and statistics\n")
2095 {
2096   struct listnode *node;
2097   struct interface *ifp;
2098
2099   if (! ripng)
2100     return CMD_SUCCESS;
2101
2102   vty_out (vty, "Routing Protocol is \"RIPng\"%s", VTY_NEWLINE);
2103   vty_out (vty, "  Sending updates every %ld seconds with +/-50%%,",
2104            ripng->update_time);
2105   vty_out (vty, " next due in %lu seconds%s",
2106            thread_timer_remain_second (ripng->t_update),
2107            VTY_NEWLINE);
2108   vty_out (vty, "  Timeout after %ld seconds,", ripng->timeout_time);
2109   vty_out (vty, " garbage collect after %ld seconds%s", ripng->garbage_time,
2110            VTY_NEWLINE);
2111
2112   /* Filtering status show. */
2113   config_show_distribute (vty);
2114
2115   /* Default metric information. */
2116   vty_out (vty, "  Default redistribution metric is %d%s",
2117            ripng->default_metric, VTY_NEWLINE);
2118
2119   /* Redistribute information. */
2120   vty_out (vty, "  Redistributing:");
2121   ripng_redistribute_write (vty, 0);
2122   vty_out (vty, "%s", VTY_NEWLINE);
2123
2124   vty_out (vty, "  Default version control: send version %d,", ripng->version);
2125   vty_out (vty, " receive version %d %s", ripng->version,
2126            VTY_NEWLINE);
2127
2128   vty_out (vty, "    Interface        Send  Recv%s", VTY_NEWLINE);
2129
2130   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2131     {
2132       struct ripng_interface *ri;
2133       
2134       ri = ifp->info;
2135
2136       if (ri->enable_network || ri->enable_interface)
2137         {
2138
2139           vty_out (vty, "    %-17s%-3d   %-3d%s", ifp->name,
2140                    ripng->version,
2141                    ripng->version,
2142                    VTY_NEWLINE);
2143         }
2144     }
2145
2146   vty_out (vty, "  Routing for Networks:%s", VTY_NEWLINE);
2147   ripng_network_write (vty, 0);
2148
2149   vty_out (vty, "  Routing Information Sources:%s", VTY_NEWLINE);
2150   vty_out (vty, "    Gateway          BadPackets BadRoutes  Distance Last Update%s", VTY_NEWLINE);
2151   ripng_peer_display (vty);
2152
2153   return CMD_SUCCESS;  
2154 }
2155
2156 DEFUN (router_ripng,
2157        router_ripng_cmd,
2158        "router ripng",
2159        "Enable a routing process\n"
2160        "Make RIPng instance command\n")
2161 {
2162   int ret;
2163
2164   vty->node = RIPNG_NODE;
2165
2166   if (!ripng)
2167     {
2168       ret = ripng_create ();
2169
2170       /* Notice to user we couldn't create RIPng. */
2171       if (ret < 0)
2172         {
2173           zlog_warn ("can't create RIPng");
2174           return CMD_WARNING;
2175         }
2176     }
2177
2178   return CMD_SUCCESS;
2179 }
2180
2181 DEFUN (no_router_ripng,
2182        no_router_ripng_cmd,
2183        "no router ripng",
2184        NO_STR
2185        "Enable a routing process\n"
2186        "Make RIPng instance command\n")
2187 {
2188   if(ripng)
2189     ripng_clean();
2190   return CMD_SUCCESS;
2191 }
2192
2193 DEFUN (ripng_route,
2194        ripng_route_cmd,
2195        "route IPV6ADDR",
2196        "Static route setup\n"
2197        "Set static RIPng route announcement\n")
2198 {
2199   int ret;
2200   struct prefix_ipv6 p;
2201   struct route_node *rp;
2202
2203   ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2204   if (ret <= 0)
2205     {
2206       vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2207       return CMD_WARNING;
2208     }
2209   apply_mask_ipv6 (&p);
2210
2211   rp = route_node_get (ripng->route, (struct prefix *) &p);
2212   if (rp->info)
2213     {
2214       vty_out (vty, "There is already same static route.%s", VTY_NEWLINE);
2215       route_unlock_node (rp);
2216       return CMD_WARNING;
2217     }
2218   rp->info = (void *)1;
2219
2220   ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, NULL, 0);
2221
2222   return CMD_SUCCESS;
2223 }
2224
2225 DEFUN (no_ripng_route,
2226        no_ripng_route_cmd,
2227        "no route IPV6ADDR",
2228        NO_STR
2229        "Static route setup\n"
2230        "Delete static RIPng route announcement\n")
2231 {
2232   int ret;
2233   struct prefix_ipv6 p;
2234   struct route_node *rp;
2235
2236   ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2237   if (ret <= 0)
2238     {
2239       vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2240       return CMD_WARNING;
2241     }
2242   apply_mask_ipv6 (&p);
2243
2244   rp = route_node_lookup (ripng->route, (struct prefix *) &p);
2245   if (! rp)
2246     {
2247       vty_out (vty, "Can't find static route.%s", VTY_NEWLINE);
2248       return CMD_WARNING;
2249     }
2250
2251   ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
2252   route_unlock_node (rp);
2253
2254   rp->info = NULL;
2255   route_unlock_node (rp);
2256
2257   return CMD_SUCCESS;
2258 }
2259
2260 DEFUN (ripng_aggregate_address,
2261        ripng_aggregate_address_cmd,
2262        "aggregate-address X:X::X:X/M",
2263        "Set aggregate RIPng route announcement\n"
2264        "Aggregate network\n")
2265 {
2266   int ret;
2267   struct prefix p;
2268   struct route_node *node;
2269
2270   ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *)&p);
2271   if (ret <= 0)
2272     {
2273       vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2274       return CMD_WARNING;
2275     }
2276
2277   /* Check aggregate alredy exist or not. */
2278   node = route_node_get (ripng->aggregate, &p);
2279   if (node->info)
2280     {
2281       vty_out (vty, "There is already same aggregate route.%s", VTY_NEWLINE);
2282       route_unlock_node (node);
2283       return CMD_WARNING;
2284     }
2285   node->info = (void *)1;
2286
2287   ripng_aggregate_add (&p);
2288
2289   return CMD_SUCCESS;
2290 }
2291
2292 DEFUN (no_ripng_aggregate_address,
2293        no_ripng_aggregate_address_cmd,
2294        "no aggregate-address X:X::X:X/M",
2295        NO_STR
2296        "Delete aggregate RIPng route announcement\n"
2297        "Aggregate network")
2298 {
2299   int ret;
2300   struct prefix p;
2301   struct route_node *rn;
2302
2303   ret = str2prefix_ipv6 (argv[0], (struct prefix_ipv6 *) &p);
2304   if (ret <= 0)
2305     {
2306       vty_out (vty, "Malformed address%s", VTY_NEWLINE);
2307       return CMD_WARNING;
2308     }
2309
2310   rn = route_node_lookup (ripng->aggregate, &p);
2311   if (! rn)
2312     {
2313       vty_out (vty, "Can't find aggregate route.%s", VTY_NEWLINE);
2314       return CMD_WARNING;
2315     }
2316   route_unlock_node (rn);
2317   rn->info = NULL;
2318   route_unlock_node (rn);
2319
2320   ripng_aggregate_delete (&p);
2321
2322   return CMD_SUCCESS;
2323 }
2324
2325 DEFUN (ripng_default_metric,
2326        ripng_default_metric_cmd,
2327        "default-metric <1-16>",
2328        "Set a metric of redistribute routes\n"
2329        "Default metric\n")
2330 {
2331   if (ripng)
2332     {
2333       ripng->default_metric = atoi (argv[0]);
2334     }
2335   return CMD_SUCCESS;
2336 }
2337
2338 DEFUN (no_ripng_default_metric,
2339        no_ripng_default_metric_cmd,
2340        "no default-metric",
2341        NO_STR
2342        "Set a metric of redistribute routes\n"
2343        "Default metric\n")
2344 {
2345   if (ripng)
2346     {
2347       ripng->default_metric = RIPNG_DEFAULT_METRIC_DEFAULT;
2348     }
2349   return CMD_SUCCESS;
2350 }
2351
2352 ALIAS (no_ripng_default_metric,
2353        no_ripng_default_metric_val_cmd,
2354        "no default-metric <1-16>",
2355        NO_STR
2356        "Set a metric of redistribute routes\n"
2357        "Default metric\n")
2358
2359 #if 0
2360 /* RIPng update timer setup. */
2361 DEFUN (ripng_update_timer,
2362        ripng_update_timer_cmd,
2363        "update-timer SECOND",
2364        "Set RIPng update timer in seconds\n"
2365        "Seconds\n")
2366 {
2367   unsigned long update;
2368   char *endptr = NULL;
2369
2370   update = strtoul (argv[0], &endptr, 10);
2371   if (update == ULONG_MAX || *endptr != '\0')
2372     {
2373       vty_out (vty, "update timer value error%s", VTY_NEWLINE);
2374       return CMD_WARNING;
2375     }
2376
2377   ripng->update_time = update;
2378
2379   ripng_event (RIPNG_UPDATE_EVENT, 0);
2380   return CMD_SUCCESS;
2381 }
2382
2383 DEFUN (no_ripng_update_timer,
2384        no_ripng_update_timer_cmd,
2385        "no update-timer SECOND",
2386        NO_STR
2387        "Unset RIPng update timer in seconds\n"
2388        "Seconds\n")
2389 {
2390   ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2391   ripng_event (RIPNG_UPDATE_EVENT, 0);
2392   return CMD_SUCCESS;
2393 }
2394
2395 /* RIPng timeout timer setup. */
2396 DEFUN (ripng_timeout_timer,
2397        ripng_timeout_timer_cmd,
2398        "timeout-timer SECOND",
2399        "Set RIPng timeout timer in seconds\n"
2400        "Seconds\n")
2401 {
2402   unsigned long timeout;
2403   char *endptr = NULL;
2404
2405   timeout = strtoul (argv[0], &endptr, 10);
2406   if (timeout == ULONG_MAX || *endptr != '\0')
2407     {
2408       vty_out (vty, "timeout timer value error%s", VTY_NEWLINE);
2409       return CMD_WARNING;
2410     }
2411
2412   ripng->timeout_time = timeout;
2413
2414   return CMD_SUCCESS;
2415 }
2416
2417 DEFUN (no_ripng_timeout_timer,
2418        no_ripng_timeout_timer_cmd,
2419        "no timeout-timer SECOND",
2420        NO_STR
2421        "Unset RIPng timeout timer in seconds\n"
2422        "Seconds\n")
2423 {
2424   ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2425   return CMD_SUCCESS;
2426 }
2427
2428 /* RIPng garbage timer setup. */
2429 DEFUN (ripng_garbage_timer,
2430        ripng_garbage_timer_cmd,
2431        "garbage-timer SECOND",
2432        "Set RIPng garbage timer in seconds\n"
2433        "Seconds\n")
2434 {
2435   unsigned long garbage;
2436   char *endptr = NULL;
2437
2438   garbage = strtoul (argv[0], &endptr, 10);
2439   if (garbage == ULONG_MAX || *endptr != '\0')
2440     {
2441       vty_out (vty, "garbage timer value error%s", VTY_NEWLINE);
2442       return CMD_WARNING;
2443     }
2444
2445   ripng->garbage_time = garbage;
2446
2447   return CMD_SUCCESS;
2448 }
2449
2450 DEFUN (no_ripng_garbage_timer,
2451        no_ripng_garbage_timer_cmd,
2452        "no garbage-timer SECOND",
2453        NO_STR
2454        "Unset RIPng garbage timer in seconds\n"
2455        "Seconds\n")
2456 {
2457   ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2458   return CMD_SUCCESS;
2459 }
2460 #endif /* 0 */
2461
2462 DEFUN (ripng_timers,
2463        ripng_timers_cmd,
2464        "timers basic <0-65535> <0-65535> <0-65535>",
2465        "RIPng timers setup\n"
2466        "Basic timer\n"
2467        "Routing table update timer value in second. Default is 30.\n"
2468        "Routing information timeout timer. Default is 180.\n"
2469        "Garbage collection timer. Default is 120.\n")
2470 {
2471   unsigned long update;
2472   unsigned long timeout;
2473   unsigned long garbage;
2474
2475   VTY_GET_INTEGER_RANGE("update timer", update, argv[0], 0, 65535);
2476   VTY_GET_INTEGER_RANGE("timeout timer", timeout, argv[1], 0, 65535);
2477   VTY_GET_INTEGER_RANGE("garbage timer", garbage, argv[2], 0, 65535);
2478
2479   /* Set each timer value. */
2480   ripng->update_time = update;
2481   ripng->timeout_time = timeout;
2482   ripng->garbage_time = garbage;
2483
2484   /* Reset update timer thread. */
2485   ripng_event (RIPNG_UPDATE_EVENT, 0);
2486
2487   return CMD_SUCCESS;
2488 }
2489
2490 DEFUN (no_ripng_timers,
2491        no_ripng_timers_cmd,
2492        "no timers basic",
2493        NO_STR
2494        "RIPng timers setup\n"
2495        "Basic timer\n")
2496 {
2497   /* Set each timer value to the default. */
2498   ripng->update_time = RIPNG_UPDATE_TIMER_DEFAULT;
2499   ripng->timeout_time = RIPNG_TIMEOUT_TIMER_DEFAULT;
2500   ripng->garbage_time = RIPNG_GARBAGE_TIMER_DEFAULT;
2501
2502   /* Reset update timer thread. */
2503   ripng_event (RIPNG_UPDATE_EVENT, 0);
2504
2505   return CMD_SUCCESS;
2506 }
2507
2508 ALIAS (no_ripng_timers,
2509        no_ripng_timers_val_cmd,
2510        "no timers basic <0-65535> <0-65535> <0-65535>",
2511        NO_STR
2512        "RIPng timers setup\n"
2513        "Basic timer\n"
2514        "Routing table update timer value in second. Default is 30.\n"
2515        "Routing information timeout timer. Default is 180.\n"
2516        "Garbage collection timer. Default is 120.\n")
2517
2518 DEFUN (show_ipv6_protocols, show_ipv6_protocols_cmd,
2519        "show ipv6 protocols",
2520        SHOW_STR
2521        IPV6_STR
2522        "Routing protocol information")
2523 {
2524   if (! ripng)
2525     return CMD_SUCCESS;
2526
2527   vty_out (vty, "Routing Protocol is \"ripng\"%s", VTY_NEWLINE);
2528   
2529   vty_out (vty, "Sending updates every %ld seconds, next due in %d seconds%s",
2530            ripng->update_time, 0,
2531            VTY_NEWLINE);
2532
2533   vty_out (vty, "Timerout after %ld seconds, garbage correct %ld%s",
2534            ripng->timeout_time,
2535            ripng->garbage_time,
2536            VTY_NEWLINE);
2537
2538   vty_out (vty, "Outgoing update filter list for all interfaces is not set");
2539   vty_out (vty, "Incoming update filter list for all interfaces is not set");
2540
2541   return CMD_SUCCESS;
2542 }
2543
2544 /* Please be carefull to use this command. */
2545 DEFUN (ripng_default_information_originate,
2546        ripng_default_information_originate_cmd,
2547        "default-information originate",
2548        "Default route information\n"
2549        "Distribute default route\n")
2550 {
2551   struct prefix_ipv6 p;
2552
2553   if (! ripng ->default_information) {
2554     ripng->default_information = 1;
2555
2556     str2prefix_ipv6 ("::/0", &p);
2557     ripng_redistribute_add (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0);
2558   }
2559
2560   return CMD_SUCCESS;
2561 }
2562
2563 DEFUN (no_ripng_default_information_originate,
2564        no_ripng_default_information_originate_cmd,
2565        "no default-information originate",
2566        NO_STR
2567        "Default route information\n"
2568        "Distribute default route\n")
2569 {
2570   struct prefix_ipv6 p;
2571
2572   if (ripng->default_information) {
2573     ripng->default_information = 0;
2574
2575     str2prefix_ipv6 ("::/0", &p);
2576     ripng_redistribute_delete (ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0);
2577   }
2578
2579   return CMD_SUCCESS;
2580 }
2581
2582 /* Update ECMP routes to zebra when ECMP is disabled. */
2583 static void
2584 ripng_ecmp_disable (void)
2585 {
2586   struct route_node *rp;
2587   struct ripng_info *rinfo, *tmp_rinfo;
2588   struct list *list;
2589   struct listnode *node, *nextnode;
2590
2591   if (!ripng)
2592     return;
2593
2594   for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2595     if ((list = rp->info) != NULL && listcount (list) > 1)
2596       {
2597         rinfo = listgetdata (listhead (list));
2598         if (!ripng_route_rte (rinfo))
2599           continue;
2600
2601         /* Drop all other entries, except the first one. */
2602         for (ALL_LIST_ELEMENTS (list, node, nextnode, tmp_rinfo))
2603           if (tmp_rinfo != rinfo)
2604             {
2605               RIPNG_TIMER_OFF (tmp_rinfo->t_timeout);
2606               RIPNG_TIMER_OFF (tmp_rinfo->t_garbage_collect);
2607               list_delete_node (list, node);
2608               ripng_info_free (tmp_rinfo);
2609             }
2610
2611         /* Update zebra. */
2612         ripng_zebra_ipv6_add (rp);
2613
2614         /* Set the route change flag. */
2615         SET_FLAG (rinfo->flags, RIPNG_RTF_CHANGED);
2616
2617         /* Signal the output process to trigger an update. */
2618         ripng_event (RIPNG_TRIGGERED_UPDATE, 0);
2619       }
2620 }
2621
2622 DEFUN (ripng_allow_ecmp,
2623        ripng_allow_ecmp_cmd,
2624        "allow-ecmp",
2625        "Allow Equal Cost MultiPath\n")
2626 {
2627   if (ripng->ecmp)
2628     {
2629       vty_out (vty, "ECMP is already enabled.%s", VTY_NEWLINE);
2630       return CMD_WARNING;
2631     }
2632
2633   ripng->ecmp = 1;
2634   zlog_info ("ECMP is enabled.");
2635   return CMD_SUCCESS;
2636 }
2637
2638 DEFUN (no_ripng_allow_ecmp,
2639        no_ripng_allow_ecmp_cmd,
2640        "no allow-ecmp",
2641        NO_STR
2642        "Allow Equal Cost MultiPath\n")
2643 {
2644   if (!ripng->ecmp)
2645     {
2646       vty_out (vty, "ECMP is already disabled.%s", VTY_NEWLINE);
2647       return CMD_WARNING;
2648     }
2649
2650   ripng->ecmp = 0;
2651   zlog_info ("ECMP is disabled.");
2652   ripng_ecmp_disable ();
2653   return CMD_SUCCESS;
2654 }
2655
2656 /* RIPng configuration write function. */
2657 static int
2658 ripng_config_write (struct vty *vty)
2659 {
2660   int ripng_network_write (struct vty *, int);
2661   void ripng_redistribute_write (struct vty *, int);
2662   int write = 0;
2663   struct route_node *rp;
2664
2665   if (ripng)
2666     {
2667
2668       /* RIPng router. */
2669       vty_out (vty, "router ripng%s", VTY_NEWLINE);
2670
2671       if (ripng->default_information)
2672         vty_out (vty, " default-information originate%s", VTY_NEWLINE);
2673
2674       ripng_network_write (vty, 1);
2675
2676       /* RIPng default metric configuration */
2677       if (ripng->default_metric != RIPNG_DEFAULT_METRIC_DEFAULT)
2678         vty_out (vty, " default-metric %d%s",
2679                  ripng->default_metric, VTY_NEWLINE);
2680
2681       ripng_redistribute_write (vty, 1);
2682
2683       /* RIP offset-list configuration. */
2684       config_write_ripng_offset_list (vty);
2685       
2686       /* RIPng aggregate routes. */
2687       for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2688         if (rp->info != NULL)
2689           vty_out (vty, " aggregate-address %s/%d%s", 
2690                    inet6_ntoa (rp->p.u.prefix6),
2691                    rp->p.prefixlen, 
2692
2693                    VTY_NEWLINE);
2694
2695       /* ECMP configuration. */
2696       if (ripng->ecmp)
2697         vty_out (vty, " allow-ecmp%s", VTY_NEWLINE);
2698
2699       /* RIPng static routes. */
2700       for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2701         if (rp->info != NULL)
2702           vty_out (vty, " route %s/%d%s", inet6_ntoa (rp->p.u.prefix6),
2703                    rp->p.prefixlen,
2704                    VTY_NEWLINE);
2705
2706       /* RIPng timers configuration. */
2707       if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT ||
2708           ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT ||
2709           ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2710         {
2711           vty_out (vty, " timers basic %ld %ld %ld%s",
2712                    ripng->update_time,
2713                    ripng->timeout_time,
2714                    ripng->garbage_time,
2715                    VTY_NEWLINE);
2716         }
2717 #if 0
2718       if (ripng->update_time != RIPNG_UPDATE_TIMER_DEFAULT)
2719         vty_out (vty, " update-timer %d%s", ripng->update_time,
2720                  VTY_NEWLINE);
2721       if (ripng->timeout_time != RIPNG_TIMEOUT_TIMER_DEFAULT)
2722         vty_out (vty, " timeout-timer %d%s", ripng->timeout_time,
2723                  VTY_NEWLINE);
2724       if (ripng->garbage_time != RIPNG_GARBAGE_TIMER_DEFAULT)
2725         vty_out (vty, " garbage-timer %d%s", ripng->garbage_time,
2726                  VTY_NEWLINE);
2727 #endif /* 0 */
2728
2729       write += config_write_distribute (vty);
2730
2731       write += config_write_if_rmap (vty);
2732
2733       write++;
2734     }
2735   return write;
2736 }
2737
2738 /* RIPng node structure. */
2739 static struct cmd_node cmd_ripng_node =
2740 {
2741   RIPNG_NODE,
2742   "%s(config-router)# ",
2743   1,
2744 };
2745
2746 static void
2747 ripng_distribute_update (struct distribute *dist)
2748 {
2749   struct interface *ifp;
2750   struct ripng_interface *ri;
2751   struct access_list *alist;
2752   struct prefix_list *plist;
2753
2754   if (! dist->ifname)
2755     return;
2756
2757   ifp = if_lookup_by_name (dist->ifname);
2758   if (ifp == NULL)
2759     return;
2760
2761   ri = ifp->info;
2762
2763   if (dist->list[DISTRIBUTE_V6_IN])
2764     {
2765       alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_IN]);
2766       if (alist)
2767         ri->list[RIPNG_FILTER_IN] = alist;
2768       else
2769         ri->list[RIPNG_FILTER_IN] = NULL;
2770     }
2771   else
2772     ri->list[RIPNG_FILTER_IN] = NULL;
2773
2774   if (dist->list[DISTRIBUTE_V6_OUT])
2775     {
2776       alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_V6_OUT]);
2777       if (alist)
2778         ri->list[RIPNG_FILTER_OUT] = alist;
2779       else
2780         ri->list[RIPNG_FILTER_OUT] = NULL;
2781     }
2782   else
2783     ri->list[RIPNG_FILTER_OUT] = NULL;
2784
2785   if (dist->prefix[DISTRIBUTE_V6_IN])
2786     {
2787       plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_IN]);
2788       if (plist)
2789         ri->prefix[RIPNG_FILTER_IN] = plist;
2790       else
2791         ri->prefix[RIPNG_FILTER_IN] = NULL;
2792     }
2793   else
2794     ri->prefix[RIPNG_FILTER_IN] = NULL;
2795
2796   if (dist->prefix[DISTRIBUTE_V6_OUT])
2797     {
2798       plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_V6_OUT]);
2799       if (plist)
2800         ri->prefix[RIPNG_FILTER_OUT] = plist;
2801       else
2802         ri->prefix[RIPNG_FILTER_OUT] = NULL;
2803     }
2804   else
2805     ri->prefix[RIPNG_FILTER_OUT] = NULL;
2806 }
2807
2808 void
2809 ripng_distribute_update_interface (struct interface *ifp)
2810 {
2811   struct distribute *dist;
2812
2813   dist = distribute_lookup (ifp->name);
2814   if (dist)
2815     ripng_distribute_update (dist);
2816 }
2817
2818 /* Update all interface's distribute list. */
2819 static void
2820 ripng_distribute_update_all (struct prefix_list *notused)
2821 {
2822   struct interface *ifp;
2823   struct listnode *node;
2824
2825   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
2826     ripng_distribute_update_interface (ifp);
2827 }
2828
2829 static void
2830 ripng_distribute_update_all_wrapper (struct access_list *notused)
2831 {
2832   ripng_distribute_update_all(NULL);
2833 }
2834
2835 /* delete all the added ripng routes. */
2836 void
2837 ripng_clean()
2838 {
2839   int i;
2840   struct route_node *rp;
2841   struct ripng_info *rinfo;
2842   struct ripng_aggregate *aggregate;
2843   struct list *list = NULL;
2844   struct listnode *listnode = NULL;
2845
2846   if (ripng) {
2847     /* Clear RIPng routes */
2848     for (rp = route_top (ripng->table); rp; rp = route_next (rp))
2849       {
2850         if ((list = rp->info) != NULL)
2851           {
2852             rinfo = listgetdata (listhead (list));
2853             if (ripng_route_rte (rinfo))
2854               ripng_zebra_ipv6_delete (rp);
2855
2856             for (ALL_LIST_ELEMENTS_RO (list, listnode, rinfo))
2857               {
2858                 RIPNG_TIMER_OFF (rinfo->t_timeout);
2859                 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
2860                 ripng_info_free (rinfo);
2861               }
2862             list_delete (list);
2863             rp->info = NULL;
2864             route_unlock_node (rp);
2865           }
2866
2867         if ((aggregate = rp->aggregate) != NULL)
2868           {
2869             ripng_aggregate_free (aggregate);
2870             rp->aggregate = NULL;
2871             route_unlock_node (rp);
2872           }
2873     }
2874
2875     /* Cancel the RIPng timers */
2876     RIPNG_TIMER_OFF (ripng->t_update);
2877     RIPNG_TIMER_OFF (ripng->t_triggered_update);
2878     RIPNG_TIMER_OFF (ripng->t_triggered_interval);
2879
2880     /* Cancel the read thread */
2881     if (ripng->t_read) {
2882       thread_cancel (ripng->t_read);
2883       ripng->t_read = NULL;
2884     }
2885
2886     /* Close the RIPng socket */
2887     if (ripng->sock >= 0) {
2888       close(ripng->sock);
2889       ripng->sock = -1;
2890     }
2891
2892     /* Static RIPng route configuration. */
2893     for (rp = route_top (ripng->route); rp; rp = route_next (rp))
2894       if (rp->info) {
2895         rp->info = NULL;
2896         route_unlock_node (rp);
2897     }
2898
2899     /* RIPng aggregated prefixes */
2900     for (rp = route_top (ripng->aggregate); rp; rp = route_next (rp))
2901       if (rp->info) {
2902           rp->info = NULL;
2903           route_unlock_node (rp);
2904     }
2905
2906     for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
2907       if (ripng->route_map[i].name)
2908         free (ripng->route_map[i].name);
2909
2910     XFREE (MTYPE_ROUTE_TABLE, ripng->table);
2911     XFREE (MTYPE_ROUTE_TABLE, ripng->route);
2912     XFREE (MTYPE_ROUTE_TABLE, ripng->aggregate);
2913
2914     XFREE (MTYPE_RIPNG, ripng);
2915     ripng = NULL;
2916   } /* if (ripng) */
2917
2918   ripng_clean_network();
2919   ripng_passive_interface_clean ();
2920   ripng_offset_clean ();
2921   ripng_interface_clean ();
2922   ripng_redistribute_clean ();
2923 }
2924
2925 /* Reset all values to the default settings. */
2926 void
2927 ripng_reset ()
2928 {
2929   /* Call ripd related reset functions. */
2930   ripng_debug_reset ();
2931   ripng_route_map_reset ();
2932
2933   /* Call library reset functions. */
2934   vty_reset ();
2935   access_list_reset ();
2936   prefix_list_reset ();
2937
2938   distribute_list_reset ();
2939
2940   ripng_interface_reset ();
2941
2942   ripng_zclient_reset ();
2943 }
2944
2945 static void
2946 ripng_if_rmap_update (struct if_rmap *if_rmap)
2947 {
2948   struct interface *ifp;
2949   struct ripng_interface *ri;
2950   struct route_map *rmap;
2951
2952   ifp = if_lookup_by_name (if_rmap->ifname);
2953   if (ifp == NULL)
2954     return;
2955
2956   ri = ifp->info;
2957
2958   if (if_rmap->routemap[IF_RMAP_IN])
2959     {
2960       rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_IN]);
2961       if (rmap)
2962         ri->routemap[IF_RMAP_IN] = rmap;
2963       else
2964         ri->routemap[IF_RMAP_IN] = NULL;
2965     }
2966   else
2967     ri->routemap[RIPNG_FILTER_IN] = NULL;
2968
2969   if (if_rmap->routemap[IF_RMAP_OUT])
2970     {
2971       rmap = route_map_lookup_by_name (if_rmap->routemap[IF_RMAP_OUT]);
2972       if (rmap)
2973         ri->routemap[IF_RMAP_OUT] = rmap;
2974       else
2975         ri->routemap[IF_RMAP_OUT] = NULL;
2976     }
2977   else
2978     ri->routemap[RIPNG_FILTER_OUT] = NULL;
2979 }
2980
2981 void
2982 ripng_if_rmap_update_interface (struct interface *ifp)
2983 {
2984   struct if_rmap *if_rmap;
2985
2986   if_rmap = if_rmap_lookup (ifp->name);
2987   if (if_rmap)
2988     ripng_if_rmap_update (if_rmap);
2989 }
2990
2991 static void
2992 ripng_routemap_update_redistribute (void)
2993 {
2994   int i;
2995
2996   if (ripng)
2997     {
2998       for (i = 0; i < ZEBRA_ROUTE_MAX; i++) 
2999         {
3000           if (ripng->route_map[i].name)
3001             ripng->route_map[i].map = 
3002               route_map_lookup_by_name (ripng->route_map[i].name);
3003         }
3004     }
3005 }
3006
3007 static void
3008 ripng_routemap_update (const char *unused)
3009 {
3010   struct interface *ifp;
3011   struct listnode *node;
3012
3013   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
3014     ripng_if_rmap_update_interface (ifp);
3015
3016   ripng_routemap_update_redistribute ();
3017 }
3018
3019 /* Initialize ripng structure and set commands. */
3020 void
3021 ripng_init ()
3022 {
3023   /* Randomize. */
3024   srandom (time (NULL));
3025
3026   /* Install RIPNG_NODE. */
3027   install_node (&cmd_ripng_node, ripng_config_write);
3028
3029   /* Install ripng commands. */
3030   install_element (VIEW_NODE, &show_ipv6_ripng_cmd);
3031   install_element (VIEW_NODE, &show_ipv6_ripng_status_cmd);
3032
3033   install_element (CONFIG_NODE, &router_ripng_cmd);
3034   install_element (CONFIG_NODE, &no_router_ripng_cmd);
3035
3036   install_default (RIPNG_NODE);
3037   install_element (RIPNG_NODE, &ripng_route_cmd);
3038   install_element (RIPNG_NODE, &no_ripng_route_cmd);
3039   install_element (RIPNG_NODE, &ripng_aggregate_address_cmd);
3040   install_element (RIPNG_NODE, &no_ripng_aggregate_address_cmd);
3041
3042   install_element (RIPNG_NODE, &ripng_default_metric_cmd);
3043   install_element (RIPNG_NODE, &no_ripng_default_metric_cmd);
3044   install_element (RIPNG_NODE, &no_ripng_default_metric_val_cmd);
3045
3046   install_element (RIPNG_NODE, &ripng_timers_cmd);
3047   install_element (RIPNG_NODE, &no_ripng_timers_cmd);
3048   install_element (RIPNG_NODE, &no_ripng_timers_val_cmd);
3049 #if 0
3050   install_element (RIPNG_NODE, &ripng_update_timer_cmd);
3051   install_element (RIPNG_NODE, &no_ripng_update_timer_cmd);
3052   install_element (RIPNG_NODE, &ripng_timeout_timer_cmd);
3053   install_element (RIPNG_NODE, &no_ripng_timeout_timer_cmd);
3054   install_element (RIPNG_NODE, &ripng_garbage_timer_cmd);
3055   install_element (RIPNG_NODE, &no_ripng_garbage_timer_cmd);
3056 #endif /* 0 */
3057
3058   install_element (RIPNG_NODE, &ripng_default_information_originate_cmd);
3059   install_element (RIPNG_NODE, &no_ripng_default_information_originate_cmd);
3060
3061   install_element (RIPNG_NODE, &ripng_allow_ecmp_cmd);
3062   install_element (RIPNG_NODE, &no_ripng_allow_ecmp_cmd);
3063
3064   ripng_if_init ();
3065   ripng_debug_init ();
3066
3067   /* Access list install. */
3068   access_list_init ();
3069   access_list_add_hook (ripng_distribute_update_all_wrapper);
3070   access_list_delete_hook (ripng_distribute_update_all_wrapper);
3071
3072   /* Prefix list initialize.*/
3073   prefix_list_init ();
3074   prefix_list_add_hook (ripng_distribute_update_all);
3075   prefix_list_delete_hook (ripng_distribute_update_all);
3076
3077   /* Distribute list install. */
3078   distribute_list_init (RIPNG_NODE);
3079   distribute_list_add_hook (ripng_distribute_update);
3080   distribute_list_delete_hook (ripng_distribute_update);
3081
3082   /* Route-map for interface. */
3083   ripng_route_map_init ();
3084   ripng_offset_init ();
3085
3086   route_map_add_hook (ripng_routemap_update);
3087   route_map_delete_hook (ripng_routemap_update);
3088
3089   if_rmap_init (RIPNG_NODE);
3090   if_rmap_hook_add (ripng_if_rmap_update);
3091   if_rmap_hook_delete (ripng_if_rmap_update);
3092 }