📄 spfifc.c
字号:
/* * OSPFD routing daemon * Copyright (C) 1998 by John T. Moy * * This program 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 * of the License, or (at your option) any later version. * * This program 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; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* Routines dealing with OSPF interfaces. * Does not include the Interface state machine, which is * contained in file ifcfsm.C. */#include "ospfinc.h"#include "ifcfsm.h"#include "nbrfsm.h"#include "system.h"#include "contrib/global.h"#include "openssl/md5.h"/* Add, modify, or delete an OSPF interface. */void OSPF::cfgIfc(CfgIfc *m, int status){ SpfIfc *ip; bool restart=false; bool nbr_change=false; bool new_lsa=false; bool new_net_lsa=false; SpfArea *new_ap; printf("----\nOSPF::cfgIfc\n"); ip = find_ifc(m->address, m->phyint); // If delete, free to heap if (status == DELETE_ITEM) { if (ip) delete ip; return; } // Add or modify an interface // Type of interface (NBMA, etc.) if (ip && ip->type() != m->IfType) { delete ip; ip = 0; } // Allocate new interface, if necessary if (!ip) { switch (m->IfType) { case IFT_BROADCAST: ip = new BroadcastIfc(m->address, m->phyint); break; case IFT_PP: ip = new PPIfc(m->address, m->phyint); break; case IFT_NBMA: ip = new NBMAIfc(m->address, m->phyint); break; case IFT_P2MP: ip = new P2mPIfc(m->address, m->phyint); break; case IFT_VL: default: return; } ip->if_mask = m->mask; ip->if_net = ip->if_addr & ip->if_mask; // Queue into global interface list ip->next = ospf->ifcs; ospf->ifcs = ip; if (spflog(CFG_ADD_IFC, 5)) log(ip); } // Allocate new area, if necessary if (!(new_ap = FindArea(m->area_id))) new_ap = new SpfArea(m->area_id); // Change timers, if need be if (m->hello_int != ip->if_hint || ip->if_pint != m->poll_int) { ip->if_hint = m->hello_int; ip->if_pint = m->poll_int; ip->restart_hellos(); } // Set new parameters ip->if_mtu = m->mtu; // Interface packet size ip->if_xdelay = m->xmt_dly; // Transit delay (seconds) ip->if_rxmt = m->rxmt_int; // Retransmission interval (seconds) ip->if_dint = m->dead_int; // Router dead interval (seconds) ip->if_autype = m->auth_type; // Authentication type memcpy(ip->if_passwd, m->auth_key, 8);// Auth key // If using MD5, reduce mtu to compensate for appended digest if (ip->if_autype == AUT_CRYPT) ip->if_mtu -= 16; // Interface address mask if (ip->if_mask != m->mask) { ip->if_mask = m->mask; ip->if_net = ip->if_addr & ip->if_mask; new_lsa = true; new_net_lsa = true; } // MIB-II IfIndex if (ip->if_IfIndex != m->IfIndex) { ip->if_IfIndex = m->IfIndex; new_lsa = true; } // Designated router priority if (ip->if_drpri != m->dr_pri) { ip->if_drpri = m->dr_pri; ip->ifa_allnbrs_event(NBE_EVAL); nbr_change = true; } // Interface cost // First verify cost if (m->if_cost == 0) m->if_cost = 1; if (ip->if_cost != m->if_cost) { ip->if_cost = m->if_cost; new_lsa = true; } // Multicast forwarding enabled? if (ip->if_mcfwd != m->mc_fwd) { ip->if_mcfwd = m->mc_fwd; mospf_clear_cache(); new_net_lsa = true; } // On Demand interface? if (ip->if_demand != (m->demand != 0)) { ip->if_demand = (m->demand != 0); restart = true; } // Passive interface? if (ip->if_passive != m->passive) { ip->if_passive = m->passive; restart = true; } // IGMP enabled? if (ip->igmp_enabled != (m->igmp != 0)) { ip->igmp_enabled = (m->igmp != 0); restart = true; } // On Area change, must restart interface if (new_ap != ip->if_area) { if (ip->if_area) { ip->run_fsm(IFE_DOWN); ip->if_area->RemoveIfc(ip); } // Add to new area ip->if_area = new_ap; ip->anext = new_ap->a_ifcs; new_ap->a_ifcs = ip; if (sys->phy_operational(ip->if_phyint)) ip->run_fsm(IFE_UP); } /* Otherwise, * On certain changes, must restart interface: * Change in demand status */ else if (restart) ip->restart(); /* Otherwise * Change in DR priority causes DR election to be * redone. Change in cost or IFIndex causes router-LSA * to be regenerated. */ else { if (nbr_change) ip->run_fsm(IFE_NCHG); if (new_lsa) new_ap->rl_orig(); if (new_net_lsa) ip->nl_orig(false); } ip->updated = true; new_ap->updated = true;}/* Copy Interface info to CfgIfc structure */static void ifc_to_cfg(const SpfIfc& i, struct CfgIfc& msg){ msg.address = i.if_addr; msg.phyint = i.if_phyint; msg.mask = i.mask(); msg.mtu = i.mtu(); msg.IfIndex = i.if_index(); msg.area_id = i.area()->id(); msg.IfType = i.type(); msg.dr_pri = i.drpri(); msg.xmt_dly = i.xmt_delay(); msg.rxmt_int = i.rxmt_interval(); msg.if_cost = i.cost(); msg.hello_int = i.hello_int(); msg.dead_int = i.dead_int(); msg.poll_int = i.poll_int(); msg.auth_type = i.autype(); memcpy(msg.auth_key, i.passwd(), sizeof(msg.auth_key)); msg.mc_fwd = i.mcfwd(); msg.demand = i.demand(); msg.passive = i.passive(); msg.igmp = i.igmp();}/* Query Interface */bool OSPF::qryIfc(struct CfgIfc& msg, InAddr address, int phyint) const{ const SpfIfc *ip = find_ifc(address, phyint); if (ip == 0) return false; ifc_to_cfg(*ip, msg); return true;}/* Get all interfaces */void OSPF::getIfcs(std::list<CfgIfc>& l) const{ IfcIterator iter(this); SpfIfc* ip; while((ip = iter.get_next())) { CfgIfc msg; ifc_to_cfg(*ip, msg); l.push_back(msg); }}/* Constructor for an OSPF interface. Set the identifiers * for an interface (address and physical interface), * set the area to NUL, and then initialize all of the * dynamic (non-config) values. */SpfIfc::SpfIfc(InAddr a, int phy): if_wtim(this), if_htim(this), if_actim(this){ if_addr = a; if_phyint = phy; if_area = 0; if_keys = 0; if_demand = false; if_passive = 0; igmp_enabled = false; db_xsum = 0; anext = 0; if_dr = 0; if_bdr = 0; if_dr_p = 0; if_state = IFS_DOWN; if_nlst = 0; if_nnbrs = 0; if_nfull = 0; if_helping = 0; in_recv_update = false; area_flood = false; global_flood = false; if_demand_helapse = 0; // Virtual link parameters if_tap = 0; // Transit area if_nbrid = 0; // Configured neighbor ID if_rmtaddr = 0; // IP address of other end}/* Destructor for an interface. Declare the interface down, * remove from global and area lists, the free associated * keys and neighbors. */SpfIfc::~SpfIfc(){ SpfIfc **ipp; SpfIfc *ip; SpfNbr *np; NbrIterator nbr_iter(this); CryptK *key; KeyIterator key_iter(this); if (ospf->spflog(CFG_DEL_IFC, 5)) ospf->log(this); // Remove cryptographic keys while ((key = key_iter.get_next())) delete key; // Declare interface down run_fsm(IFE_DOWN); // Remove neighbors while ((np = nbr_iter.get_next())) delete np; // Free from global list for (ipp = &ospf->ifcs; (ip = *ipp) != 0; ipp = &ip->next) { if (ip == this) { *ipp = next; break; } } // Free from area list if_area->RemoveIfc(this); // Close physical interface if (if_phyint != -1) ospf->phy_detach(if_phyint, if_addr);}/* Return the physical interface type. */int SpfIfc::type() const{ return(if_type);}/* Return a printable string for each interface type */const char *iftypes(int iftype){ switch(iftype) { case IFT_BROADCAST: return("BCast"); case IFT_PP: return("P-P"); case IFT_NBMA: return("NBMA"); case IFT_P2MP: return("P2MP"); case IFT_VL: return("VL"); default: break; } return("Unknown");}// Is the interface a virtual link?bool SpfIfc::is_virtual(){ return(if_type == IFT_VL);}// Can the interface support more than one neighbor?bool SpfIfc::is_multi_access(){ return(if_type != IFT_PP && if_type != IFT_VL);}// Return the transit area (0 if not a virtual link)SpfArea *SpfIfc::transit_area(){ return(if_tap);}// Return the endpoint of a virtual linkrtid_t *SpfIfc::vl_endpt(){ return(&if_nbrid);}/* Base functions that may be overriden for specific interface * types. */void SpfIfc::start_hellos(){ send_hello(); if_htim.start(if_hint*Timer::SECOND);}void SpfIfc::restart_hellos(){ if_htim.restart();}void SpfIfc::stop_hellos(){ if_htim.stop();}bool SpfIfc::elects_dr(){ return(false);}/* Trivial virtual functions for virtual links. *//* Trivial functions for interfaces which elect a Designated * Router. */bool DRIfc::elects_dr(){ return(true);}/* Trivial virtual functions for Broadcast interfaces. *//* Trivial virtual functions for NBMA interfaces. */void NBMAIfc::if_send(Pkt *pdesc, InAddr addr){ nonbroadcast_send(pdesc, addr);}void NBMAIfc::start_hellos(){ if (if_drpri) ifa_nbr_start(1);}void NBMAIfc::restart_hellos(){ nonbroadcast_restart_hellos();}void NBMAIfc::stop_hellos(){ nonbroadcast_stop_hellos();}/* Trivial virtual functions for Point-to-MultiPoint interfaces. */void P2mPIfc::if_send(Pkt *pdesc, InAddr addr){ nonbroadcast_send(pdesc, addr);}void P2mPIfc::start_hellos(){ ifa_nbr_start(0);}void P2mPIfc::restart_hellos(){ nonbroadcast_restart_hellos();}void P2mPIfc::stop_hellos(){ nonbroadcast_stop_hellos();}/* Functions to manipulate loopback interfaces. */LoopIfc::LoopIfc(SpfArea *a, InAddr net, InMask mask) : SpfIfc(net, -1){ if_type = IFT_LOOPBK; if_area = a; if_mask = mask; if_net = if_addr & if_mask; if_state = IFS_LOOP;}LoopIfc::~LoopIfc(){ if_state = IFS_DOWN;}void LoopIfc::ifa_start(){}RtrLink *LoopIfc::rl_insert(RTRhdr *, RtrLink *){ return(0);}void LoopIfc::add_adj_to_cand(class PriQ &){}/* If an interface has not been mentioned in a reconfig, just * remove it. */void SpfIfc::clear_config(){ delete this;}/* Restart an interface. Generate the interface down event, * and if the interface is physically up, generate the * up event as well. */void SpfIfc::restart(){ // Declare interface down run_fsm(IFE_DOWN); if (sys->phy_operational(if_phyint)) run_fsm(IFE_UP);}/* Find an interface data structure given its IP address and, * optionally, its physical interface. * Only used for real interfaces, and not virtual links. */SpfIfc *OSPF::find_ifc(uns32 xaddr, int phy) const{ IfcIterator iter(this); SpfIfc *ip; while ((ip = iter.get_next())) { if (ip->is_virtual()) continue; if (phy != -1 && phy != ip->if_phyint) continue; if (ip->if_addr == xaddr) break; } return(ip);}/* OSPF packet has been received on a physical interface. * Associate the packet with the correct OSPF interface, * as described in Section 8.2 of the OSPF specification. */SpfIfc *OSPF::find_ifc(Pkt *pdesc){ SpfPkt *spfpkt; IfcIterator iter(this); SpfIfc *ip; InAddr ipsrc; InAddr ipdst; VLIfc *vif; RTRrte *endpt; SpfArea *tap; ipsrc = ntoh32(pdesc->iphdr->i_src); ipdst = ntoh32(pdesc->iphdr->i_dest); spfpkt = pdesc->spfpkt; tap = 0; while ((ip = iter.get_next())) { if (ip->is_virtual()) continue; // Save interface if dest matches interface // address, for later virtual link processing if (ipdst == ip->if_addr) tap = ip->if_area; if (pdesc->phyint != -1 && ip->if_phyint != pdesc->phyint) continue; else if (ip->if_area->a_id != ntoh32(spfpkt->p_aid)) continue; else if ((ip->is_multi_access() || pdesc->phyint == -1) && (ipsrc & ip->mask()) != ip->net()) continue; else if (ipdst == AllDRouters || ipdst == AllSPFRouters) return(ip); else if (ipdst == ip->if_addr) return(ip); } // Real interface not found if (tap == 0) { AreaIterator aiter(this); SpfArea *a; while ((a = aiter.get_next())) { HostAddr *loopbk; if ((loopbk = (HostAddr *) a->hosts.find(ipdst,0xffffffff)) && loopbk->r_cost == 0) { tap = a; break; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -