📄 ospf.c
字号:
ap = new SpfArea(m->area_id); if (!(hp = (HostAddr *) ap->hosts.find(m->net, m->mask))) hp = new HostAddr(ap, m->net, m->mask); if (status == DELETE_ITEM) { ap->hosts.remove(hp); delete hp->ip; delete hp; } else { hp->r_cost = m->cost; hp->updated = true; hp->ip->updated = true; ap->updated = true; } // Reoriginate router-LSA for all areas // Can't do just one, because host address may be advertised // in a different area if configured area has no active interfaces rl_orig(); calc_my_addr();}/* Transfer host parameters to cfg structure */static void host_to_cfg(const HostAddr& h, CfgHost& msg){ msg.net = h.r_rte->net(); msg.mask = h.r_rte->mask(); msg.area_id = h.r_area; msg.cost = h.r_cost;}/* Query Host information */bool OSPF::qryHost(struct CfgHost& msg, aid_t area_id, InAddr net, InMask mask) const{ const SpfArea* ap = FindArea(area_id); if (ap == 0) return false; HostAddr* hp = (HostAddr *) ap->hosts.find(net, mask); if (hp == 0) return false; host_to_cfg(*hp, msg); return true;}/* Get all host information associated with area */void OSPF::getHosts(std::list<CfgHost>& l, aid_t area_id) const{ SpfArea* ap = FindArea(area_id); if (ap == 0) return; AVLsearch hiter(&ap->hosts); HostAddr* hp; while ((hp = (HostAddr*)hiter.next())) { CfgHost msg; host_to_cfg(*hp, msg); l.push_back(msg); }}/* Host not listed in a reconfig. Delete it. */void HostAddr::clear_config(){ ap->hosts.remove(this); ospf->rl_orig(); delete this; ospf->calc_my_addr();}/* Process an incoming monitor request. */void OSPF::monitor(MonMsg *msg, byte type, int, int conn_id){ switch(type) { case MonReq_Stat: // Global statistics global_stats(msg, conn_id); break; case MonReq_Area: // Area statistics area_stats(msg, conn_id); break; case MonReq_Ifc: // Interface statistics interface_stats(msg, conn_id); break; case MonReq_VL: // Virtual link statistics vl_stats(msg, conn_id); break; case MonReq_Nbr: // Neighbor statistics neighbor_stats(msg, conn_id); break; case MonReq_VLNbr: // Virtual neighbor statistics vlnbr_stats(msg, conn_id); break; case MonReq_LSA: // Dump LSA contents lsa_stats(msg, conn_id); break; case MonReq_Rte: // Dump routing table entry rte_stats(msg, conn_id); break; case MonReq_OpqReg: register_for_opqs(conn_id); break; case MonReq_OpqNext: opq_stats(msg, conn_id); break; case MonReq_LLLSA: // Dump Link-local LSA contents lllsa_stats(msg, conn_id); break; default: break; }}/* We have received an update of the elapsed real time * since the program was started. Go through the timer * queue and execute those timers which are now due to * fire. */void OSPF::tick(){ Timer *tqelt; uns32 sec; uns32 msec; sec = sys_etime.sec; msec = sys_etime.msec; while ((tqelt = (Timer *) timerq.priq_gethead())) { if (tqelt->cost0 > sec) break; if (tqelt->cost0 == sec && tqelt->cost1 > msec) break; // Fire timer tqelt = (Timer *) timerq.priq_rmhead(); tqelt->fire(); }}/* Return the number of milliseconds until the next wakeup. * Returns -1 if there is no pending wakeup. */int OSPF::timeout(){ Timer *tqelt; SPFtime wakeup_time; if (!(tqelt = (Timer *) timerq.priq_gethead())) return(-1); wakeup_time.sec = tqelt->cost0; wakeup_time.msec = tqelt->cost1; if (time_less(wakeup_time, sys_etime)) return(0); else return(time_diff(wakeup_time, sys_etime));}/* An indication that the physical or data link layer * has failed. Execute the down event on all associated * OSPF interfaces. * Redo the external routing calculation in case the * physical interface contains non-OSPF subnets which * are referenced in imported external routes. * Also, turn off IGMP processing. */void OSPF::phy_down(int phyint){ IfcIterator iter(this); SpfIfc *ip; PhyInt *phyp; ase_sched = true; while ((ip = iter.get_next())) { if (ip->if_phyint == phyint) ip->run_fsm(IFE_DOWN); } if ((phyp = (PhyInt *)phyints.find((uns32) phyint, 0))) { phyp->operational = false; phyp->verify_igmp_capabilities(); } // Delete phyint from routing table entries' next hops INrte *rte; INiterator rtiter(inrttbl); while ((rte = rtiter.nextrte())) { MPath *old; if (!rte->valid()) continue; if (!rte->r_mpath) continue; old = rte->r_mpath; rte->r_mpath = old->prune_phyint(phyint); if (!rte->r_mpath) rte->declare_unreachable(); if (rte->r_mpath != old) { rte->changed = true; rte->sys_install(); } }}/* An indication that the physical and data link layers * are operational. Execute the up event on all associated * OSPF interfaces. * Redo the external routing calculation in case the * physical interface contains non-OSPF subnets which * are referenced in imported external routes. * * In additional, force a routing calculation because a * previous phy_down() deleted routing table entries, and * if LSAs have not changed (say because of a quick link * flap) we need to put them back. */void OSPF::phy_up(int phyint){ IfcIterator iter(this); SpfIfc *ip; ase_sched = true; while ((ip = iter.get_next())) { if (ip->if_phyint == phyint) { ip->run_fsm(IFE_UP); full_sched = true; ase_sched = true; } }}/* An indication that a group member has appeared * on a directly attached interface. If the phyint == -1, * the group member is a MOSPF internal group. * This routine is usually called by IGMP. */void OSPF::join_indication(InAddr group, int phyint){ GroupMembership *gentry; PhyInt *phyp; gentry = new GroupMembership(group, phyint); local_membership.add(gentry); phyp = (PhyInt *) phyints.find((uns32) phyint, 0); if (phyp && phyp->mospf_ifp) phyp->mospf_ifp->area()->grp_orig(group, 0); else if (phyint == -1) grp_orig(group, 0); if (spflog(LOG_NEWGRP, 4)) { log(&group); if (phyint != -1) { log(" on "); log(sys->phyname(phyint)); } }}/* Leave group processing, similar to the above * join, just in reverse. */void OSPF::leave_indication(InAddr group, int phyint){ GroupMembership *gentry; PhyInt *phyp; gentry = (GroupMembership *) local_membership.find(group, phyint); if (!gentry) return; local_membership.remove(gentry); phyp = (PhyInt *)phyints.find(phyint, 0); if (phyp && phyp->mospf_ifp) phyp->mospf_ifp->area()->grp_orig(group, 0); else if (phyint == -1) grp_orig(group, 0); if (spflog(LOG_GRPEXP, 4)) { log(&group); if (phyint != -1) { log(" on "); log(sys->phyname(phyint)); } } delete gentry;}/* Kernel has indicated that it has deleted one of the * routes that we have added. This is probably due to * a network interface going down. Store the information * so that if we don't soon delete the entry also, we * will re-add it to the kernel in OSPF::krt_sync(). */void OSPF::krt_delete_notification(InAddr net, InMask mask){ INrte *rte; // Ignore delete notifications while in hitless restart if (in_hitless_restart()) return; // Normally store and reinstall into kernel after short delay if ((rte = inrttbl->find(net, mask)) && rte->valid()) { printf("route was valid - add it to deletes\n"); KrtSync *item; item = new KrtSync(net, mask); krtdeletes.add(item); } printf("find returned: %p\n", rte); }/* Kernel has indicated that we have previously installed * a route to this destination. If we don't have the destination * currently in our routing table, assume that it is a remnant * from a previous execution run, and delete the route. */void OSPF::remnant_notification(InAddr net, InMask mask){ INrte *rte; // If we're in hitless restart, just store remnant // for later processing if (in_hitless_restart()) { AVLitem *rem; if (!(rem = remnants.find(net, mask))) { rem = new AVLitem(net, mask); remnants.add(rem); } return; } // Normally delete all remnants from the kernel immediately if (!(rte = inrttbl->find(net, mask)) || !rte->valid()) { if (spflog(LOG_REMNANT, 5)) { log(&net, &mask); } sys->rtdel(net, mask, 0); }}/* Perform a lookup in OSPF's copy of the IP routing * table. Used on those platforms that do not maintain * a "kernel" copy of the routing table. */MPath *OSPF::ip_lookup(InAddr dest){ INrte *rte; if ((rte = inrttbl->best_match(dest))) return(rte->r_mpath); return(0);}/* Find the source address that would be used to send * packets to the given destination. */InAddr OSPF::ip_source(InAddr dest){ INrte *rte; SpfIfc *ip = 0; if ((rte = inrttbl->best_match(dest)) && (ip = rte->ifc()) && (!ip->unnumbered())) return(ip->if_addr); return(my_addr());}/* Return the IP address associated with a given physical * interface. */InAddr OSPF::if_addr(int phyint){ PhyInt *phyp; phyp = (PhyInt *)phyints.find(phyint, 0); return(phyp ? phyp->my_addr : 0);}/* The graceful shutdown procedure. Executed in phases. * First flush all locally-originated LSAs, except network-LSAs. * Then flush the network-LSAs. Finally, remove OSPF entries * from the system routing table, send out empty hellos, and * exit. * * A maximum time limit is placed on the entire procedure. */void OSPF::shutdown(int seconds){ AreaIterator aiter(this); SpfArea *a; IfcIterator iiter(this); SpfIfc *ip; if (shutdown_phase) return; shutdown_phase++; // Set timer countdown = seconds; // Flush self-originated LSAs flush_self_orig(FindLSdb(0, 0, LST_ASL)); flush_self_orig(FindLSdb(0, 0, LST_AS_OPQ)); while ((a = aiter.get_next())) { flush_self_orig(FindLSdb(0, a, LST_RTR)); flush_self_orig(FindLSdb(0, a, LST_SUMM)); flush_self_orig(FindLSdb(0, a, LST_ASBR)); flush_self_orig(FindLSdb(0, a, LST_GM)); flush_self_orig(FindLSdb(0, a, LST_AREA_OPQ)); } while ((ip = iiter.get_next())) flush_self_orig(FindLSdb(ip, 0, LST_LINK_OPQ));}/* Continue the shutdown process. */void OSPF::shutdown_continue(){ AreaIterator aiter(this); IfcIterator iiter(this); SpfArea *a; SpfIfc *ip; INrte *rte; INiterator iter(inrttbl); switch(shutdown_phase++) { case 1: // Reset timer countdown = 1; // Flush network-LSAs while ((a = aiter.get_next())) flush_self_orig(FindLSdb(0, a, LST_NET)); break; case 2: // Send empty Hellos while((ip = iiter.get_next())) ip->send_hello(true); // Withdraw routing entries while ((rte = iter.nextrte())) { switch(rte->type()) { case RT_SPF: case RT_SPFIA: case RT_EXTT1: case RT_EXTT2: case RT_STATIC: sys->rtdel(rte->net(), rte->mask(), rte->last_mpath); break; default: break; } } // Exit program sys->halt(0, "Shutdown complete"); break; default: sys->halt(0, "Shutdown complete"); break; }}/* Entry point to initiate a hitless restart. * After preparation is complete, halt will be called. */void OSPF::hitless_restart(int seconds, byte reason){ if (hitless_prep_phase > 0) return; grace_period = seconds; restart_reason = reason; hitless_prep_phase = 1; phase_duration = 0; prepare_hitless_restart();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -