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
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}
836