From 718e3744195351130f4ce7dbe0613f4b3e23df93 Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 13 Dec 2002 20:15:29 +0000 Subject: Initial revision --- ripngd/ripng_interface.c | 835 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 835 insertions(+) create mode 100644 ripngd/ripng_interface.c (limited to 'ripngd/ripng_interface.c') diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c new file mode 100644 index 00000000..c177381a --- /dev/null +++ b/ripngd/ripng_interface.c @@ -0,0 +1,835 @@ +/* + * Interface related function for RIPng. + * Copyright (C) 1998 Kunihiro Ishiguro + * + * This file is part of GNU Zebra. + * + * GNU Zebra is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * GNU Zebra is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Zebra; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include + +#include "linklist.h" +#include "if.h" +#include "prefix.h" +#include "memory.h" +#include "network.h" +#include "filter.h" +#include "log.h" +#include "stream.h" +#include "zclient.h" +#include "command.h" +#include "table.h" +#include "thread.h" + +#include "ripngd/ripngd.h" +#include "ripngd/ripng_debug.h" + +/* If RFC2133 definition is used. */ +#ifndef IPV6_JOIN_GROUP +#define IPV6_JOIN_GROUP IPV6_ADD_MEMBERSHIP +#endif +#ifndef IPV6_LEAVE_GROUP +#define IPV6_LEAVE_GROUP IPV6_DROP_MEMBERSHIP +#endif + +/* Static utility function. */ +static void ripng_enable_apply (struct interface *); +static void ripng_passive_interface_apply (struct interface *); + +/* Join to the all rip routers multicast group. */ +int +ripng_multicast_join (struct interface *ifp) +{ + int ret; + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (mreq)); + inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *) &mreq, sizeof (mreq)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_JOIN_GROUP: %s", strerror (errno)); + + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng %s join to all-rip-routers multicast group", ifp->name); + + return ret; +} + +/* Leave from the all rip routers multicast group. */ +int +ripng_multicast_leave (struct interface *ifp) +{ + int ret; + struct ipv6_mreq mreq; + + memset (&mreq, 0, sizeof (mreq)); + inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); + mreq.ipv6mr_interface = ifp->ifindex; + + ret = setsockopt (ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char *) &mreq, sizeof (mreq)); + if (ret < 0) + zlog_warn ("can't setsockopt IPV6_LEAVE_GROUP: %s\n", strerror (errno)); + + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng %s leave from all-rip-routers multicast group", + ifp->name); + + return ret; +} + +/* Check max mtu size. */ +int +ripng_check_max_mtu () +{ + listnode node; + struct interface *ifp; + int mtu; + + mtu = 0; + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + if (mtu < ifp->mtu) + mtu = ifp->mtu; + } + return mtu; +} + +int +ripng_if_down (struct interface *ifp) +{ + struct route_node *rp; + struct ripng_info *rinfo; + struct ripng_interface *ri; + + if (ripng->table) + { + for (rp = route_top (ripng->table); rp; rp = route_next (rp)) + if ((rinfo = rp->info) != NULL) + { + /* Routes got through this interface. */ + if (rinfo->ifindex == ifp->ifindex + && rinfo->type == ZEBRA_ROUTE_RIPNG + && rinfo->sub_type == RIPNG_ROUTE_RTE) + { + ripng_zebra_ipv6_delete ((struct prefix_ipv6 *) &rp->p, + &rinfo->nexthop, + rinfo->ifindex); + + RIPNG_TIMER_OFF (rinfo->t_timeout); + RIPNG_TIMER_OFF (rinfo->t_garbage_collect); + + rp->info = NULL; + route_unlock_node (rp); + + ripng_info_free (rinfo); + } + else + { + /* All redistributed routes got through this interface. */ + if (rinfo->ifindex == ifp->ifindex) + ripng_redistribute_delete (rinfo->type, rinfo->sub_type, + (struct prefix_ipv6 *) &rp->p, + rinfo->ifindex); + } + } + } + + ri = ifp->info; + + if (ripng && ri->running) + { + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("turn off %s", ifp->name); + + /* Leave from multicast group. */ + ripng_multicast_leave (ifp); + + ri->running = 0; + } + + return 0; +} + +/* Inteface link up message processing. */ +int +ripng_interface_up (int command, struct zclient *zclient, zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + + /* zebra_interface_state_read() updates interface structure in iflist. */ + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + + if (ifp == NULL) + return 0; + + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("interface up %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* Check if this interface is RIPng enabled or not. */ + ripng_enable_apply (ifp); + + /* Check for a passive interface. */ + ripng_passive_interface_apply (ifp); + + /* Apply distribute list to the all interface. */ + ripng_distribute_update_interface (ifp); + + return 0; +} + +/* Inteface link down message processing. */ +int +ripng_interface_down (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct interface *ifp; + + /* zebra_interface_state_read() updates interface structure in iflist. */ + s = zclient->ibuf; + ifp = zebra_interface_state_read (s); + + if (ifp == NULL) + return 0; + + ripng_if_down (ifp); + + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("interface down %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + return 0; +} + +/* Inteface addition message from zebra. */ +int +ripng_interface_add (int command, struct zclient *zclient, zebra_size_t length) +{ + struct interface *ifp; + + ifp = zebra_interface_add_read (zclient->ibuf); + + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("RIPng interface add %s index %d flags %ld metric %d mtu %d", + ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); + + /* Check is this interface is RIP enabled or not.*/ + ripng_enable_apply (ifp); + + /* Apply distribute list to the interface. */ + ripng_distribute_update_interface (ifp); + + /* Check interface routemap. */ + ripng_if_rmap_update_interface (ifp); + + return 0; +} + +int +ripng_interface_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + return 0; +} + +int +ripng_interface_address_add (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *c; + struct prefix *p; + char buf[INET6_ADDRSTRLEN]; + + c = zebra_interface_address_add_read (zclient->ibuf); + + if (c == NULL) + return 0; + + p = c->address; + + if (p->family == AF_INET6) + { + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("RIPng connected address %s/%d add", + inet_ntop (AF_INET6, &p->u.prefix6, buf, INET6_ADDRSTRLEN), + p->prefixlen); + + /* Check is this interface is RIP enabled or not.*/ + ripng_enable_apply (c->ifp); + } + + return 0; +} + +int +ripng_interface_address_delete (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct connected *ifc; + struct prefix *p; + char buf[INET6_ADDRSTRLEN]; + + ifc = zebra_interface_address_delete_read (zclient->ibuf); + + if (ifc) + { + p = ifc->address; + + if (p->family == AF_INET6) + { + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_info ("RIPng connected address %s/%d delete", + inet_ntop (AF_INET6, &p->u.prefix6, buf, + INET6_ADDRSTRLEN), + p->prefixlen); + + /* Check is this interface is RIP enabled or not.*/ + ripng_enable_apply (ifc->ifp); + } + connected_free (ifc); + } + + return 0; +} + +/* RIPng enable interface vector. */ +vector ripng_enable_if; + +/* RIPng enable network table. */ +struct route_table *ripng_enable_network; + +/* Lookup RIPng enable network. */ +int +ripng_enable_network_lookup (struct interface *ifp) +{ + listnode listnode; + struct connected *connected; + + for (listnode = listhead (ifp->connected); listnode; nextnode (listnode)) + if ((connected = getdata (listnode)) != NULL) + { + struct prefix *p; + struct route_node *node; + + p = connected->address; + + if (p->family == AF_INET6) + { + node = route_node_match (ripng_enable_network, p); + if (node) + { + route_unlock_node (node); + return 1; + } + } + } + return -1; +} + +/* Add RIPng enable network. */ +int +ripng_enable_network_add (struct prefix *p) +{ + struct route_node *node; + + node = route_node_get (ripng_enable_network, p); + + if (node->info) + { + route_unlock_node (node); + return -1; + } + else + node->info = "enabled"; + + return 1; +} + +/* Delete RIPng enable network. */ +int +ripng_enable_network_delete (struct prefix *p) +{ + struct route_node *node; + + node = route_node_lookup (ripng_enable_network, p); + if (node) + { + node->info = NULL; + + /* Unlock info lock. */ + route_unlock_node (node); + + /* Unlock lookup lock. */ + route_unlock_node (node); + + return 1; + } + return -1; +} + +/* Lookup function. */ +int +ripng_enable_if_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (ripng_enable_if); i++) + if ((str = vector_slot (ripng_enable_if, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +/* Add interface to ripng_enable_if. */ +int +ripng_enable_if_add (char *ifname) +{ + int ret; + + ret = ripng_enable_if_lookup (ifname); + if (ret >= 0) + return -1; + + vector_set (ripng_enable_if, strdup (ifname)); + + return 1; +} + +/* Delete interface from ripng_enable_if. */ +int +ripng_enable_if_delete (char *ifname) +{ + int index; + char *str; + + index = ripng_enable_if_lookup (ifname); + if (index < 0) + return -1; + + str = vector_slot (ripng_enable_if, index); + free (str); + vector_unset (ripng_enable_if, index); + + return 1; +} + +/* Wake up interface. */ +int +ripng_interface_wakeup (struct thread *t) +{ + struct interface *ifp; + struct ripng_interface *ri; + + /* Get interface. */ + ifp = THREAD_ARG (t); + + ri = ifp->info; + ri->t_wakeup = NULL; + + /* Join to multicast group. */ + ripng_multicast_join (ifp); + + /* Send RIP request to the interface. */ + ripng_request (ifp); + + return 0; +} + +/* Check RIPng is enabed on this interface. */ +void +ripng_enable_apply (struct interface *ifp) +{ + int ret; + struct ripng_interface *ri = NULL; + + /* Check interface. */ + if (if_is_loopback (ifp)) + return; + + if (! if_is_up (ifp)) + return; + + ri = ifp->info; + + /* Check network configuration. */ + ret = ripng_enable_network_lookup (ifp); + + /* If the interface is matched. */ + if (ret > 0) + ri->enable_network = 1; + else + ri->enable_network = 0; + + /* Check interface name configuration. */ + ret = ripng_enable_if_lookup (ifp->name); + if (ret >= 0) + ri->enable_interface = 1; + else + ri->enable_interface = 0; + + /* Update running status of the interface. */ + if (ri->enable_network || ri->enable_interface) + { + if (! ri->running) + { + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng turn on %s", ifp->name); + + /* Add interface wake up thread. */ + if (! ri->t_wakeup) + ri->t_wakeup = thread_add_timer (master, ripng_interface_wakeup, + ifp, 1); +#if 0 + /* Join to multicast group. */ + ripng_multicast_join (ifp); + + /* Send RIP request to the interface. */ + ripng_request (ifp); +#endif /* 0 */ + + ri->running = 1; + } + } + else + { + if (ri->running) + { + if (IS_RIPNG_DEBUG_EVENT) + zlog_info ("RIPng turn off %s", ifp->name); + + /* Leave from multicast group. */ + ripng_multicast_leave (ifp); + + ri->running = 0; + } + } +} + +/* Set distribute list to all interfaces. */ +static void +ripng_enable_apply_all () +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ripng_enable_apply (ifp); + } +} + +/* Vector to store passive-interface name. */ +vector Vripng_passive_interface; + +/* Utility function for looking up passive interface settings. */ +int +ripng_passive_interface_lookup (char *ifname) +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vripng_passive_interface); i++) + if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +void +ripng_passive_interface_apply (struct interface *ifp) +{ + int ret; + struct ripng_interface *ri; + + ri = ifp->info; + + ret = ripng_passive_interface_lookup (ifp->name); + if (ret < 0) + ri->passive = 0; + else + ri->passive = 1; +} + +void +ripng_passive_interface_apply_all (void) +{ + struct interface *ifp; + listnode node; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ripng_passive_interface_apply (ifp); + } +} + +/* Passive interface. */ +int +ripng_passive_interface_set (struct vty *vty, char *ifname) +{ + if (ripng_passive_interface_lookup (ifname) >= 0) + return CMD_WARNING; + + vector_set (Vripng_passive_interface, strdup (ifname)); + + ripng_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +int +ripng_passive_interface_unset (struct vty *vty, char *ifname) +{ + int i; + char *str; + + i = ripng_passive_interface_lookup (ifname); + if (i < 0) + return CMD_WARNING; + + str = vector_slot (Vripng_passive_interface, i); + free (str); + vector_unset (Vripng_passive_interface, i); + + ripng_passive_interface_apply_all (); + + return CMD_SUCCESS; +} + +/* Free all configured RIP passive-interface settings. */ +void +ripng_passive_interface_clean (void) +{ + int i; + char *str; + + for (i = 0; i < vector_max (Vripng_passive_interface); i++) + if ((str = vector_slot (Vripng_passive_interface, i)) != NULL) + { + free (str); + vector_slot (Vripng_passive_interface, i) = NULL; + } + ripng_passive_interface_apply_all (); +} + +/* Write RIPng enable network and interface to the vty. */ +int +ripng_network_write (struct vty *vty) +{ + int i; + char *str; + char *ifname; + struct route_node *node; + char buf[BUFSIZ]; + + /* Write enable network. */ + for (node = route_top (ripng_enable_network); node; node = route_next (node)) + if (node->info) + { + struct prefix *p = &node->p; + vty_out (vty, " network %s/%d%s", + inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ), + p->prefixlen, + VTY_NEWLINE); + + } + + /* Write enable interface. */ + for (i = 0; i < vector_max (ripng_enable_if); i++) + if ((str = vector_slot (ripng_enable_if, i)) != NULL) + vty_out (vty, " network %s%s", str, + VTY_NEWLINE); + + /* Write passive interface. */ + for (i = 0; i < vector_max (Vripng_passive_interface); i++) + if ((ifname = vector_slot (Vripng_passive_interface, i)) != NULL) + vty_out (vty, " passive-interface %s%s", ifname, VTY_NEWLINE); + + return 0; +} + +/* RIPng enable on specified interface or matched network. */ +DEFUN (ripng_network, + ripng_network_cmd, + "network IF_OR_ADDR", + "RIPng enable on specified interface or network.\n" + "Interface or address") +{ + int ret; + struct prefix p; + + ret = str2prefix (argv[0], &p); + + /* Given string is IPv6 network or interface name. */ + if (ret) + ret = ripng_enable_network_add (&p); + else + ret = ripng_enable_if_add (argv[0]); + + if (ret < 0) + { + vty_out (vty, "There is same network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + ripng_enable_apply_all (); + + return CMD_SUCCESS; +} + +/* RIPng enable on specified interface or matched network. */ +DEFUN (no_ripng_network, + no_ripng_network_cmd, + "no network IF_OR_ADDR", + NO_STR + "RIPng enable on specified interface or network.\n" + "Interface or address") +{ + int ret; + struct prefix p; + + ret = str2prefix (argv[0], &p); + + /* Given string is interface name. */ + if (ret) + ret = ripng_enable_network_delete (&p); + else + ret = ripng_enable_if_delete (argv[0]); + + if (ret < 0) + { + vty_out (vty, "can't find network %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + ripng_enable_apply_all (); + + return CMD_SUCCESS; +} + +DEFUN (ripng_passive_interface, + ripng_passive_interface_cmd, + "passive-interface IFNAME", + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return ripng_passive_interface_set (vty, argv[0]); +} + +DEFUN (no_ripng_passive_interface, + no_ripng_passive_interface_cmd, + "no passive-interface IFNAME", + NO_STR + "Suppress routing updates on an interface\n" + "Interface name\n") +{ + return ripng_passive_interface_unset (vty, argv[0]); +} + +struct ripng_interface * +ri_new () +{ + struct ripng_interface *ri; + ri = XCALLOC (MTYPE_IF, sizeof (struct ripng_interface)); + return ri; +} + +int +ripng_if_new_hook (struct interface *ifp) +{ + ifp->info = ri_new (); + return 0; +} + +/* Configuration write function for ripngd. */ +int +interface_config_write (struct vty *vty) +{ + listnode node; + struct interface *ifp; + struct ripng_interface *ri; + int write = 0; + + for (node = listhead (iflist); node; nextnode (node)) + { + ifp = getdata (node); + ri = ifp->info; + + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + vty_out (vty, "!%s", VTY_NEWLINE); + + write++; + } + return write; +} + +/* ripngd's interface node. */ +struct cmd_node interface_node = +{ + INTERFACE_NODE, + "%s(config-if)# ", +}; + +/* Initialization of interface. */ +void +ripng_if_init () +{ + /* Interface initialize. */ + iflist = list_new (); + if_add_hook (IF_NEW_HOOK, ripng_if_new_hook); + + /* RIPng enable network init. */ + ripng_enable_network = route_table_init (); + + /* RIPng enable interface init. */ + ripng_enable_if = vector_init (1); + + /* RIPng passive interface. */ + Vripng_passive_interface = vector_init (1); + + /* Install interface node. */ + install_node (&interface_node, interface_config_write); + + install_element (CONFIG_NODE, &interface_cmd); + install_element (INTERFACE_NODE, &config_end_cmd); + install_element (INTERFACE_NODE, &config_exit_cmd); + install_element (INTERFACE_NODE, &config_help_cmd); + install_element (INTERFACE_NODE, &interface_desc_cmd); + install_element (INTERFACE_NODE, &no_interface_desc_cmd); + + install_element (RIPNG_NODE, &ripng_network_cmd); + install_element (RIPNG_NODE, &no_ripng_network_cmd); + install_element (RIPNG_NODE, &ripng_passive_interface_cmd); + install_element (RIPNG_NODE, &no_ripng_passive_interface_cmd); +} -- cgit v1.2.1