spfhello.c
来自「BCAST Implementation for NS2」· C语言 代码 · 共 370 行
C
370 行
/* * 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 implementing the sending and receiving of * Hello packets (Sections 9.5 and and 10.5 of the OSPF * specification). */#include "ospfinc.h"#include "ifcfsm.h"#include "nbrfsm.h"/* Hello timer has fired for a point-to-point, * brodacast interface, or virtual link. Simply multicast * an hello packet out the interface. */void HelloTimer::action(){ if (!ip->suppress_this_hello(ip->if_nlst)) ip->send_hello();}/* Send an hello packet out a given interface. Include * all neighbors in state 2-way or greater in the * body of the hello, then multicast the * resulting packet out the interface. */void SpfIfc::send_hello(bool empty){ NbrIterator iter(this); SpfNbr *np; uns16 size; Pkt pkt; HloPkt *hlopkt; rtid_t *hlo_nbrs; if (if_passive) return; size = sizeof(HloPkt); while((np = iter.get_next())) { if (np->state() >= NBS_INIT) size += sizeof(rtid_t); } if (build_hello(&pkt, size) == 0) return; // Fill in the neighbors recently heard from iter.reset(); hlopkt = (HloPkt *) (pkt.spfpkt); hlo_nbrs = (rtid_t *) (hlopkt + 1); // If shutting down, send empty hellos while(!empty && (np = iter.get_next())) { if (np->state() >= NBS_INIT) { *hlo_nbrs++ = hton32(np->id()); pkt.dptr += sizeof(rtid_t); } } if_send(&pkt, AllSPFRouters);}/* Timer has fired, telling us that it is time to send an * hello to a given neighbor. */void NbrHelloTimer::action(){ if (!np->n_ifp->suppress_this_hello(np)) np->send_hello();}/* Timer has fired, telling us that the neighbor has not * been heard from recently. Declare the neighbor down. */void InactTimer::action(){ if (!np->hellos_suppressed || np->n_state < NBS_LOAD) np->nbr_fsm(NBE_INACTIVE);}/* Send an hello packet directly to a given neighbor. Only * need mention the neighbor in the "routers heard from" * list. However, still may need to fill in the DR and * backup fields, because this could be an NBMA neighbor. */void SpfNbr::send_hello(){ uns16 size; Pkt pkt; HloPkt *hlopkt; rtid_t *hlo_nbrs; size = sizeof(HloPkt); if (n_state >= NBS_INIT) size += sizeof(rtid_t); if (n_ifp->build_hello(&pkt, size) == 0) return; // Fill in if neighbor has been seen hlopkt = (HloPkt *) (pkt.spfpkt); hlo_nbrs = (rtid_t *) (hlopkt + 1); if (n_state >= NBS_INIT) { *hlo_nbrs++ = hton32(n_id); pkt.dptr += sizeof(rtid_t); } n_ifp->nbr_send(&pkt, this);}/* On NBMA interfaces only, routers ineligible to become * designated router send responses to hello received from * eligible routers other than the DR and BDR, in order to * bootstrap the DR election procedure. */void SpfIfc::send_hello_response(SpfNbr *){}void NBMAIfc::send_hello_response(SpfNbr *np){ if (if_drpri && !ospf->host_mode) return; else if (np->is_dr()) return; else if (np->is_bdr()) return; else if (np->n_pri == 0) return; np->send_hello();}/* Build a copy of the hello packet to be sent out a particular * interface. Returns 0 if fails to allocate hello packet. */int SpfIfc::build_hello(Pkt *pkt, uns16 size){ HloPkt *hlopkt; size += sizeof(InPkt); if (ospf->ospf_getpkt(pkt, SPT_HELLO, size) == 0) return(0); // Fill in body of Hello packet hlopkt = (HloPkt *) (pkt->spfpkt); hlopkt->hlo_mask = hton32(if_mask); hlopkt->hlo_hint = hton16(if_hint); hlopkt->hlo_opts = 0; if (!if_area->is_stub()) hlopkt->hlo_opts |= SPO_EXT; if (ospf->mospf_enabled()) hlopkt->hlo_opts |= SPO_MC; if (!elects_dr() && (if_demand || (if_nlst && if_nlst->rq_suppression))) hlopkt->hlo_opts |= SPO_DC; hlopkt->hlo_pri = ospf->host_mode ? 0: if_drpri; hlopkt->hlo_dint = hton32(if_dint); hlopkt->hlo_dr = ((type() != IFT_PP) ? hton32(if_dr) : hton32(if_mtu)); hlopkt->hlo_bdr = hton32(if_bdr); // Advance data pointer pkt->dptr = (byte *) (hlopkt + 1); return(size);}/* Received an hello on a given interface. Perform * processing according to Section 10.5 of the OSPF * specification. */void SpfIfc::recv_hello(Pkt *pdesc){ InPkt *inpkt; HloPkt *hlopkt; rtid_t old_id; rtid_t nbr_id; InAddr nbr_addr; bool was_declaring_dr; bool was_declaring_bdr; byte old_pri; rtid_t *idp; bool nbr_change; bool backup_seen; bool first_hello; SpfNbr *np; if (if_state == IFS_DOWN || if_passive) return; inpkt = pdesc->iphdr; nbr_addr = ntoh32(inpkt->i_src); hlopkt = (HloPkt *) pdesc->spfpkt; nbr_id = ntoh32(hlopkt->hdr.srcid); // Verify network parameters if (ntoh16(hlopkt->hlo_hint) != if_hint) return; if (ntoh32(hlopkt->hlo_dint) != if_dint) return; if (is_multi_access() && ntoh32(hlopkt->hlo_mask) != if_mask) return; if (if_area->a_stub != ((hlopkt->hlo_opts & SPO_EXT) == 0)) return; if (ospf->PPAdjLimit != 0 && type() == IFT_PP && ntoh32(hlopkt->hlo_dr) > if_mtu) { if (ospf->spflog(LOG_BADMTU, 5)) { ospf->log(this); ospf->log("remote mtu "); ospf->log(ntoh32(hlopkt->hlo_dr)); } return; } // Find the neighbor structure // If one is not found, it is created if (!(np = find_nbr(nbr_addr, nbr_id))) np = new SpfNbr(this, nbr_id, nbr_addr); // Set ID or address, depending on interface type old_id = np->n_id; set_id_or_addr(np, nbr_id, nbr_addr); // Save and then set neighbor parameters was_declaring_dr = np->declared_dr(); was_declaring_bdr = np->declared_bdr(); old_pri = np->n_pri; np->n_dr = ntoh32(hlopkt->hlo_dr); np->n_bdr = ntoh32(hlopkt->hlo_bdr); np->n_pri = hlopkt->hlo_pri; // Run through state machine, if necessary // Record hello receipt first_hello = (np->n_state == NBS_DOWN); np->nbr_fsm(NBE_HELLO); // Check for bidirectionality for (idp = (rtid_t *) (hlopkt+1); ; idp++) { // If not bidirectional, processing stops if ((byte *) idp >= pdesc->end) { np->nbr_fsm(NBE_1WAY); if (first_hello) { np->nbr_fsm(NBE_EVAL); if (!np->ifc()->is_multi_access() || np->ifc()->type() == IFT_P2MP) np->send_hello(); } else send_hello_response(np); return; } else if (ntoh32(*idp) == ospf->my_id()) break; } np->nbr_fsm(NBE_2WAY); np->negotiate_demand(hlopkt->hlo_opts); // Look for changes that can affect the selection // of the attached network's Designated Router nbr_change = false; backup_seen = false; if (old_pri != np->n_pri) { np->nbr_fsm(NBE_EVAL); nbr_change = true; } else if (old_id != np->n_id) nbr_change = true; else if (was_declaring_dr != np->declared_dr()) nbr_change = true; else if (was_declaring_bdr != np->declared_bdr()) nbr_change = true; if (if_state == IFS_WAIT) { if (np->declared_dr() && ntoh32(hlopkt->hlo_bdr) == 0) backup_seen = true; if (np->declared_bdr()) backup_seen = true; if (ospf->in_hitless_restart() && ntoh32(hlopkt->hlo_dr) == if_addr) { backup_seen = true; // Declare self to be DR again if_dr = if_addr; } } // Possibly respond to hello send_hello_response(np); // Execute any scheduled FSM events if (backup_seen) run_fsm(IFE_BSEEN); else if (nbr_change) run_fsm(IFE_NCHG); // Possibly originate a new network-LSA if (old_id != np->n_id && np->ifc()->state() == IFS_DR) np->ifc()->nl_orig(false);}/* Logic determining whether you should suppress a particular * hello being sent out a demand interface. */bool SpfIfc::suppress_this_hello(SpfNbr *np){ if (np && np->hellos_suppressed && np->n_state == NBS_FULL) return(true); if (if_demand && !elects_dr() && !np) { if_demand_helapse += if_hint; if (if_demand_helapse < if_pint) return(false); else if (if_demand_helapse >= 2*if_pint) { if_demand_helapse = if_pint; return(false); } else return(true); } return(false);}/* Routine used to negotiate hello suppression with a neighbor. * Called when either an Hello packet or database description * packet is received. */void SpfNbr::negotiate_demand(byte opts){ if (n_ifp->elects_dr()) { hellos_suppressed = false; return; } else if ((rq_suppression = ((opts & SPO_DC) != 0))) hellos_suppressed = true; else if (n_state >= NBS_2WAY) { hellos_suppressed = false; n_acttim.start(n_ifp->if_dint*Timer::SECOND); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?