blob: c177381a62d335063e576e437f16fa57e5b54c8f [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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
38#include "ripngd/ripngd.h"
39#include "ripngd/ripng_debug.h"
40
41/* If RFC2133 definition is used. */
42#ifndef IPV6_JOIN_GROUP
43#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP
44#endif
45#ifndef IPV6_LEAVE_GROUP
46#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP
47#endif
48
49/* Static utility function. */
50static void ripng_enable_apply (struct interface *);
51static void ripng_passive_interface_apply (struct interface *);
52
53/* Join to the all rip routers multicast group. */
54int
55ripng_multicast_join (struct interface *ifp)
56{
57 int ret;
58 struct ipv6_mreq mreq;
59
60 memset (&mreq, 0, sizeof (mreq));
61 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
62 mreq.ipv6mr_interface = ifp->ifindex;
63
64 ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
65 (char *) &mreq, sizeof (mreq));
66 if (ret < 0)
67 zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno));
68
69 if (IS_RIPNG_DEBUG_EVENT)
70 zlog_info ("RIPng %s join to all-rip-routers multicast group", ifp->name);
71
72 return ret;
73}
74
75/* Leave from the all rip routers multicast group. */
76int
77ripng_multicast_leave (struct interface *ifp)
78{
79 int ret;
80 struct ipv6_mreq mreq;
81
82 memset (&mreq, 0, sizeof (mreq));
83 inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
84 mreq.ipv6mr_interface = ifp->ifindex;
85
86 ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
87 (char *) &mreq, sizeof (mreq));
88 if (ret < 0)
89 zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", strerror (errno));
90
91 if (IS_RIPNG_DEBUG_EVENT)
92 zlog_info ("RIPng %s leave from all-rip-routers multicast group",
93 ifp->name);
94
95 return ret;
96}
97
98/* Check max mtu size. */
99int
100ripng_check_max_mtu ()
101{
102 listnode node;
103 struct interface *ifp;
104 int mtu;
105
106 mtu = 0;
107 for (node = listhead (iflist); node; nextnode (node))
108 {
109 ifp = getdata (node);
110 if (mtu < ifp->mtu)
111 mtu = ifp->mtu;
112 }
113 return mtu;
114}
115
116int
117ripng_if_down (struct interface *ifp)
118{
119 struct route_node *rp;
120 struct ripng_info *rinfo;
121 struct ripng_interface *ri;
122
123 if (ripng->table)
124 {
125 for (rp = route_top (ripng->table); rp; rp = route_next (rp))
126 if ((rinfo = rp->info) != NULL)
127 {
128 /* Routes got through this interface. */
129 if (rinfo->ifindex == ifp->ifindex
130 && rinfo->type == ZEBRA_ROUTE_RIPNG
131 && rinfo->sub_type == RIPNG_ROUTE_RTE)
132 {
133 ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p,
134 &rinfo->nexthop,
135 rinfo->ifindex);
136
137 RIPNG_TIMER_OFF (rinfo->t_timeout);
138 RIPNG_TIMER_OFF (rinfo->t_garbage_collect);
139
140 rp->info = NULL;
141 route_unlock_node (rp);
142
143 ripng_info_free (rinfo);
144 }
145 else
146 {
147 /* All redistributed routes got through this interface. */
148 if (rinfo->ifindex == ifp->ifindex)
149 ripng_redistribute_delete (rinfo->type, rinfo->sub_type,
150 (struct prefix_ipv6 *) &rp->p,
151 rinfo->ifindex);
152 }
153 }
154 }
155
156 ri = ifp->info;
157
158 if (ripng && ri->running)
159 {
160 if (IS_RIPNG_DEBUG_EVENT)
161 zlog_info ("turn off %s", ifp->name);
162
163 /* Leave from multicast group. */
164 ripng_multicast_leave (ifp);
165
166 ri->running = 0;
167 }
168
169 return 0;
170}
171
172/* Inteface link up message processing. */
173int
174ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length)
175{
176 struct stream *s;
177 struct interface *ifp;
178
179 /* zebra_interface_state_read() updates interface structure in iflist. */
180 s = zclient->ibuf;
181 ifp = zebra_interface_state_read (s);
182
183 if (ifp == NULL)
184 return 0;
185
186 if (IS_RIPNG_DEBUG_ZEBRA)
187 zlog_info ("interface up %s index %d flags %ld metric %d mtu %d",
188 ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
189
190 /* Check if this interface is RIPng enabled or not. */
191 ripng_enable_apply (ifp);
192
193 /* Check for a passive interface. */
194 ripng_passive_interface_apply (ifp);
195
196 /* Apply distribute list to the all interface. */
197 ripng_distribute_update_interface (ifp);
198
199 return 0;
200}
201
202/* Inteface link down message processing. */
203int
204ripng_interface_down (int command, struct zclient *zclient,
205 zebra_size_t length)
206{
207 struct stream *s;
208 struct interface *ifp;
209
210 /* zebra_interface_state_read() updates interface structure in iflist. */
211 s = zclient->ibuf;
212 ifp = zebra_interface_state_read (s);
213
214 if (ifp == NULL)
215 return 0;
216
217 ripng_if_down (ifp);
218
219 if (IS_RIPNG_DEBUG_ZEBRA)
220 zlog_info ("interface down %s index %d flags %ld metric %d mtu %d",
221 ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
222
223 return 0;
224}
225
226/* Inteface addition message from zebra. */
227int
228ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length)
229{
230 struct interface *ifp;
231
232 ifp = zebra_interface_add_read (zclient->ibuf);
233
234 if (IS_RIPNG_DEBUG_ZEBRA)
235 zlog_info ("RIPng interface add %s index %d flags %ld metric %d mtu %d",
236 ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu);
237
238 /* Check is this interface is RIP enabled or not.*/
239 ripng_enable_apply (ifp);
240
241 /* Apply distribute list to the interface. */
242 ripng_distribute_update_interface (ifp);
243
244 /* Check interface routemap. */
245 ripng_if_rmap_update_interface (ifp);
246
247 return 0;
248}
249
250int
251ripng_interface_delete (int command, struct zclient *zclient,
252 zebra_size_t length)
253{
254 return 0;
255}
256
257int
258ripng_interface_address_add (int command, struct zclient *zclient,
259 zebra_size_t length)
260{
261 struct connected *c;
262 struct prefix *p;
263 char buf[INET6_ADDRSTRLEN];
264
265 c = zebra_interface_address_add_read (zclient->ibuf);
266
267 if (c == NULL)
268 return 0;
269
270 p = c->address;
271
272 if (p->family == AF_INET6)
273 {
274 if (IS_RIPNG_DEBUG_ZEBRA)
275 zlog_info ("RIPng connected address %s/%d add",
276 inet_ntop (AF_INET6, &p->u.prefix6, buf, INET6_ADDRSTRLEN),
277 p->prefixlen);
278
279 /* Check is this interface is RIP enabled or not.*/
280 ripng_enable_apply (c->ifp);
281 }
282
283 return 0;
284}
285
286int
287ripng_interface_address_delete (int command, struct zclient *zclient,
288 zebra_size_t length)
289{
290 struct connected *ifc;
291 struct prefix *p;
292 char buf[INET6_ADDRSTRLEN];
293
294 ifc = zebra_interface_address_delete_read (zclient->ibuf);
295
296 if (ifc)
297 {
298 p = ifc->address;
299
300 if (p->family == AF_INET6)
301 {
302 if (IS_RIPNG_DEBUG_ZEBRA)
303 zlog_info ("RIPng connected address %s/%d delete",
304 inet_ntop (AF_INET6, &p->u.prefix6, buf,
305 INET6_ADDRSTRLEN),
306 p->prefixlen);
307
308 /* Check is this interface is RIP enabled or not.*/
309 ripng_enable_apply (ifc->ifp);
310 }
311 connected_free (ifc);
312 }
313
314 return 0;
315}
316
317/* RIPng enable interface vector. */
318vector ripng_enable_if;
319
320/* RIPng enable network table. */
321struct route_table *ripng_enable_network;
322
323/* Lookup RIPng enable network. */
324int
325ripng_enable_network_lookup (struct interface *ifp)
326{
327 listnode listnode;
328 struct connected *connected;
329
330 for (listnode = listhead (ifp->connected); listnode; nextnode (listnode))
331 if ((connected = getdata (listnode)) != NULL)
332 {
333 struct prefix *p;
334 struct route_node *node;
335
336 p = connected->address;
337
338 if (p->family == AF_INET6)
339 {
340 node = route_node_match (ripng_enable_network, p);
341 if (node)
342 {
343 route_unlock_node (node);
344 return 1;
345 }
346 }
347 }
348 return -1;
349}
350
351/* Add RIPng enable network. */
352int
353ripng_enable_network_add (struct prefix *p)
354{
355 struct route_node *node;
356
357 node = route_node_get (ripng_enable_network, p);
358
359 if (node->info)
360 {
361 route_unlock_node (node);
362 return -1;
363 }
364 else
365 node->info = "enabled";
366
367 return 1;
368}
369
370/* Delete RIPng enable network. */
371int
372ripng_enable_network_delete (struct prefix *p)
373{
374 struct route_node *node;
375
376 node = route_node_lookup (ripng_enable_network, p);
377 if (node)
378 {
379 node->info = NULL;
380
381 /* Unlock info lock. */
382 route_unlock_node (node);
383
384 /* Unlock lookup lock. */
385 route_unlock_node (node);
386
387 return 1;
388 }
389 return -1;
390}
391
392/* Lookup function. */
393int
394ripng_enable_if_lookup (char *ifname)
395{
396 int i;
397 char *str;
398
399 for (i = 0; i < vector_max (ripng_enable_if); i++)
400 if ((str = vector_slot (ripng_enable_if, i)) != NULL)
401 if (strcmp (str, ifname) == 0)
402 return i;
403 return -1;
404}
405
406/* Add interface to ripng_enable_if. */
407int
408ripng_enable_if_add (char *ifname)
409{
410 int ret;
411
412 ret = ripng_enable_if_lookup (ifname);
413 if (ret >= 0)
414 return -1;
415
416 vector_set (ripng_enable_if, strdup (ifname));
417
418 return 1;
419}
420
421/* Delete interface from ripng_enable_if. */
422int
423ripng_enable_if_delete (char *ifname)
424{
425 int index;
426 char *str;
427
428 index = ripng_enable_if_lookup (ifname);
429 if (index < 0)
430 return -1;
431
432 str = vector_slot (ripng_enable_if, index);
433 free (str);
434 vector_unset (ripng_enable_if, index);
435
436 return 1;
437}
438
439/* Wake up interface. */
440int
441ripng_interface_wakeup (struct thread *t)
442{
443 struct interface *ifp;
444 struct ripng_interface *ri;
445
446 /* Get interface. */
447 ifp = THREAD_ARG (t);
448
449 ri = ifp->info;
450 ri->t_wakeup = NULL;
451
452 /* Join to multicast group. */
453 ripng_multicast_join (ifp);
454
455 /* Send RIP request to the interface. */
456 ripng_request (ifp);
457
458 return 0;
459}
460
461/* Check RIPng is enabed on this interface. */
462void
463ripng_enable_apply (struct interface *ifp)
464{
465 int ret;
466 struct ripng_interface *ri = NULL;
467
468 /* Check interface. */
469 if (if_is_loopback (ifp))
470 return;
471
472 if (! if_is_up (ifp))
473 return;
474
475 ri = ifp->info;
476
477 /* Check network configuration. */
478 ret = ripng_enable_network_lookup (ifp);
479
480 /* If the interface is matched. */
481 if (ret > 0)
482 ri->enable_network = 1;
483 else
484 ri->enable_network = 0;
485
486 /* Check interface name configuration. */
487 ret = ripng_enable_if_lookup (ifp->name);
488 if (ret >= 0)
489 ri->enable_interface = 1;
490 else
491 ri->enable_interface = 0;
492
493 /* Update running status of the interface. */
494 if (ri->enable_network || ri->enable_interface)
495 {
496 if (! ri->running)
497 {
498 if (IS_RIPNG_DEBUG_EVENT)
499 zlog_info ("RIPng turn on %s", ifp->name);
500
501 /* Add interface wake up thread. */
502 if (! ri->t_wakeup)
503 ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup,
504 ifp, 1);
505#if 0
506 /* Join to multicast group. */
507 ripng_multicast_join (ifp);
508
509 /* Send RIP request to the interface. */
510 ripng_request (ifp);
511#endif /* 0 */
512
513 ri->running = 1;
514 }
515 }
516 else
517 {
518 if (ri->running)
519 {
520 if (IS_RIPNG_DEBUG_EVENT)
521 zlog_info ("RIPng turn off %s", ifp->name);
522
523 /* Leave from multicast group. */
524 ripng_multicast_leave (ifp);
525
526 ri->running = 0;
527 }
528 }
529}
530
531/* Set distribute list to all interfaces. */
532static void
533ripng_enable_apply_all ()
534{
535 struct interface *ifp;
536 listnode node;
537
538 for (node = listhead (iflist); node; nextnode (node))
539 {
540 ifp = getdata (node);
541 ripng_enable_apply (ifp);
542 }
543}
544
545/* Vector to store passive-interface name. */
546vector Vripng_passive_interface;
547
548/* Utility function for looking up passive interface settings. */
549int
550ripng_passive_interface_lookup (char *ifname)
551{
552 int i;
553 char *str;
554
555 for (i = 0; i < vector_max (Vripng_passive_interface); i++)
556 if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
557 if (strcmp (str, ifname) == 0)
558 return i;
559 return -1;
560}
561
562void
563ripng_passive_interface_apply (struct interface *ifp)
564{
565 int ret;
566 struct ripng_interface *ri;
567
568 ri = ifp->info;
569
570 ret = ripng_passive_interface_lookup (ifp->name);
571 if (ret < 0)
572 ri->passive = 0;
573 else
574 ri->passive = 1;
575}
576
577void
578ripng_passive_interface_apply_all (void)
579{
580 struct interface *ifp;
581 listnode node;
582
583 for (node = listhead (iflist); node; nextnode (node))
584 {
585 ifp = getdata (node);
586 ripng_passive_interface_apply (ifp);
587 }
588}
589
590/* Passive interface. */
591int
592ripng_passive_interface_set (struct vty *vty, char *ifname)
593{
594 if (ripng_passive_interface_lookup (ifname) >= 0)
595 return CMD_WARNING;
596
597 vector_set (Vripng_passive_interface, strdup (ifname));
598
599 ripng_passive_interface_apply_all ();
600
601 return CMD_SUCCESS;
602}
603
604int
605ripng_passive_interface_unset (struct vty *vty, char *ifname)
606{
607 int i;
608 char *str;
609
610 i = ripng_passive_interface_lookup (ifname);
611 if (i < 0)
612 return CMD_WARNING;
613
614 str = vector_slot (Vripng_passive_interface, i);
615 free (str);
616 vector_unset (Vripng_passive_interface, i);
617
618 ripng_passive_interface_apply_all ();
619
620 return CMD_SUCCESS;
621}
622
623/* Free all configured RIP passive-interface settings. */
624void
625ripng_passive_interface_clean (void)
626{
627 int i;
628 char *str;
629
630 for (i = 0; i < vector_max (Vripng_passive_interface); i++)
631 if ((str = vector_slot (Vripng_passive_interface, i)) != NULL)
632 {
633 free (str);
634 vector_slot (Vripng_passive_interface, i) = NULL;
635 }
636 ripng_passive_interface_apply_all ();
637}
638
639/* Write RIPng enable network and interface to the vty. */
640int
641ripng_network_write (struct vty *vty)
642{
643 int i;
644 char *str;
645 char *ifname;
646 struct route_node *node;
647 char buf[BUFSIZ];
648
649 /* Write enable network. */
650 for (node = route_top (ripng_enable_network); node; node = route_next (node))
651 if (node->info)
652 {
653 struct prefix *p = &node->p;
654 vty_out (vty, " network %s/%d%s",
655 inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ),
656 p->prefixlen,
657 VTY_NEWLINE);
658
659 }
660
661 /* Write enable interface. */
662 for (i = 0; i < vector_max (ripng_enable_if); i++)
663 if ((str = vector_slot (ripng_enable_if, i)) != NULL)
664 vty_out (vty, " network %s%s", str,
665 VTY_NEWLINE);
666
667 /* Write passive interface. */
668 for (i = 0; i < vector_max (Vripng_passive_interface); i++)
669 if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL)
670 vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE);
671
672 return 0;
673}
674
675/* RIPng enable on specified interface or matched network. */
676DEFUN (ripng_network,
677 ripng_network_cmd,
678 "network IF_OR_ADDR",
679 "RIPng enable on specified interface or network.\n"
680 "Interface or address")
681{
682 int ret;
683 struct prefix p;
684
685 ret = str2prefix (argv[0], &p);
686
687 /* Given string is IPv6 network or interface name. */
688 if (ret)
689 ret = ripng_enable_network_add (&p);
690 else
691 ret = ripng_enable_if_add (argv[0]);
692
693 if (ret < 0)
694 {
695 vty_out (vty, "There is same network configuration %s%s", argv[0],
696 VTY_NEWLINE);
697 return CMD_WARNING;
698 }
699
700 ripng_enable_apply_all ();
701
702 return CMD_SUCCESS;
703}
704
705/* RIPng enable on specified interface or matched network. */
706DEFUN (no_ripng_network,
707 no_ripng_network_cmd,
708 "no network IF_OR_ADDR",
709 NO_STR
710 "RIPng enable on specified interface or network.\n"
711 "Interface or address")
712{
713 int ret;
714 struct prefix p;
715
716 ret = str2prefix (argv[0], &p);
717
718 /* Given string is interface name. */
719 if (ret)
720 ret = ripng_enable_network_delete (&p);
721 else
722 ret = ripng_enable_if_delete (argv[0]);
723
724 if (ret < 0)
725 {
726 vty_out (vty, "can't find network %s%s", argv[0],
727 VTY_NEWLINE);
728 return CMD_WARNING;
729 }
730
731 ripng_enable_apply_all ();
732
733 return CMD_SUCCESS;
734}
735
736DEFUN (ripng_passive_interface,
737 ripng_passive_interface_cmd,
738 "passive-interface IFNAME",
739 "Suppress routing updates on an interface\n"
740 "Interface name\n")
741{
742 return ripng_passive_interface_set (vty, argv[0]);
743}
744
745DEFUN (no_ripng_passive_interface,
746 no_ripng_passive_interface_cmd,
747 "no passive-interface IFNAME",
748 NO_STR
749 "Suppress routing updates on an interface\n"
750 "Interface name\n")
751{
752 return ripng_passive_interface_unset (vty, argv[0]);
753}
754
755struct ripng_interface *
756ri_new ()
757{
758 struct ripng_interface *ri;
759 ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface));
760 return ri;
761}
762
763int
764ripng_if_new_hook (struct interface *ifp)
765{
766 ifp->info = ri_new ();
767 return 0;
768}
769
770/* Configuration write function for ripngd. */
771int
772interface_config_write (struct vty *vty)
773{
774 listnode node;
775 struct interface *ifp;
776 struct ripng_interface *ri;
777 int write = 0;
778
779 for (node = listhead (iflist); node; nextnode (node))
780 {
781 ifp = getdata (node);
782 ri = ifp->info;
783
784 vty_out (vty, "interface %s%s", ifp->name,
785 VTY_NEWLINE);
786 if (ifp->desc)
787 vty_out (vty, " description %s%s", ifp->desc,
788 VTY_NEWLINE);
789
790 vty_out (vty, "!%s", VTY_NEWLINE);
791
792 write++;
793 }
794 return write;
795}
796
797/* ripngd's interface node. */
798struct cmd_node interface_node =
799{
800 INTERFACE_NODE,
801 "%s(config-if)# ",
802};
803
804/* Initialization of interface. */
805void
806ripng_if_init ()
807{
808 /* Interface initialize. */
809 iflist = list_new ();
810 if_add_hook (IF_NEW_HOOK, ripng_if_new_hook);
811
812 /* RIPng enable network init. */
813 ripng_enable_network = route_table_init ();
814
815 /* RIPng enable interface init. */
816 ripng_enable_if = vector_init (1);
817
818 /* RIPng passive interface. */
819 Vripng_passive_interface = vector_init (1);
820
821 /* Install interface node. */
822 install_node (&interface_node, interface_config_write);
823
824 install_element (CONFIG_NODE, &interface_cmd);
825 install_element (INTERFACE_NODE, &config_end_cmd);
826 install_element (INTERFACE_NODE, &config_exit_cmd);
827 install_element (INTERFACE_NODE, &config_help_cmd);
828 install_element (INTERFACE_NODE, &interface_desc_cmd);
829 install_element (INTERFACE_NODE, &no_interface_desc_cmd);
830
831 install_element (RIPNG_NODE, &ripng_network_cmd);
832 install_element (RIPNG_NODE, &no_ripng_network_cmd);
833 install_element (RIPNG_NODE, &ripng_passive_interface_cmd);
834 install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd);
835}