]> git.sommitrealweird.co.uk Git - quagga-debian.git/blob - ripngd/ripng_interface.c
New upstream version 1.2.4
[quagga-debian.git] / ripngd / ripng_interface.c
1 /*
2  * Interface related function for RIPng.
3  * Copyright (C) 1998 Kunihiro Ishiguro
4  *
5  * This file is part of GNU Zebra.
6  *
7  * GNU Zebra is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation; either version 2, or (at your option) any
10  * later version.
11  *
12  * GNU Zebra is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
19  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20  * 02111-1307, USA.  
21  */
22
23 #include <zebra.h>
24
25 #include "linklist.h"
26 #include "if.h"
27 #include "prefix.h"
28 #include "memory.h"
29 #include "network.h"
30 #include "filter.h"
31 #include "log.h"
32 #include "stream.h"
33 #include "zclient.h"
34 #include "command.h"
35 #include "table.h"
36 #include "thread.h"
37 #include "privs.h"
38 #include "vrf.h"
39
40 #include "ripngd/ripngd.h"
41 #include "ripngd/ripng_debug.h"
42
43 /* If RFC2133 definition is used. */
44 #ifndef IPV6_JOIN_GROUP
45 #define IPV6_JOIN_GROUP  IPV6_ADD_MEMBERSHIP 
46 #endif
47 #ifndef IPV6_LEAVE_GROUP
48 #define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP 
49 #endif
50
51 extern struct zebra_privs_t ripngd_privs;
52
53 /* Static utility function. */
54 static void ripng_enable_apply (struct interface *);
55 static void ripng_passive_interface_apply (struct interface *);
56 static int ripng_enable_if_lookup (const char *);
57 static int ripng_enable_network_lookup2 (struct connected *);
58 static void ripng_enable_apply_all (void);
59
60 /* Join to the all rip routers multicast group. */
61 static int
62 ripng_multicast_join (struct interface *ifp)
63 {
64   int ret;
65   struct ipv6_mreq mreq;
66   int save_errno;
67
68   if (if_is_up (ifp) && if_is_multicast (ifp)) {
69     memset (&mreq, 0, sizeof (mreq));
70     inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
71     mreq.ipv6mr_interface = ifp->ifindex;
72
73     /*
74      * NetBSD 1.6.2 requires root to join groups on gif(4).
75      * While this is bogus, privs are available and easy to use
76      * for this call as a workaround.
77      */
78     if (ripngd_privs.change (ZPRIVS_RAISE))
79       zlog_err ("ripng_multicast_join: could not raise privs");
80
81     ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
82                       (char *) &mreq, sizeof (mreq));
83     save_errno = errno;
84
85     if (ripngd_privs.change (ZPRIVS_LOWER))
86       zlog_err ("ripng_multicast_join: could not lower privs");
87
88     if (ret < 0 && save_errno == EADDRINUSE)
89       {
90         /*
91          * Group is already joined.  This occurs due to sloppy group
92          * management, in particular declining to leave the group on
93          * an interface that has just gone down.
94          */
95         zlog_warn ("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name);
96         return 0;               /* not an error */
97       }
98
99     if (ret < 0)
100       zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s",
101                  safe_strerror (save_errno));
102
103     if (IS_RIPNG_DEBUG_EVENT)
104       zlog_debug ("RIPng %s join to all-rip-routers multicast group", ifp->name);
105
106     if (ret < 0)
107       return -1;
108   }
109   return 0;
110 }
111
112 /* Leave from the all rip routers multicast group. */
113 static int
114 ripng_multicast_leave (struct interface *ifp)
115 {
116   int ret;
117   struct ipv6_mreq mreq;
118
119   if (if_is_up (ifp) && if_is_multicast (ifp)) {
120     memset (&mreq, 0, sizeof (mreq));
121     inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
122     mreq.ipv6mr_interface = ifp->ifindex;
123
124     ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
125                       (char *) &mreq, sizeof (mreq));
126     if (ret < 0)
127       zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", safe_strerror (errno));
128
129     if (IS_RIPNG_DEBUG_EVENT)
130       zlog_debug ("RIPng %s leave from all-rip-routers multicast group",
131                  ifp->name);
132
133     if (ret < 0)
134       return -1;
135   }
136
137   return 0;
138 }
139
140 /* How many link local IPv6 address could be used on the interface ? */
141 static int
142 ripng_if_ipv6_lladdress_check (struct interface *ifp)
143 {
144   struct listnode *nn;
145   struct connected *connected;
146   int count = 0;
147
148   for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, connected))
149     {
150       struct prefix *p;
151       p = connected->address;
152
153       if ((p->family == AF_INET6) &&
154           IN6_IS_ADDR_LINKLOCAL (&p->u.prefix6))
155         count++;
156     }
157
158   return count;
159 }
160
161 static int
162 ripng_if_down (struct interface *ifp)
163 {
164   struct route_node *rp;
165   struct ripng_info *rinfo;
166   struct ripng_interface *ri;
167   struct list *list = NULL;
168   struct listnode *listnode = NULL, *nextnode = NULL;
169
170   if (ripng)
171     for (rp = route_top (ripng->table); rp; rp = route_next (rp))
172       if ((list = rp->info) != NULL)
173         for (ALL_LIST_ELEMENTS (list, listnode, nextnode, rinfo))
174           if (rinfo->ifindex == ifp->ifindex)
175             ripng_ecmp_delete (rinfo);
176
177   ri = ifp->info;
178   
179   if (ri->running)
180    {
181      if (IS_RIPNG_DEBUG_EVENT)
182        zlog_debug ("turn off %s", ifp->name);
183
184      /* Leave from multicast group. */
185      ripng_multicast_leave (ifp);
186
187      ri->running = 0;
188    }
189
190   return 0;
191 }
192
193 /* Inteface link up message processing. */
194 int
195 ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length,
196     vrf_id_t vrf_id)
197 {
198   struct stream *s;
199   struct interface *ifp;
200
201   /* zebra_interface_state_read() updates interface structure in iflist. */
202   s = zclient->ibuf;
203   ifp = zebra_interface_state_read (s, vrf_id);
204
205   if (ifp == NULL)
206     return 0;
207
208   if (IS_RIPNG_DEBUG_ZEBRA)
209     zlog_debug ("interface up %s index %d flags %llx metric %d mtu %d",
210                ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
211                ifp->metric, ifp->mtu6);
212
213   /* Check if this interface is RIPng enabled or not. */
214   ripng_enable_apply (ifp);
215
216   /* Check for a passive interface. */
217   ripng_passive_interface_apply (ifp);
218
219   /* Apply distribute list to the all interface. */
220   ripng_distribute_update_interface (ifp);
221
222   return 0;
223 }
224
225 /* Inteface link down message processing. */
226 int
227 ripng_interface_down (int command, struct zclient *zclient,
228                       zebra_size_t length, vrf_id_t vrf_id)
229 {
230   struct stream *s;
231   struct interface *ifp;
232
233   /* zebra_interface_state_read() updates interface structure in iflist. */
234   s = zclient->ibuf;
235   ifp = zebra_interface_state_read (s, vrf_id);
236
237   if (ifp == NULL)
238     return 0;
239
240   ripng_if_down (ifp);
241
242   if (IS_RIPNG_DEBUG_ZEBRA)
243     zlog_debug ("interface down %s index %d flags %#llx metric %d mtu %d",
244                 ifp->name, ifp->ifindex,
245                 (unsigned long long) ifp->flags, ifp->metric, ifp->mtu6);
246
247   return 0;
248 }
249
250 /* Inteface addition message from zebra. */
251 int
252 ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length,
253     vrf_id_t vrf_id)
254 {
255   struct interface *ifp;
256
257   ifp = zebra_interface_add_read (zclient->ibuf, vrf_id);
258
259   if (IS_RIPNG_DEBUG_ZEBRA)
260     zlog_debug ("RIPng interface add %s index %d flags %#llx metric %d mtu %d",
261                 ifp->name, ifp->ifindex, (unsigned long long) ifp->flags,
262                 ifp->metric, ifp->mtu6);
263
264   /* Check is this interface is RIP enabled or not.*/
265   ripng_enable_apply (ifp);
266
267   /* Apply distribute list to the interface. */
268   ripng_distribute_update_interface (ifp);
269
270   /* Check interface routemap. */
271   ripng_if_rmap_update_interface (ifp);
272
273   return 0;
274 }
275
276 int
277 ripng_interface_delete (int command, struct zclient *zclient,
278                         zebra_size_t length, vrf_id_t vrf_id)
279 {
280   struct interface *ifp;
281   struct stream *s;
282
283   s = zclient->ibuf;
284   /*  zebra_interface_state_read() updates interface structure in iflist */
285   ifp = zebra_interface_state_read (s, vrf_id);
286
287   if (ifp == NULL)
288     return 0;
289
290   if (if_is_up (ifp)) {
291     ripng_if_down(ifp);
292   }
293
294   zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d",
295             ifp->name, ifp->ifindex, (unsigned long long) ifp->flags,
296             ifp->metric, ifp->mtu6);
297
298   /* To support pseudo interface do not free interface structure.  */
299   /* if_delete(ifp); */
300   ifp->ifindex = IFINDEX_INTERNAL;
301
302   return 0;
303 }
304
305 void
306 ripng_interface_clean (void)
307 {
308   struct listnode *node, *nnode;
309   struct interface *ifp;
310   struct ripng_interface *ri;
311
312   for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
313     {
314       ri = ifp->info;
315
316       ri->enable_network = 0;
317       ri->enable_interface = 0;
318       ri->running = 0;
319
320       if (ri->t_wakeup)
321         {
322           thread_cancel (ri->t_wakeup);
323           ri->t_wakeup = NULL;
324         }
325     }
326 }
327
328 void
329 ripng_interface_reset (void)
330 {
331   struct listnode *node;
332   struct interface *ifp;
333   struct ripng_interface *ri;
334
335   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
336     {
337       ri = ifp->info;
338
339       ri->enable_network = 0;
340       ri->enable_interface = 0;
341       ri->running = 0;
342
343       ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
344       ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON;
345
346       ri->list[RIPNG_FILTER_IN] = NULL;
347       ri->list[RIPNG_FILTER_OUT] = NULL;
348
349       ri->prefix[RIPNG_FILTER_IN] = NULL;
350       ri->prefix[RIPNG_FILTER_OUT] = NULL;
351
352       if (ri->t_wakeup)
353         {
354           thread_cancel (ri->t_wakeup);
355           ri->t_wakeup = NULL;
356         }
357
358       ri->passive = 0;
359     }
360 }
361
362 static void
363 ripng_apply_address_add (struct connected *ifc) {
364   struct prefix_ipv6 address;
365   struct prefix *p;
366
367   if (!ripng)
368     return;
369
370   if (! if_is_up(ifc->ifp))
371     return;
372
373   p = ifc->address;
374
375   memset (&address, 0, sizeof (address));
376   address.family = p->family;
377   address.prefix = p->u.prefix6;
378   address.prefixlen = p->prefixlen;
379   apply_mask_ipv6(&address);
380
381   /* Check if this interface is RIP enabled or not
382      or  Check if this address's prefix is RIP enabled */
383   if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) ||
384       (ripng_enable_network_lookup2(ifc) >= 0))
385     ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
386                            &address, ifc->ifp->ifindex, NULL, 0);
387
388 }
389
390 int
391 ripng_interface_address_add (int command, struct zclient *zclient,
392                              zebra_size_t length, vrf_id_t vrf_id)
393 {
394   struct connected *c;
395   struct prefix *p;
396
397   c = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, 
398                                     zclient->ibuf, vrf_id);
399
400   if (c == NULL)
401     return 0;
402
403   p = c->address;
404
405   if (p->family == AF_INET6)
406     {
407       struct ripng_interface *ri = c->ifp->info;
408       
409       if (IS_RIPNG_DEBUG_ZEBRA)
410         zlog_debug ("RIPng connected address %s/%d add",
411                    inet6_ntoa(p->u.prefix6),
412                    p->prefixlen);
413       
414       /* Check is this prefix needs to be redistributed. */
415       ripng_apply_address_add(c);
416
417       /* Let's try once again whether the interface could be activated */
418       if (!ri->running) {
419         /* Check if this interface is RIP enabled or not.*/
420         ripng_enable_apply (c->ifp);
421
422         /* Apply distribute list to the interface. */
423         ripng_distribute_update_interface (c->ifp);
424
425         /* Check interface routemap. */
426         ripng_if_rmap_update_interface (c->ifp);
427       }
428
429     }
430
431   return 0;
432 }
433
434 static void
435 ripng_apply_address_del (struct connected *ifc) {
436   struct prefix_ipv6 address;
437   struct prefix *p;
438
439   if (!ripng)
440     return;
441
442   if (! if_is_up(ifc->ifp))
443     return;
444
445   p = ifc->address;
446
447   memset (&address, 0, sizeof (address));
448   address.family = p->family;
449   address.prefix = p->u.prefix6;
450   address.prefixlen = p->prefixlen;
451   apply_mask_ipv6(&address);
452
453   ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
454                             &address, ifc->ifp->ifindex);
455 }
456
457 int
458 ripng_interface_address_delete (int command, struct zclient *zclient,
459                                 zebra_size_t length, vrf_id_t vrf_id)
460 {
461   struct connected *ifc;
462   struct prefix *p;
463   char buf[INET6_ADDRSTRLEN];
464
465   ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_DELETE, 
466                                       zclient->ibuf, vrf_id);
467   
468   if (ifc)
469     {
470       p = ifc->address;
471
472       if (p->family == AF_INET6)
473         {
474           if (IS_RIPNG_DEBUG_ZEBRA)
475             zlog_debug ("RIPng connected address %s/%d delete",
476                        inet_ntop (AF_INET6, &p->u.prefix6, buf,
477                                   INET6_ADDRSTRLEN),
478                        p->prefixlen);
479
480           /* Check wether this prefix needs to be removed. */
481           ripng_apply_address_del(ifc);
482         }
483       connected_free (ifc);
484     }
485
486   return 0;
487 }
488
489 /* RIPng enable interface vector. */
490 vector ripng_enable_if;
491
492 /* RIPng enable network table. */
493 struct route_table *ripng_enable_network;
494
495 /* Lookup RIPng enable network. */
496 /* Check wether the interface has at least a connected prefix that
497  * is within the ripng_enable_network table. */
498 static int
499 ripng_enable_network_lookup_if (struct interface *ifp)
500 {
501   struct listnode *node;
502   struct connected *connected;
503   struct prefix_ipv6 address;
504
505   for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))
506     {
507       struct prefix *p; 
508       struct route_node *node;
509
510       p = connected->address;
511
512       if (p->family == AF_INET6)
513         {
514           address.family = AF_INET6;
515           address.prefix = p->u.prefix6;
516           address.prefixlen = IPV6_MAX_BITLEN;
517
518           node = route_node_match (ripng_enable_network,
519                                    (struct prefix *)&address);
520           if (node)
521             {
522               route_unlock_node (node);
523               return 1;
524             }
525         }
526     }
527   return -1;
528 }
529
530 /* Check wether connected is within the ripng_enable_network table. */
531 static int
532 ripng_enable_network_lookup2 (struct connected *connected)
533 {
534   struct prefix_ipv6 address;
535   struct prefix *p;
536
537   p = connected->address;
538
539   if (p->family == AF_INET6) {
540     struct route_node *node;
541
542     address.family = p->family;
543     address.prefix = p->u.prefix6;
544     address.prefixlen = IPV6_MAX_BITLEN;
545
546     /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within ripng_enable_network */
547     node = route_node_match (ripng_enable_network,
548                              (struct prefix *)&address);
549
550     if (node) {
551       route_unlock_node (node);
552       return 1;
553     }
554   }
555
556   return -1;
557 }
558
559 /* Add RIPng enable network. */
560 static int
561 ripng_enable_network_add (struct prefix *p)
562 {
563   struct route_node *node;
564
565   node = route_node_get (ripng_enable_network, p);
566
567   if (node->info)
568     {
569       route_unlock_node (node);
570       return -1;
571     }
572   else
573     node->info = (char *) "enabled";
574
575   /* XXX: One should find a better solution than a generic one */
576   ripng_enable_apply_all();
577
578   return 1;
579 }
580
581 /* Delete RIPng enable network. */
582 static int
583 ripng_enable_network_delete (struct prefix *p)
584 {
585   struct route_node *node;
586
587   node = route_node_lookup (ripng_enable_network, p);
588   if (node)
589     {
590       node->info = NULL;
591
592       /* Unlock info lock. */
593       route_unlock_node (node);
594
595       /* Unlock lookup lock. */
596       route_unlock_node (node);
597
598       return 1;
599     }
600   return -1;
601 }
602
603 /* Lookup function. */
604 static int
605 ripng_enable_if_lookup (const char *ifname)
606 {
607   unsigned int i;
608   char *str;
609
610   for (i = 0; i < vector_active (ripng_enable_if); i++)
611     if ((str = vector_slot (ripng_enable_if, i)) != NULL)
612       if (strcmp (str, ifname) == 0)
613         return i;
614   return -1;
615 }
616
617 /* Add interface to ripng_enable_if. */
618 static int
619 ripng_enable_if_add (const char *ifname)
620 {
621   int ret;
622
623   ret = ripng_enable_if_lookup (ifname);
624   if (ret >= 0)
625     return -1;
626
627   vector_set (ripng_enable_if, strdup (ifname));
628
629   ripng_enable_apply_all();
630
631   return 1;
632 }
633
634 /* Delete interface from ripng_enable_if. */
635 static int
636 ripng_enable_if_delete (const char *ifname)
637 {
638   int index;
639   char *str;
640
641   index = ripng_enable_if_lookup (ifname);
642   if (index < 0)
643     return -1;
644
645   str = vector_slot (ripng_enable_if, index);
646   free (str);
647   vector_unset (ripng_enable_if, index);
648
649   ripng_enable_apply_all();
650
651   return 1;
652 }
653
654 /* Wake up interface. */
655 static int
656 ripng_interface_wakeup (struct thread *t)
657 {
658   struct interface *ifp;
659   struct ripng_interface *ri;
660
661   /* Get interface. */
662   ifp = THREAD_ARG (t);
663
664   ri = ifp->info;
665   ri->t_wakeup = NULL;
666
667   /* Join to multicast group. */
668   if (ripng_multicast_join (ifp) < 0) {
669     zlog_err ("multicast join failed, interface %s not running", ifp->name);
670     return 0;
671   }
672     
673   /* Set running flag. */
674   ri->running = 1;
675
676   /* Send RIP request to the interface. */
677   ripng_request (ifp);
678
679   return 0;
680 }
681
682 static void
683 ripng_connect_set (struct interface *ifp, int set)
684 {
685   struct listnode *node, *nnode;
686   struct connected *connected;
687   struct prefix_ipv6 address;
688
689   for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, connected))
690     {
691       struct prefix *p;
692       p = connected->address;
693
694       if (p->family != AF_INET6)
695         continue;
696
697       address.family = AF_INET6;
698       address.prefix = p->u.prefix6;
699       address.prefixlen = p->prefixlen;
700       apply_mask_ipv6 (&address);
701
702       if (set) {
703         /* Check once more wether this prefix is within a "network IF_OR_PREF" one */
704         if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) ||
705             (ripng_enable_network_lookup2(connected) >= 0))
706           ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
707                                   &address, connected->ifp->ifindex, NULL, 0);
708       } else {
709         ripng_redistribute_delete (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
710                                    &address, connected->ifp->ifindex);
711         if (ripng_redistribute_check (ZEBRA_ROUTE_CONNECT))
712           ripng_redistribute_add (ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE,
713                                   &address, connected->ifp->ifindex, NULL, 0);
714       }
715     }
716 }
717
718 /* Check RIPng is enabed on this interface. */
719 void
720 ripng_enable_apply (struct interface *ifp)
721 {
722   int ret;
723   struct ripng_interface *ri = NULL;
724
725   /* Check interface. */
726   if (! if_is_up (ifp))
727     return;
728   
729   ri = ifp->info;
730
731   /* Is this interface a candidate for RIPng ? */
732   ret = ripng_enable_network_lookup_if (ifp);
733
734   /* If the interface is matched. */
735   if (ret > 0)
736     ri->enable_network = 1;
737   else
738     ri->enable_network = 0;
739
740   /* Check interface name configuration. */
741   ret = ripng_enable_if_lookup (ifp->name);
742   if (ret >= 0)
743     ri->enable_interface = 1;
744   else
745     ri->enable_interface = 0;
746
747   /* any candidate interface MUST have a link-local IPv6 address */
748   if ((! ripng_if_ipv6_lladdress_check (ifp)) &&
749       (ri->enable_network || ri->enable_interface)) {
750     ri->enable_network = 0;
751     ri->enable_interface = 0;
752     zlog_warn("Interface %s does not have any link-local address",
753               ifp->name);
754   }
755
756   /* Update running status of the interface. */
757   if (ri->enable_network || ri->enable_interface)
758     {
759         {
760           if (IS_RIPNG_DEBUG_EVENT)
761             zlog_debug ("RIPng turn on %s", ifp->name);
762
763           /* Add interface wake up thread. */
764           if (! ri->t_wakeup)
765             ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup,
766                                              ifp, 1);
767
768           ripng_connect_set (ifp, 1);
769         }
770     }
771   else
772     {
773       if (ri->running)
774         {
775           /* Might as well clean up the route table as well
776            * ripng_if_down sets to 0 ri->running, and displays "turn off %s"
777            **/
778           ripng_if_down(ifp);
779
780           ripng_connect_set (ifp, 0);
781         }
782     }
783 }
784
785 /* Set distribute list to all interfaces. */
786 static void
787 ripng_enable_apply_all (void)
788 {
789   struct interface *ifp;
790   struct listnode *node;
791
792   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
793     ripng_enable_apply (ifp);
794 }
795
796 /* Clear all network and neighbor configuration */
797 void
798 ripng_clean_network ()
799 {
800   unsigned int i;
801   char *str;
802   struct route_node *rn;
803
804   /* ripng_enable_network */
805   for (rn = route_top (ripng_enable_network); rn; rn = route_next (rn))
806     if (rn->info) {
807       rn->info = NULL;
808       route_unlock_node(rn);
809     }
810
811   /* ripng_enable_if */
812   for (i = 0; i < vector_active (ripng_enable_if); i++)
813     if ((str = vector_slot (ripng_enable_if, i)) != NULL) {
814       free (str);
815       vector_slot (ripng_enable_if, i) = NULL;
816     }
817 }
818
819 /* Vector to store passive-interface name. */
820 vector Vripng_passive_interface;
821
822 /* Utility function for looking up passive interface settings. */
823 static int
824 ripng_passive_interface_lookup (const char *ifname)
825 {
826   unsigned int i;
827   char *str;
828
829   for (i = 0; i < vector_active (Vripng_passive_interface); i++)
830     if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
831       if (strcmp (str, ifname) == 0)
832         return i;
833   return -1;
834 }
835
836 void
837 ripng_passive_interface_apply (struct interface *ifp)
838 {
839   int ret;
840   struct ripng_interface *ri;
841
842   ri = ifp->info;
843
844   ret = ripng_passive_interface_lookup (ifp->name);
845   if (ret < 0)
846     ri->passive = 0;
847   else
848     ri->passive = 1;
849 }
850
851 static void
852 ripng_passive_interface_apply_all (void)
853 {
854   struct interface *ifp;
855   struct listnode *node;
856
857   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
858     ripng_passive_interface_apply (ifp);
859 }
860
861 /* Passive interface. */
862 static int
863 ripng_passive_interface_set (struct vty *vty, const char *ifname)
864 {
865   if (ripng_passive_interface_lookup (ifname) >= 0)
866     return CMD_WARNING;
867
868   vector_set (Vripng_passive_interface, strdup (ifname));
869
870   ripng_passive_interface_apply_all ();
871
872   return CMD_SUCCESS;
873 }
874
875 static int
876 ripng_passive_interface_unset (struct vty *vty, const char *ifname)
877 {
878   int i;
879   char *str;
880
881   i = ripng_passive_interface_lookup (ifname);
882   if (i < 0)
883     return CMD_WARNING;
884
885   str = vector_slot (Vripng_passive_interface, i);
886   free (str);
887   vector_unset (Vripng_passive_interface, i);
888
889   ripng_passive_interface_apply_all ();
890
891   return CMD_SUCCESS;
892 }
893
894 /* Free all configured RIP passive-interface settings. */
895 void
896 ripng_passive_interface_clean (void)
897 {
898   unsigned int i;
899   char *str;
900
901   for (i = 0; i < vector_active (Vripng_passive_interface); i++)
902     if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
903       {
904         free (str);
905         vector_slot (Vripng_passive_interface, i) = NULL;
906       }
907   ripng_passive_interface_apply_all ();
908 }
909
910 /* Write RIPng enable network and interface to the vty. */
911 int
912 ripng_network_write (struct vty *vty, int config_mode)
913 {
914   unsigned int i;
915   const char *ifname;
916   struct route_node *node;
917   char buf[BUFSIZ];
918
919   /* Write enable network. */
920   for (node = route_top (ripng_enable_network); node; node = route_next (node))
921     if (node->info)
922       {
923         struct prefix *p = &node->p;
924         vty_out (vty, "%s%s/%d%s", 
925                  config_mode ? " network " : "    ",
926                  inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
927                  p->prefixlen,
928                  VTY_NEWLINE);
929
930       }
931   
932   /* Write enable interface. */
933   for (i = 0; i < vector_active (ripng_enable_if); i++)
934     if ((ifname = vector_slot (ripng_enable_if, i)) != NULL)
935       vty_out (vty, "%s%s%s",
936                config_mode ? " network " : "    ",
937                ifname,
938                VTY_NEWLINE);
939
940   /* Write passive interface. */
941   if (config_mode)
942     for (i = 0; i < vector_active (Vripng_passive_interface); i++)
943       if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL)
944         vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
945
946   return 0;
947 }
948
949 /* RIPng enable on specified interface or matched network. */
950 DEFUN (ripng_network,
951        ripng_network_cmd,
952        "network IF_OR_ADDR",
953        "RIPng enable on specified interface or network.\n"
954        "Interface or address")
955 {
956   int ret;
957   struct prefix p;
958
959   ret = str2prefix (argv[0], &p);
960
961   /* Given string is IPv6 network or interface name. */
962   if (ret)
963     ret = ripng_enable_network_add (&p);
964   else
965     ret = ripng_enable_if_add (argv[0]);
966
967   if (ret < 0)
968     {
969       vty_out (vty, "There is same network configuration %s%s", argv[0],
970                VTY_NEWLINE);
971       return CMD_WARNING;
972     }
973
974   return CMD_SUCCESS;
975 }
976
977 /* RIPng enable on specified interface or matched network. */
978 DEFUN (no_ripng_network,
979        no_ripng_network_cmd,
980        "no network IF_OR_ADDR",
981        NO_STR
982        "RIPng enable on specified interface or network.\n"
983        "Interface or address")
984 {
985   int ret;
986   struct prefix p;
987
988   ret = str2prefix (argv[0], &p);
989
990   /* Given string is interface name. */
991   if (ret)
992     ret = ripng_enable_network_delete (&p);
993   else
994     ret = ripng_enable_if_delete (argv[0]);
995
996   if (ret < 0)
997     {
998       vty_out (vty, "can't find network %s%s", argv[0],
999                VTY_NEWLINE);
1000       return CMD_WARNING;
1001     }
1002   
1003   return CMD_SUCCESS;
1004 }
1005
1006 DEFUN (ipv6_ripng_split_horizon,
1007        ipv6_ripng_split_horizon_cmd,
1008        "ipv6 ripng split-horizon",
1009        IPV6_STR
1010        "Routing Information Protocol\n"
1011        "Perform split horizon\n")
1012 {
1013   struct interface *ifp;
1014   struct ripng_interface *ri;
1015
1016   ifp = vty->index;
1017   ri = ifp->info;
1018
1019   ri->split_horizon = RIPNG_SPLIT_HORIZON;
1020   return CMD_SUCCESS;
1021 }
1022
1023 DEFUN (ipv6_ripng_split_horizon_poisoned_reverse,
1024        ipv6_ripng_split_horizon_poisoned_reverse_cmd,
1025        "ipv6 ripng split-horizon poisoned-reverse",
1026        IPV6_STR
1027        "Routing Information Protocol\n"
1028        "Perform split horizon\n"
1029        "With poisoned-reverse\n")
1030 {
1031   struct interface *ifp;
1032   struct ripng_interface *ri;
1033
1034   ifp = vty->index;
1035   ri = ifp->info;
1036
1037   ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE;
1038   return CMD_SUCCESS;
1039 }
1040
1041 DEFUN (no_ipv6_ripng_split_horizon,
1042        no_ipv6_ripng_split_horizon_cmd,
1043        "no ipv6 ripng split-horizon",
1044        NO_STR
1045        IPV6_STR
1046        "Routing Information Protocol\n"
1047        "Perform split horizon\n")
1048 {
1049   struct interface *ifp;
1050   struct ripng_interface *ri;
1051
1052   ifp = vty->index;
1053   ri = ifp->info;
1054
1055   ri->split_horizon = RIPNG_NO_SPLIT_HORIZON;
1056   return CMD_SUCCESS;
1057 }
1058
1059 ALIAS (no_ipv6_ripng_split_horizon,
1060        no_ipv6_ripng_split_horizon_poisoned_reverse_cmd,
1061        "no ipv6 ripng split-horizon poisoned-reverse",
1062        NO_STR
1063        IPV6_STR
1064        "Routing Information Protocol\n"
1065        "Perform split horizon\n"
1066        "With poisoned-reverse\n")
1067
1068 DEFUN (ripng_passive_interface,
1069        ripng_passive_interface_cmd,
1070        "passive-interface IFNAME",
1071        "Suppress routing updates on an interface\n"
1072        "Interface name\n")
1073 {
1074   return ripng_passive_interface_set (vty, argv[0]);
1075 }
1076
1077 DEFUN (no_ripng_passive_interface,
1078        no_ripng_passive_interface_cmd,
1079        "no passive-interface IFNAME",
1080        NO_STR
1081        "Suppress routing updates on an interface\n"
1082        "Interface name\n")
1083 {
1084   return ripng_passive_interface_unset (vty, argv[0]);
1085 }
1086
1087 static struct ripng_interface *
1088 ri_new (void)
1089 {
1090   struct ripng_interface *ri;
1091   ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface));
1092
1093   /* Set default split-horizon behavior.  If the interface is Frame
1094      Relay or SMDS is enabled, the default value for split-horizon is
1095      off.  But currently Zebra does detect Frame Relay or SMDS
1096      interface.  So all interface is set to split horizon.  */
1097   ri->split_horizon_default = RIPNG_SPLIT_HORIZON;
1098   ri->split_horizon = ri->split_horizon_default;
1099
1100   return ri;
1101 }
1102
1103 static int
1104 ripng_if_new_hook (struct interface *ifp)
1105 {
1106   ifp->info = ri_new ();
1107   return 0;
1108 }
1109
1110 /* Called when interface structure deleted. */
1111 static int
1112 ripng_if_delete_hook (struct interface *ifp)
1113 {
1114   XFREE (MTYPE_IF, ifp->info);
1115   ifp->info = NULL;
1116   return 0;
1117 }
1118
1119 /* Configuration write function for ripngd. */
1120 static int
1121 interface_config_write (struct vty *vty)
1122 {
1123   struct listnode *node;
1124   struct interface *ifp;
1125   struct ripng_interface *ri;
1126   int write = 0;
1127
1128   for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp))
1129     {
1130       ri = ifp->info;
1131
1132       /* Do not display the interface if there is no
1133        * configuration about it.
1134        **/
1135       if ((!ifp->desc) &&
1136           (ri->split_horizon == ri->split_horizon_default))
1137         continue;
1138
1139       vty_out (vty, "interface %s%s", ifp->name,
1140                VTY_NEWLINE);
1141       if (ifp->desc)
1142         vty_out (vty, " description %s%s", ifp->desc,
1143                  VTY_NEWLINE);
1144
1145       /* Split horizon. */
1146       if (ri->split_horizon != ri->split_horizon_default)
1147         {
1148           switch (ri->split_horizon) {
1149           case RIPNG_SPLIT_HORIZON:
1150             vty_out (vty, " ipv6 ripng split-horizon%s", VTY_NEWLINE);
1151             break;
1152           case RIPNG_SPLIT_HORIZON_POISONED_REVERSE:
1153             vty_out (vty, " ipv6 ripng split-horizon poisoned-reverse%s",
1154                           VTY_NEWLINE);
1155             break;
1156           case RIPNG_NO_SPLIT_HORIZON:
1157           default:
1158             vty_out (vty, " no ipv6 ripng split-horizon%s", VTY_NEWLINE);
1159             break;
1160           }
1161         }
1162
1163       vty_out (vty, "!%s", VTY_NEWLINE);
1164
1165       write++;
1166     }
1167   return write;
1168 }
1169
1170 /* ripngd's interface node. */
1171 static struct cmd_node interface_node =
1172 {
1173   INTERFACE_NODE,
1174   "%s(config-if)# ",
1175   1 /* VTYSH */
1176 };
1177
1178 /* Initialization of interface. */
1179 void
1180 ripng_if_init ()
1181 {
1182   /* Interface initialize. */
1183   if_add_hook (IF_NEW_HOOK, ripng_if_new_hook);
1184   if_add_hook (IF_DELETE_HOOK, ripng_if_delete_hook);
1185
1186   /* RIPng enable network init. */
1187   ripng_enable_network = route_table_init ();
1188
1189   /* RIPng enable interface init. */
1190   ripng_enable_if = vector_init (1);
1191
1192   /* RIPng passive interface. */
1193   Vripng_passive_interface = vector_init (1);
1194
1195   /* Install interface node. */
1196   install_node (&interface_node, interface_config_write);
1197   
1198   /* Install commands. */
1199   install_element (CONFIG_NODE, &interface_cmd);
1200   install_element (CONFIG_NODE, &no_interface_cmd);
1201   install_default (INTERFACE_NODE);
1202   install_element (INTERFACE_NODE, &interface_desc_cmd);
1203   install_element (INTERFACE_NODE, &no_interface_desc_cmd);
1204
1205   install_element (RIPNG_NODE, &ripng_network_cmd);
1206   install_element (RIPNG_NODE, &no_ripng_network_cmd);
1207   install_element (RIPNG_NODE, &ripng_passive_interface_cmd);
1208   install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd);
1209
1210   install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd);
1211   install_element (INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd);
1212   install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd);
1213   install_element (INTERFACE_NODE, &no_ipv6_ripng_split_horizon_poisoned_reverse_cmd);
1214 }