/* * 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 this program; see the file COPYING; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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 "privs.h" #include "vrf.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 *); static int ripng_enable_if_lookup(const char *); static int ripng_enable_network_lookup2(struct connected *); static void ripng_enable_apply_all(void); /* Join to the all rip routers multicast group. */ static int ripng_multicast_join(struct interface *ifp) { int ret; struct ipv6_mreq mreq; int save_errno; if (if_is_multicast(ifp)) { memset(&mreq, 0, sizeof(mreq)); inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; /* * NetBSD 1.6.2 requires root to join groups on gif(4). * While this is bogus, privs are available and easy to use * for this call as a workaround. */ if (ripngd_privs.change(ZPRIVS_RAISE)) zlog_err("ripng_multicast_join: could not raise privs"); ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq, sizeof(mreq)); save_errno = errno; if (ripngd_privs.change(ZPRIVS_LOWER)) zlog_err("ripng_multicast_join: could not lower privs"); if (ret < 0 && save_errno == EADDRINUSE) { /* * Group is already joined. This occurs due to sloppy * group * management, in particular declining to leave the * group on * an interface that has just gone down. */ zlog_warn("ripng join on %s EADDRINUSE (ignoring)\n", ifp->name); return 0; /* not an error */ } if (ret < 0) zlog_warn("can't setsockopt IPV6_JOIN_GROUP: %s", safe_strerror(save_errno)); if (IS_RIPNG_DEBUG_EVENT) zlog_debug( "RIPng %s join to all-rip-routers multicast group", ifp->name); if (ret < 0) return -1; } return 0; } /* Leave from the all rip routers multicast group. */ static int ripng_multicast_leave(struct interface *ifp) { int ret; struct ipv6_mreq mreq; if (if_is_multicast(ifp)) { 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", safe_strerror(errno)); if (IS_RIPNG_DEBUG_EVENT) zlog_debug( "RIPng %s leave from all-rip-routers multicast group", ifp->name); if (ret < 0) return -1; } return 0; } /* How many link local IPv6 address could be used on the interface ? */ static int ripng_if_ipv6_lladdress_check(struct interface *ifp) { struct listnode *nn; struct connected *connected; int count = 0; for (ALL_LIST_ELEMENTS_RO(ifp->connected, nn, connected)) { struct prefix *p; p = connected->address; if ((p->family == AF_INET6) && IN6_IS_ADDR_LINKLOCAL(&p->u.prefix6)) count++; } return count; } static int ripng_if_down(struct interface *ifp) { struct route_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; struct list *list = NULL; struct listnode *listnode = NULL, *nextnode = NULL; if (ripng) for (rp = route_top(ripng->table); rp; rp = route_next(rp)) if ((list = rp->info) != NULL) for (ALL_LIST_ELEMENTS(list, listnode, nextnode, rinfo)) if (rinfo->ifindex == ifp->ifindex) ripng_ecmp_delete(rinfo); ri = ifp->info; if (ri->running) { if (IS_RIPNG_DEBUG_EVENT) zlog_debug("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, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; ifp = zebra_interface_state_read(s, vrf_id); if (ifp == NULL) return 0; if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( "interface up %s index %d flags %llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); /* 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, vrf_id_t vrf_id) { struct stream *s; struct interface *ifp; /* zebra_interface_state_read() updates interface structure in iflist. */ s = zclient->ibuf; ifp = zebra_interface_state_read(s, vrf_id); if (ifp == NULL) return 0; ripng_if_down(ifp); if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( "interface down %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); return 0; } /* Inteface addition message from zebra. */ int ripng_interface_add(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct interface *ifp; ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( "RIPng interface add %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); /* 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, vrf_id_t vrf_id) { struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read(s, vrf_id); if (ifp == NULL) return 0; if (if_is_up(ifp)) { ripng_if_down(ifp); } zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d", ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); /* To support pseudo interface do not free interface structure. */ /* if_delete(ifp); */ if_set_index(ifp, IFINDEX_INTERNAL); return 0; } void ripng_interface_clean(void) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; struct ripng_interface *ri; FOR_ALL_INTERFACES (vrf, ifp) { ri = ifp->info; ri->enable_network = 0; ri->enable_interface = 0; ri->running = 0; if (ri->t_wakeup) { thread_cancel(ri->t_wakeup); ri->t_wakeup = NULL; } } } void ripng_interface_reset(void) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; struct ripng_interface *ri; FOR_ALL_INTERFACES (vrf, ifp) { ri = ifp->info; ri->enable_network = 0; ri->enable_interface = 0; ri->running = 0; ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; ri->split_horizon_default = RIPNG_NO_SPLIT_HORIZON; ri->list[RIPNG_FILTER_IN] = NULL; ri->list[RIPNG_FILTER_OUT] = NULL; ri->prefix[RIPNG_FILTER_IN] = NULL; ri->prefix[RIPNG_FILTER_OUT] = NULL; if (ri->t_wakeup) { thread_cancel(ri->t_wakeup); ri->t_wakeup = NULL; } ri->passive = 0; } } static void ripng_apply_address_add(struct connected *ifc) { struct prefix_ipv6 address; struct prefix *p; if (!ripng) return; if (!if_is_up(ifc->ifp)) return; p = ifc->address; memset(&address, 0, sizeof(address)); address.family = p->family; address.prefix = p->u.prefix6; address.prefixlen = p->prefixlen; apply_mask_ipv6(&address); /* Check if this interface is RIP enabled or not or Check if this address's prefix is RIP enabled */ if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) || (ripng_enable_network_lookup2(ifc) >= 0)) ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, ifc->ifp->ifindex, NULL, 0); } int ripng_interface_address_add(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *c; struct prefix *p; c = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_ADD, zclient->ibuf, vrf_id); if (c == NULL) return 0; p = c->address; if (p->family == AF_INET6) { struct ripng_interface *ri = c->ifp->info; if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug("RIPng connected address %s/%d add", inet6_ntoa(p->u.prefix6), p->prefixlen); /* Check is this prefix needs to be redistributed. */ ripng_apply_address_add(c); /* Let's try once again whether the interface could be activated */ if (!ri->running) { /* Check if this interface is RIP enabled or not.*/ ripng_enable_apply(c->ifp); /* Apply distribute list to the interface. */ ripng_distribute_update_interface(c->ifp); /* Check interface routemap. */ ripng_if_rmap_update_interface(c->ifp); } } return 0; } static void ripng_apply_address_del(struct connected *ifc) { struct prefix_ipv6 address; struct prefix *p; if (!ripng) return; if (!if_is_up(ifc->ifp)) return; p = ifc->address; memset(&address, 0, sizeof(address)); address.family = p->family; address.prefix = p->u.prefix6; address.prefixlen = p->prefixlen; apply_mask_ipv6(&address); ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, ifc->ifp->ifindex); } int ripng_interface_address_delete(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { struct connected *ifc; struct prefix *p; char buf[INET6_ADDRSTRLEN]; ifc = zebra_interface_address_read(ZEBRA_INTERFACE_ADDRESS_DELETE, zclient->ibuf, vrf_id); if (ifc) { p = ifc->address; if (p->family == AF_INET6) { if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( "RIPng connected address %s/%d delete", inet_ntop(AF_INET6, &p->u.prefix6, buf, INET6_ADDRSTRLEN), p->prefixlen); /* Check wether this prefix needs to be removed. */ ripng_apply_address_del(ifc); } 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. */ /* Check wether the interface has at least a connected prefix that * is within the ripng_enable_network table. */ static int ripng_enable_network_lookup_if(struct interface *ifp) { struct listnode *node; struct connected *connected; struct prefix_ipv6 address; for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { struct prefix *p; struct route_node *n; p = connected->address; if (p->family == AF_INET6) { address.family = AF_INET6; address.prefix = p->u.prefix6; address.prefixlen = IPV6_MAX_BITLEN; n = route_node_match(ripng_enable_network, (struct prefix *)&address); if (n) { route_unlock_node(n); return 1; } } } return -1; } /* Check wether connected is within the ripng_enable_network table. */ static int ripng_enable_network_lookup2(struct connected *connected) { struct prefix_ipv6 address; struct prefix *p; p = connected->address; if (p->family == AF_INET6) { struct route_node *node; address.family = p->family; address.prefix = p->u.prefix6; address.prefixlen = IPV6_MAX_BITLEN; /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within * ripng_enable_network */ node = route_node_match(ripng_enable_network, (struct prefix *)&address); if (node) { route_unlock_node(node); return 1; } } return -1; } /* Add RIPng enable network. */ static 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 = (void *)1; /* XXX: One should find a better solution than a generic one */ ripng_enable_apply_all(); return 1; } /* Delete RIPng enable network. */ static 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. */ static int ripng_enable_if_lookup(const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active(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. */ static int ripng_enable_if_add(const char *ifname) { int ret; ret = ripng_enable_if_lookup(ifname); if (ret >= 0) return -1; vector_set(ripng_enable_if, strdup(ifname)); ripng_enable_apply_all(); return 1; } /* Delete interface from ripng_enable_if. */ static int ripng_enable_if_delete(const 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); ripng_enable_apply_all(); return 1; } /* Wake up interface. */ static 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. */ if (ripng_multicast_join(ifp) < 0) { zlog_err("multicast join failed, interface %s not running", ifp->name); return 0; } /* Set running flag. */ ri->running = 1; /* Send RIP request to the interface. */ ripng_request(ifp); return 0; } static void ripng_connect_set(struct interface *ifp, int set) { struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv6 address; for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) { struct prefix *p; p = connected->address; if (p->family != AF_INET6) continue; address.family = AF_INET6; address.prefix = p->u.prefix6; address.prefixlen = p->prefixlen; apply_mask_ipv6(&address); if (set) { /* Check once more wether this prefix is within a * "network IF_OR_PREF" one */ if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) || (ripng_enable_network_lookup2(connected) >= 0)) ripng_redistribute_add( ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, connected->ifp->ifindex, NULL, 0); } else { ripng_redistribute_delete( ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, connected->ifp->ifindex); if (ripng_redistribute_check(ZEBRA_ROUTE_CONNECT)) ripng_redistribute_add( ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE, &address, connected->ifp->ifindex, NULL, 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_up(ifp)) return; ri = ifp->info; /* Is this interface a candidate for RIPng ? */ ret = ripng_enable_network_lookup_if(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; /* any candidate interface MUST have a link-local IPv6 address */ if ((!ripng_if_ipv6_lladdress_check(ifp)) && (ri->enable_network || ri->enable_interface)) { ri->enable_network = 0; ri->enable_interface = 0; zlog_warn("Interface %s does not have any link-local address", ifp->name); } /* Update running status of the interface. */ if (ri->enable_network || ri->enable_interface) { zlog_info("RIPng INTERFACE ON %s", ifp->name); /* Add interface wake up thread. */ thread_add_timer(master, ripng_interface_wakeup, ifp, 1, &ri->t_wakeup); ripng_connect_set(ifp, 1); } else { if (ri->running) { /* Might as well clean up the route table as well * ripng_if_down sets to 0 ri->running, and displays *"turn off %s" **/ ripng_if_down(ifp); ripng_connect_set(ifp, 0); } } } /* Set distribute list to all interfaces. */ static void ripng_enable_apply_all(void) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; FOR_ALL_INTERFACES (vrf, ifp) ripng_enable_apply(ifp); } /* Clear all network and neighbor configuration */ void ripng_clean_network() { unsigned int i; char *str; struct route_node *rn; /* ripng_enable_network */ for (rn = route_top(ripng_enable_network); rn; rn = route_next(rn)) if (rn->info) { rn->info = NULL; route_unlock_node(rn); } /* ripng_enable_if */ for (i = 0; i < vector_active(ripng_enable_if); i++) if ((str = vector_slot(ripng_enable_if, i)) != NULL) { free(str); vector_slot(ripng_enable_if, i) = NULL; } } /* Vector to store passive-interface name. */ vector Vripng_passive_interface; /* Utility function for looking up passive interface settings. */ static int ripng_passive_interface_lookup(const char *ifname) { unsigned int i; char *str; for (i = 0; i < vector_active(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; } static void ripng_passive_interface_apply_all(void) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; FOR_ALL_INTERFACES (vrf, ifp) ripng_passive_interface_apply(ifp); } /* Passive interface. */ static int ripng_passive_interface_set(struct vty *vty, const char *ifname) { if (ripng_passive_interface_lookup(ifname) >= 0) return CMD_WARNING_CONFIG_FAILED; vector_set(Vripng_passive_interface, strdup(ifname)); ripng_passive_interface_apply_all(); return CMD_SUCCESS; } static int ripng_passive_interface_unset(struct vty *vty, const char *ifname) { int i; char *str; i = ripng_passive_interface_lookup(ifname); if (i < 0) return CMD_WARNING_CONFIG_FAILED; 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) { unsigned int i; char *str; for (i = 0; i < vector_active(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 config_mode) { unsigned int i; const 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, "%s%s/%d\n", config_mode ? " network " : " ", inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); } /* Write enable interface. */ for (i = 0; i < vector_active(ripng_enable_if); i++) if ((ifname = vector_slot(ripng_enable_if, i)) != NULL) vty_out(vty, "%s%s\n", config_mode ? " network " : " ", ifname); /* Write passive interface. */ if (config_mode) for (i = 0; i < vector_active(Vripng_passive_interface); i++) if ((ifname = vector_slot(Vripng_passive_interface, i)) != NULL) vty_out(vty, " passive-interface %s\n", ifname); 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\n") { int idx_if_or_addr = 1; int ret; struct prefix p; ret = str2prefix(argv[idx_if_or_addr]->arg, &p); /* Given string is IPv6 network or interface name. */ if (ret) ret = ripng_enable_network_add(&p); else ret = ripng_enable_if_add(argv[idx_if_or_addr]->arg); if (ret < 0) { vty_out(vty, "There is same network configuration %s\n", argv[idx_if_or_addr]->arg); return CMD_WARNING_CONFIG_FAILED; } 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\n") { int idx_if_or_addr = 2; int ret; struct prefix p; ret = str2prefix(argv[idx_if_or_addr]->arg, &p); /* Given string is interface name. */ if (ret) ret = ripng_enable_network_delete(&p); else ret = ripng_enable_if_delete(argv[idx_if_or_addr]->arg); if (ret < 0) { vty_out(vty, "can't find network %s\n", argv[idx_if_or_addr]->arg); return CMD_WARNING_CONFIG_FAILED; } return CMD_SUCCESS; } DEFUN (ipv6_ripng_split_horizon, ipv6_ripng_split_horizon_cmd, "ipv6 ripng split-horizon", IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n") { VTY_DECLVAR_CONTEXT(interface, ifp); struct ripng_interface *ri; ri = ifp->info; ri->split_horizon = RIPNG_SPLIT_HORIZON; return CMD_SUCCESS; } DEFUN (ipv6_ripng_split_horizon_poisoned_reverse, ipv6_ripng_split_horizon_poisoned_reverse_cmd, "ipv6 ripng split-horizon poisoned-reverse", IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") { VTY_DECLVAR_CONTEXT(interface, ifp); struct ripng_interface *ri; ri = ifp->info; ri->split_horizon = RIPNG_SPLIT_HORIZON_POISONED_REVERSE; return CMD_SUCCESS; } DEFUN (no_ipv6_ripng_split_horizon, no_ipv6_ripng_split_horizon_cmd, "no ipv6 ripng split-horizon [poisoned-reverse]", NO_STR IPV6_STR "Routing Information Protocol\n" "Perform split horizon\n" "With poisoned-reverse\n") { VTY_DECLVAR_CONTEXT(interface, ifp); struct ripng_interface *ri; ri = ifp->info; ri->split_horizon = RIPNG_NO_SPLIT_HORIZON; return CMD_SUCCESS; } DEFUN (ripng_passive_interface, ripng_passive_interface_cmd, "passive-interface IFNAME", "Suppress routing updates on an interface\n" "Interface name\n") { int idx_ifname = 1; return ripng_passive_interface_set(vty, argv[idx_ifname]->arg); } 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") { int idx_ifname = 2; return ripng_passive_interface_unset(vty, argv[idx_ifname]->arg); } static struct ripng_interface *ri_new(void) { struct ripng_interface *ri; ri = XCALLOC(MTYPE_IF, sizeof(struct ripng_interface)); /* Set default split-horizon behavior. If the interface is Frame Relay or SMDS is enabled, the default value for split-horizon is off. But currently Zebra does detect Frame Relay or SMDS interface. So all interface is set to split horizon. */ ri->split_horizon_default = RIPNG_SPLIT_HORIZON; ri->split_horizon = ri->split_horizon_default; return ri; } static int ripng_if_new_hook(struct interface *ifp) { ifp->info = ri_new(); return 0; } /* Called when interface structure deleted. */ static int ripng_if_delete_hook(struct interface *ifp) { XFREE(MTYPE_IF, ifp->info); ifp->info = NULL; return 0; } /* Configuration write function for ripngd. */ static int interface_config_write(struct vty *vty) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; struct ripng_interface *ri; int write = 0; FOR_ALL_INTERFACES (vrf, ifp) { ri = ifp->info; /* Do not display the interface if there is no * configuration about it. **/ if ((!ifp->desc) && (ri->split_horizon == ri->split_horizon_default)) continue; vty_frame(vty, "interface %s\n", ifp->name); if (ifp->desc) vty_out(vty, " description %s\n", ifp->desc); /* Split horizon. */ if (ri->split_horizon != ri->split_horizon_default) { switch (ri->split_horizon) { case RIPNG_SPLIT_HORIZON: vty_out(vty, " ipv6 ripng split-horizon\n"); break; case RIPNG_SPLIT_HORIZON_POISONED_REVERSE: vty_out(vty, " ipv6 ripng split-horizon poisoned-reverse\n"); break; case RIPNG_NO_SPLIT_HORIZON: default: vty_out(vty, " no ipv6 ripng split-horizon\n"); break; } } vty_endframe(vty, "!\n"); write++; } return write; } /* ripngd's interface node. */ static struct cmd_node interface_node = { INTERFACE_NODE, "%s(config-if)# ", 1 /* VTYSH */ }; /* Initialization of interface. */ void ripng_if_init() { /* Interface initialize. */ hook_register_prio(if_add, 0, ripng_if_new_hook); hook_register_prio(if_del, 0, ripng_if_delete_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); if_cmd_init(); 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); install_element(INTERFACE_NODE, &ipv6_ripng_split_horizon_cmd); install_element(INTERFACE_NODE, &ipv6_ripng_split_horizon_poisoned_reverse_cmd); install_element(INTERFACE_NODE, &no_ipv6_ripng_split_horizon_cmd); }