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