📄 rip_interface.c
字号:
/* Interface related function for RIP. * Copyright (C) 1997, 98 Kunihiro Ishiguro <kunihiro@zebra.org> * * 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 <zebra.h>#include "command.h"#include "if.h"#include "sockunion.h"#include "prefix.h"#include "memory.h"#include "network.h"#include "table.h"#include "log.h"#include "stream.h"#include "thread.h"#include "zclient.h"#include "filter.h"#include "sockopt.h"#include "zebra/connected.h"#include "ripd/ripd.h"#include "ripd/rip_debug.h"void rip_enable_apply (struct interface *);void rip_passive_interface_apply (struct interface *);int rip_if_down(struct interface *ifp);struct message ri_version_msg[] = { {RI_RIP_VERSION_1, "1"}, {RI_RIP_VERSION_2, "2"}, {RI_RIP_VERSION_1_AND_2, "1 2"}, {0, NULL}};/* RIP enabled network vector. */vector rip_enable_interface;/* RIP enabled interface table. */struct route_table *rip_enable_network;/* Vector to store passive-interface name. */vector Vrip_passive_interface;/* Join to the RIP version 2 multicast group. */intipv4_multicast_join (int sock, struct in_addr group, struct in_addr ifa, unsigned int ifindex){ int ret; ret = setsockopt_multicast_ipv4 (sock, IP_ADD_MEMBERSHIP, ifa, group.s_addr, ifindex); if (ret < 0) zlog (NULL, LOG_INFO, "can't setsockopt IP_ADD_MEMBERSHIP %s", strerror (errno)); return ret;}/* Leave from the RIP version 2 multicast group. */intipv4_multicast_leave (int sock, struct in_addr group, struct in_addr ifa, unsigned int ifindex){ int ret; ret = setsockopt_multicast_ipv4 (sock, IP_DROP_MEMBERSHIP, ifa, group.s_addr, ifindex); if (ret < 0) zlog (NULL, LOG_INFO, "can't setsockopt IP_DROP_MEMBERSHIP"); return ret;}/* Allocate new RIP's interface configuration. */struct rip_interface *rip_interface_new (){ struct rip_interface *ri; ri = XMALLOC (MTYPE_RIP_INTERFACE, sizeof (struct rip_interface)); memset (ri, 0, sizeof (struct rip_interface)); /* Default authentication type is simple password for Cisco compatibility. */ /* ri->auth_type = RIP_NO_AUTH; */ ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; /* 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 = 1; ri->split_horizon = ri->split_horizon_default; return ri;}voidrip_interface_multicast_set (int sock, struct interface *ifp){ int ret; listnode node; struct servent *sp; struct sockaddr_in from; for (node = listhead (ifp->connected); node; nextnode (node)) { struct prefix_ipv4 *p; struct connected *connected; struct in_addr addr; connected = getdata (node); p = (struct prefix_ipv4 *) connected->address; if (p->family == AF_INET) { addr = p->prefix; if (setsockopt_multicast_ipv4 (sock, IP_MULTICAST_IF, addr, 0, ifp->ifindex) < 0) { zlog_warn ("Can't setsockopt IP_MULTICAST_IF to fd %d", sock); return; } /* Bind myself. */ memset (&from, 0, sizeof (struct sockaddr_in)); /* Set RIP port. */ sp = getservbyname ("router", "udp"); if (sp) from.sin_port = sp->s_port; else from.sin_port = htons (RIP_PORT_DEFAULT); /* Address shoud be any address. */ from.sin_family = AF_INET; from.sin_addr = addr;#ifdef HAVE_SIN_LEN from.sin_len = sizeof (struct sockaddr_in);#endif /* HAVE_SIN_LEN */ ret = bind (sock, (struct sockaddr *) & from, sizeof (struct sockaddr_in)); if (ret < 0) { zlog_warn ("Can't bind socket: %s", strerror (errno)); return; } return; } }}/* Send RIP request packet to specified interface. */voidrip_request_interface_send (struct interface *ifp, u_char version){ struct sockaddr_in to; /* RIPv2 support multicast. */ if (version == RIPv2 && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_info ("multicast request on %s", ifp->name); rip_request_send (NULL, ifp, version); return; } /* RIPv1 and non multicast interface. */ if (if_is_pointopoint (ifp) || if_is_broadcast (ifp)) { listnode cnode; if (IS_RIP_DEBUG_EVENT) zlog_info ("broadcast request to %s", ifp->name); for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) { struct prefix_ipv4 *p; struct connected *connected; connected = getdata (cnode); p = (struct prefix_ipv4 *) connected->destination; if (p->family == AF_INET) { memset (&to, 0, sizeof (struct sockaddr_in)); to.sin_port = htons (RIP_PORT_DEFAULT); to.sin_addr = p->prefix;#if 0 if (IS_RIP_DEBUG_EVENT) zlog_info ("SEND request to %s", inet_ntoa (to.sin_addr));#endif /* 0 */ rip_request_send (&to, ifp, version); } } }}/* This will be executed when interface goes up. */voidrip_request_interface (struct interface *ifp){ struct rip_interface *ri; /* In default ripd doesn't send RIP_REQUEST to the loopback interface. */ if (if_is_loopback (ifp)) return; /* If interface is down, don't send RIP packet. */ if (! if_is_up (ifp)) return; /* Fetch RIP interface information. */ ri = ifp->info; /* If there is no version configuration in the interface, use rip's version setting. */ if (ri->ri_send == RI_RIP_UNSPEC) { if (rip->version == RIPv1) rip_request_interface_send (ifp, RIPv1); else rip_request_interface_send (ifp, RIPv2); } /* If interface has RIP version configuration use it. */ else { if (ri->ri_send & RIPv1) rip_request_interface_send (ifp, RIPv1); if (ri->ri_send & RIPv2) rip_request_interface_send (ifp, RIPv2); }}/* Send RIP request to the neighbor. */voidrip_request_neighbor (struct in_addr addr){ struct sockaddr_in to; memset (&to, 0, sizeof (struct sockaddr_in)); to.sin_port = htons (RIP_PORT_DEFAULT); to.sin_addr = addr; rip_request_send (&to, NULL, rip->version);}/* Request routes at all interfaces. */voidrip_request_neighbor_all (){ struct route_node *rp; if (! rip) return; if (IS_RIP_DEBUG_EVENT) zlog_info ("request to the all neighbor"); /* Send request to all neighbor. */ for (rp = route_top (rip->neighbor); rp; rp = route_next (rp)) if (rp->info) rip_request_neighbor (rp->p.u.prefix4);}/* Multicast packet receive socket. */intrip_multicast_join (struct interface *ifp, int sock){ listnode cnode; if (if_is_up (ifp) && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_info ("multicast join at %s", ifp->name); for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) { struct prefix_ipv4 *p; struct connected *connected; struct in_addr group; connected = getdata (cnode); p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; group.s_addr = htonl (INADDR_RIP_GROUP); if (ipv4_multicast_join (sock, group, p->prefix, ifp->ifindex) < 0) return -1; else return 0; } } return 0;}/* Leave from multicast group. */voidrip_multicast_leave (struct interface *ifp, int sock){ listnode cnode; if (if_is_up (ifp) && if_is_multicast (ifp)) { if (IS_RIP_DEBUG_EVENT) zlog_info ("multicast leave from %s", ifp->name); for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) { struct prefix_ipv4 *p; struct connected *connected; struct in_addr group; connected = getdata (cnode); p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; group.s_addr = htonl (INADDR_RIP_GROUP); if (ipv4_multicast_leave (sock, group, p->prefix, ifp->ifindex) == 0) return; } }}/* Is there and address on interface that I could use ? */intrip_if_ipv4_address_check (struct interface *ifp){ struct listnode *nn; struct connected *connected; int count = 0; for (nn = listhead (ifp->connected); nn; nextnode (nn)) if ((connected = getdata (nn)) != NULL) { struct prefix *p; p = connected->address; if (p->family == AF_INET) { count++; } } return count;} /* Does this address belongs to me ? */intif_check_address (struct in_addr addr){ listnode node; for (node = listhead (iflist); node; nextnode (node)) { listnode cnode; struct interface *ifp; ifp = getdata (node); for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) { struct connected *connected; struct prefix_ipv4 *p; connected = getdata (cnode); p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; if (IPV4_ADDR_CMP (&p->prefix, &addr) == 0) return 1; } } return 0;}/* is this address from a valid neighbor? (RFC2453 - Sec. 3.9.2) */intif_valid_neighbor (struct in_addr addr){ listnode node; struct connected *connected = NULL; struct prefix_ipv4 *p; for (node = listhead (iflist); node; nextnode (node)) { listnode cnode; struct interface *ifp; ifp = getdata (node); for (cnode = listhead (ifp->connected); cnode; nextnode (cnode)) { struct prefix *pxn = NULL; /* Prefix of the neighbor */ struct prefix *pxc = NULL; /* Prefix of the connected network */ connected = getdata (cnode); if (if_is_pointopoint (ifp)) { p = (struct prefix_ipv4 *) connected->address; if (p && p->family == AF_INET) { if (IPV4_ADDR_SAME (&p->prefix, &addr)) return 1; p = (struct prefix_ipv4 *) connected->destination; if (p && IPV4_ADDR_SAME (&p->prefix, &addr)) return 1; } } else { p = (struct prefix_ipv4 *) connected->address; if (p->family != AF_INET) continue; pxn = prefix_new(); pxn->family = AF_INET; pxn->prefixlen = 32; pxn->u.prefix4 = addr; pxc = prefix_new(); prefix_copy(pxc, (struct prefix *) p); apply_mask(pxc); if (prefix_match (pxc, pxn)) { prefix_free (pxn); prefix_free (pxc); return 1; } prefix_free(pxc); prefix_free(pxn); } } } return 0;}/* Inteface link down message processing. */intrip_interface_down (int command, struct zclient *zclient, zebra_size_t length){ struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist. */ ifp = zebra_interface_state_read(s); if (ifp == NULL) return 0; rip_if_down(ifp); if (IS_RIP_DEBUG_ZEBRA) zlog_info ("interface %s index %d flags %ld metric %d mtu %d is down", ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); return 0;}/* Inteface link up message processing */intrip_interface_up (int command, struct zclient *zclient, zebra_size_t length){ struct interface *ifp; /* zebra_interface_state_read () updates interface structure in iflist. */ ifp = zebra_interface_state_read (zclient->ibuf); if (ifp == NULL) return 0; if (IS_RIP_DEBUG_ZEBRA) zlog_info ("interface %s index %d flags %ld metric %d mtu %d is up", ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); /* Check if this interface is RIP enabled or not.*/ rip_enable_apply (ifp); /* Check for a passive interface */ rip_passive_interface_apply (ifp); /* Apply distribute list to the all interface. */ rip_distribute_update_interface (ifp); return 0;}/* Inteface addition message from zebra. */intrip_interface_add (int command, struct zclient *zclient, zebra_size_t length){ struct interface *ifp; ifp = zebra_interface_add_read (zclient->ibuf); if (IS_RIP_DEBUG_ZEBRA) zlog_info ("interface add %s index %d flags %ld metric %d mtu %d", ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); /* Check if this interface is RIP enabled or not.*/ rip_enable_apply (ifp); /* Apply distribute list to the all interface. */ rip_distribute_update_interface (ifp); /* rip_request_neighbor_all (); */ return 0;}intrip_interface_delete (int command, struct zclient *zclient, zebra_size_t length){ struct interface *ifp; struct stream *s; s = zclient->ibuf; /* zebra_interface_state_read() updates interface structure in iflist */ ifp = zebra_interface_state_read(s); if (ifp == NULL) return 0; if (if_is_up (ifp)) { rip_if_down(ifp); } zlog_info("interface delete %s index %d flags %ld metric %d mtu %d", ifp->name, ifp->ifindex, ifp->flags, ifp->metric, ifp->mtu); /* To support pseudo interface do not free interface structure. */ /* if_delete(ifp); */ return 0;}voidrip_interface_clean (){ listnode node; struct interface *ifp; struct rip_interface *ri; for (node = listhead (iflist); node; nextnode (node)) { ifp = getdata (node); 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; } }}voidrip_interface_reset (){ listnode node; struct interface *ifp; struct rip_interface *ri; for (node = listhead (iflist); node; nextnode (node)) { ifp = getdata (node); ri = ifp->info; ri->enable_network = 0; ri->enable_interface = 0; ri->running = 0; ri->ri_send = RI_RIP_UNSPEC; ri->ri_receive = RI_RIP_UNSPEC; /* ri->auth_type = RIP_NO_AUTH; */ ri->auth_type = RIP_AUTH_SIMPLE_PASSWORD; if (ri->auth_str) { free (ri->auth_str); ri->auth_str = NULL; } if (ri->key_chain) { free (ri->key_chain); ri->key_chain = NULL; } ri->split_horizon = 0; ri->split_horizon_default = 0; ri->list[RIP_FILTER_IN] = NULL; ri->list[RIP_FILTER_OUT] = NULL; ri->prefix[RIP_FILTER_IN] = NULL; ri->prefix[RIP_FILTER_OUT] = NULL; if (ri->t_wakeup) { thread_cancel (ri->t_wakeup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -