📄 ospfd_sim.c
字号:
ospf->cfgOspf((CfgGen *) msg); break; case CfgType_Area: ospf->cfgArea((CfgArea *)msg, status); break; case CfgType_Range: ospf->cfgRnge((CfgRnge *)msg, status); break; case CfgType_Host: ospf->cfgHost((CfgHost *)msg, status); break; case CfgType_Ifc: ifcmsg = (CfgIfc *)msg; if (!(phyp = (PhyintMap *)port_map.find(ifcmsg->phyint, 0))) { phyp = new PhyintMap(ifcmsg->phyint); port_map.add(phyp); } phyp->addr = ifcmsg->address; phyp->mask = ifcmsg->mask; if (!my_addr) my_addr = ifcmsg->address; ospf->cfgIfc(ifcmsg, status); break; case CfgType_VL: ospf->cfgVL((CfgVL *)msg, status); break; case CfgType_Nbr: ospf->cfgNbr((CfgNbr *)msg, status); break; case CfgType_Route: ospf->cfgExRt((CfgExRt *)msg, status); break; case CfgType_Key: ospf->cfgAuKey((CfgAuKey *)msg, status); break; default: break; }}/* Constructor for the physical interface. */PhyintMap::PhyintMap(int phyint) : AVLitem(phyint,0){ working = true; promiscuous = false; sprintf(name, "N%d", phyint);}/* Send a tick response, listing the current state * of the link-state database. */void SimSys::send_tick_response(){ DBStats *statp; SpfArea *ap; SpfArea *low; int mlen; low = 0; statp = new DBStats; mlen = sizeof(DBStats); if (ospf) { AreaIterator iter(ospf); statp->n_exlsas = ospf->n_extLSAs(); statp->ex_dbxsum = ospf->xsum_extLSAs(); while ((ap = iter.get_next())) { if (ap->n_active_if == 0) continue; if (!low || low->id() > ap->id()) low = ap; } } else { statp->n_exlsas = 0; statp->ex_dbxsum = 0; } if (low) { statp->area_id = low->id(); statp->n_lsas = low->n_LSAs(); statp->dbxsum = low->database_xsum(); } else { statp->area_id = 0; statp->n_lsas = 0; statp->dbxsum = 0; } ctl_pkt.queue_xpkt(statp, SIM_TICK_RESPONSE, 0, mlen); delete statp;}/* Queue a received packet, until it is time to process * it. */void SimSys::queue_rcv(struct SimPktHdr *pkt, int plen){ SimPktQ *qptr; qptr = new SimPktQ; qptr->next = 0; qptr->ip_data = (SimPktHdr *) new byte[plen]; memcpy(qptr->ip_data, pkt, plen); if (rcv_head == 0) rcv_head = rcv_tail = qptr; else { rcv_tail->next = qptr; rcv_tail = qptr; }}/* After receiving a tick, process the queue of packets * that were delayed until this time interval. */void SimSys::process_rcvqueue(){ SimPktQ *qptr; SimPktQ *next; SimPktQ *prev; SPFtime limit; prev = 0; time_add(sys_etime, 1000/TICKS_PER_SECOND, &limit); for (qptr = rcv_head; qptr; qptr = next) { SimPktHdr *pkthdr; next = qptr->next; pkthdr = qptr->ip_data; // Time to process? if (time_less(pkthdr->ts, limit)) { // Remove from receive queue if (rcv_head == qptr) rcv_head = next; else prev->next = next; if (rcv_tail == qptr) rcv_tail = prev; delete qptr; rxpkt(pkthdr); delete [] ((byte *) pkthdr); } else prev = qptr; }}/* Forward a multicast datagram. * Have MOSPF calculate the forwarding cache entry. * If the incoming interface is not -1, and not in the * cache entry, just discard. Otherwise, forward out all * of the specified output interfaces. */void SimSys::mc_fwd(int in_phyint, InPkt *pkt){ size_t len; SimPktHdr *data; MCache *ce; if (!ospf) return; len = ntoh16(pkt->i_len); data = (SimPktHdr *) new byte[len+sizeof(SimPktHdr)]; data->ts = xmt_stamp; memcpy(data+1, pkt, len); // Calculate cache entry if ((ce = ospf->mclookup(ntoh32(pkt->i_src), ntoh32(pkt->i_dest)))) { // Verify incoming interface if (ce->valid_incoming(in_phyint)) { int i; /* If locally originated, send out upstream interface. * will then be forwarded correctly when received * by us and *other* routers. */ if (in_phyint == -1 && ce->n_upstream != 0 && ce->up_phys[0] != -1) { data->phyint = hton32(ce->up_phys[0]); send_multicast(data, len, true); } else { // Send to all outgoing interfaces, and neighbors for (i = 0; i < ce->n_downstream; i++) { if (pkt->i_ttl <= ce->down_str[i].ttl) continue; if (ce->down_str[i].nbr_addr == 0) { data->phyint = hton32(ce->down_str[i].phyint); send_multicast(data, len, true); } else sendpkt(pkt, ce->down_str[i].phyint, ce->down_str[i].nbr_addr); } } } } delete [] ((byte *)data);}/* Send a multicast packet. Find all the routers attached * to the segment and broadcast to them individually. * Router does not send the multicast to itself. This routine * is also used to deliver packets over unnumbered point-to-point * links. */void SimSys::send_multicast(SimPktHdr *data, size_t len, bool loopback){ int phyint; AddressMap *mapp; AVLsearch iter(&address_map); InPkt *pkt; InAddr dest; pkt = (InPkt *) (data+1); dest = ntoh32(pkt->i_dest); phyint = ntoh32(data->phyint); iter.seek(phyint, 0); while ((mapp = (AddressMap *) iter.next())) { sockaddr_in to; if (mapp->index1() != (uns32) phyint) break; // Loopback ping packets if (mapp->home == my_id) { if (loopback) rxpkt(data); continue; } to.sin_family = AF_INET; to.sin_addr.s_addr = inet_addr(LOOPADDR); to.sin_port = hton16(mapp->port); if (sendto(uni_fd, data, len+sizeof(SimPktHdr), 0, (sockaddr *) &to, sizeof(to)) == -1) perror("sendto"); //sys_spflog(ERR_SYS, "sendto failed"); }}/* Return the port that is listening for unicast * packets to te simulated router. */uns16 SimSys::get_port_addr(InAddr addr, InAddr &owner){ AddressMap *mapp; AVLsearch iter(&address_map); iter.seek(addr, 0); if (!(mapp = (AddressMap *) iter.next()) || (mapp->index1() != addr)) return(0); owner = mapp->home; return (mapp->port);}/* Contructor for an entry in the address map, that maps * unicast addresses to group addresses to simulate * data-link address translation. */AddressMap::AddressMap(InAddr addr, InAddr home) : AVLitem(addr, home){}/* Construct a ping session. */PingSession::PingSession(uns16 id, InAddr s, InAddr d, byte t) : AVLitem(id, 0){ src = s; dest = d; ttl = t; seqno = 0;}/* When the ping session timer fires, we send another ICMP * echo. */void PingSession::action(){ simsys->sendicmp(ICMP_TYPE_ECHO, 0, src, dest, 0, index1(), seqno++, ttl);}/* Construct a traceroute session. */TRSession::TRSession(uns16 id, InAddr d, byte t) : AVLitem(id, 0){ dest = d; maxttl = t; seqno = 0; ttl = 0; iteration = MAXITER; terminating = false;}/* Probe has timed out. Send a timeout message to the controller, * and then just act as if a response was received. */void TRSession::action(){ simsys->ctl_pkt.queue_xpkt(0, SIM_TRACEROUTE_TMO, index1(), 0); response_received(255);}/* Traceroute response received. If it is any form of destination * unreachable, we are going to end the probes after the * current iteration. Otherwise, send a new ping and start * the timer again. * "type" is the ICMP packet type of any ICMP error received. * type == 255 indicates a timeout. */void TRSession::response_received(byte type){ TrTtlMsg ttlm; stop(); if (type == ICMP_TYPE_UNREACH || type == ICMP_TYPE_ECHOREPLY) { if (iteration == 0) terminating = true; } else terminating = false; // Start of new probe sequence? if (iteration++ == MAXITER) { if (terminating || ++ttl > maxttl) { simsys->traceroutes.remove(this); delete this; return; } iteration = 0; ttlm.ttl = ttl; simsys->ctl_pkt.queue_xpkt(&ttlm, SIM_TRACEROUTE_TTL, index1(), sizeof(ttlm)); } // Send next probe packet simsys->sendicmp(ICMP_TYPE_ECHO, 0, 0, dest, 0, index1(), seqno++, ttl); start(2*maxttl*10, false);}/* When the ping session timer fires, we send another ICMP * echo. */void SimSys::sendicmp(byte type, byte code, InAddr src, InAddr dest, InPkt *rcvd, uns16 id, uns16 seqno, byte ttl){ InPkt *iphdr; IcmpPkt *icmphdr; int len; IcmpPkt *r_icmp = 0; int iphlen = 0; if (rcvd) { dest = ntoh32(rcvd->i_src); iphlen = (rcvd->i_vhlen & 0xf) << 2; r_icmp = (IcmpPkt *) (((byte *) rcvd) + iphlen); } switch (type) { case ICMP_TYPE_ECHO: len = sizeof(InPkt) + sizeof(IcmpPkt) + sizeof(SPFtime); break; case ICMP_TYPE_ECHOREPLY: len = ntoh16(rcvd->i_len) - iphlen; len += sizeof(InPkt); break; default: // Don't respond to errors with errors if (rcvd->i_prot == PROT_ICMP && r_icmp->ic_type != ICMP_TYPE_ECHO && r_icmp->ic_type != ICMP_TYPE_ECHOREPLY) return; len = MIN(ntoh16(rcvd->i_len), ICMP_ERR_RETURN_BYTES); len += sizeof(InPkt) + sizeof(IcmpPkt); break; } iphdr = (InPkt *) new byte[len]; iphdr->i_vhlen = IHLVER; iphdr->i_tos = 0; iphdr->i_ffo = 0; iphdr->i_prot = PROT_ICMP; iphdr->i_len = hton16(len); iphdr->i_id = 0; iphdr->i_ttl = ((ttl != 0) ? ttl : DEFAULT_TTL); iphdr->i_src = src ? hton32(src) : hton32(ip_source(dest)); iphdr->i_dest = hton32(dest); iphdr->i_chksum = 0; // Don't bother icmphdr = (IcmpPkt *) (iphdr + 1); icmphdr->ic_type = type; icmphdr->ic_code = code; icmphdr->ic_chksum = 0; // Don't bother // Fill in body switch (type) { int rlen; case ICMP_TYPE_ECHO: SPFtime *timep; icmphdr->ic_id = hton16(id); icmphdr->ic_seqno = hton16(seqno); timep = (SPFtime *) (icmphdr+1); *timep = sys_etime; break; case ICMP_TYPE_ECHOREPLY: icmphdr->ic_id = r_icmp->ic_id; icmphdr->ic_seqno = r_icmp->ic_seqno; rlen = ntoh16(rcvd->i_len) - iphlen - sizeof(IcmpPkt); if (rlen > 0) memcpy(icmphdr+1, r_icmp+1, rlen); break; default: rlen = MIN(ntoh16(rcvd->i_len), ICMP_ERR_RETURN_BYTES); memcpy(icmphdr+1, rcvd, rlen); break; } if (iphdr->i_ttl-- == 1) sendicmp(ICMP_TYPE_TTL_EXCEED, 0, 0, 0, iphdr, 0, 0, 0); else simsys->sendpkt(iphdr); delete [] ((byte *) iphdr);}/* The follow two routines taken from ospfd's INtbl * and INrte classes. * Should make these utility routines. *//* Add an entry to an IP routing table entry. Install the * prefix pointers so that the best match operations will * work correctly. */SimRte *SimRttbl::add(uns32 net, uns32 mask){ SimRte *rte; SimRte *parent; SimRte *child; AVLsearch iter(&routes); if ((rte = (SimRte *) routes.find(net, mask))) return(rte); // Add to routing table entry rte = new SimRte(net, mask); routes.add(rte); // Set prefix pointer parent = (SimRte *) routes.previous(net, mask); for (; parent; parent = parent->prefix) { if (rte->is_child(parent)) { rte->prefix = parent; break; } } // Set children's parent pointers iter.seek(rte); while ((child = (SimRte *)iter.next()) && child->is_child(rte)) { if (child->prefix && child->prefix->is_child(rte)) continue; child->prefix = rte; } return(rte);}/* Find the best matching routing table entry for a given * IP destination. */SimRte *SimRttbl::best_match(uns32 addr){ SimRte *rte; SimRte *prev; rte = (SimRte *) routes.root(); prev = 0; while (rte) { if (addr < rte->net()) rte = (SimRte *) rte->go_left(); else if (addr > rte->net() || 0xffffffff > rte->mask()) { prev = rte; rte = (SimRte *) rte->go_right(); } else // Matching host route break; } // If no exact match, take previous entry if (!rte) rte = prev; // Go up prefix chain, looking for valid routes for (; rte; rte = rte->prefix) { if ((addr & rte->mask()) != rte->net()) continue; if (rte->reachable) break; } return((!rte || rte->reject) ? 0 : rte);}/* Find the source address that would be used to send * packets to the given destination. */InAddr SimSys::ip_source(InAddr dest){ SimRte *rte; if ((rte = rttbl.best_match(dest))) { if (rte->if_addr != 0) return(rte->if_addr); } return(my_addr);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -