]> git.proxmox.com Git - mirror_frr.git/blob - ripngd/ripng_interface.c
Initial revision
[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
38 #include "ripngd/ripngd.h"
39 #include "ripngd/ripng_debug.h"
40 \f
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. */
50 static void ripng_enable_apply (struct interface *);
51 static void ripng_passive_interface_apply (struct interface *);
52
53 /* Join to the all rip routers multicast group. */
54 int
55 ripng_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. */
76 int
77 ripng_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. */
99 int
100 ripng_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
116 int
117 ripng_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. */
173 int
174 ripng_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. */
203 int
204 ripng_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. */
227 int
228 ripng_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
250 int
251 ripng_interface_delete (int command, struct zclient *zclient,
252 zebra_size_t length)
253 {
254 return 0;
255 }
256
257 int
258 ripng_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
286 int
287 ripng_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 \f
317 /* RIPng enable interface vector. */
318 vector ripng_enable_if;
319
320 /* RIPng enable network table. */
321 struct route_table *ripng_enable_network;
322
323 /* Lookup RIPng enable network. */
324 int
325 ripng_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. */
352 int
353 ripng_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. */
371 int
372 ripng_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. */
393 int
394 ripng_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. */
407 int
408 ripng_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. */
422 int
423 ripng_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. */
440 int
441 ripng_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. */
462 void
463 ripng_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. */
532 static void
533 ripng_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 \f
545 /* Vector to store passive-interface name. */
546 vector Vripng_passive_interface;
547
548 /* Utility function for looking up passive interface settings. */
549 int
550 ripng_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
562 void
563 ripng_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
577 void
578 ripng_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. */
591 int
592 ripng_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
604 int
605 ripng_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. */
624 void
625 ripng_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. */
640 int
641 ripng_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. */
676 DEFUN (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. */
706 DEFUN (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
736 DEFUN (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
745 DEFUN (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 \f
755 struct ripng_interface *
756 ri_new ()
757 {
758 struct ripng_interface *ri;
759 ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface));
760 return ri;
761 }
762
763 int
764 ripng_if_new_hook (struct interface *ifp)
765 {
766 ifp->info = ri_new ();
767 return 0;
768 }
769
770 /* Configuration write function for ripngd. */
771 int
772 interface_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. */
798 struct cmd_node interface_node =
799 {
800 INTERFACE_NODE,
801 "%s(config-if)# ",
802 };
803
804 /* Initialization of interface. */
805 void
806 ripng_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 }