📄 ospfd_sim.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. */#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/time.h>#include <sys/resource.h>#include <unistd.h>#include <tcl.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <net/if.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include "../src/ospfinc.h"#include "../src/monitor.h"#include "../src/system.h"#include "tcppkt.h"#include "machtype.h"#include "sim.h"#include "mtrace.h"#include "ospfd_sim.h"#include <time.h>#include "icmp.h"rtid_t my_id;SimSys *simsys;char buffer[MAX_IP_PKTSIZE];char *LOOPADDR = "127.0.0.1";char *BROADADDR = "127.255.255.255";// External declarations/* The main simulated OSPF loop. Loops getting messages (packets, timer * ticks, configuration messages, etc.) and never returns * until the simulated OSPF process is told to exit. * Syntax: * ospfd_sim "router_id" "controller_port" */int main(int argc, char *argv[]){ int n_fd; fd_set fdset; fd_set wrset; uns16 controller_port; char temp[30]; int stat; int ctl_fd; // Get command line arguments if (argc != 3) { printf("syntax: ospfd_mon $router_id $controller_port\n"); exit(1); } my_id = ntoh32(inet_addr(argv[1])); controller_port = atoi(argv[2]); // Start random number generator srand(getpid()); // Connect to simulation controller // Keep on trying if we're getting timeouts do { sockaddr_in ctl_addr; if (!(ctl_fd = socket(AF_INET, SOCK_STREAM, 0))) { perror("create control socket"); exit(1); } memset((char *) &ctl_addr, 0, sizeof(ctl_addr)); ctl_addr.sin_family = AF_INET; ctl_addr.sin_addr.s_addr = inet_addr(LOOPADDR); ctl_addr.sin_port = hton16(controller_port); stat = connect(ctl_fd, (struct sockaddr *) &ctl_addr,sizeof(ctl_addr)); if (stat < 0) { close(ctl_fd); usleep ((int) ((1000000.0*rand())/(RAND_MAX+1.0))); } } while (stat < 0); // Create simulation environment sys = simsys = new SimSys(ctl_fd); // Log command arguments sprintf(temp, "invoked: ospfd_sim %s %s", argv[1], argv[2]); simsys->sys_spflog(ERR_SYS, temp); // Main loop, never exits while (1) { bool ifc_data=false; FD_ZERO(&fdset); FD_ZERO(&wrset); // Flush any logging messages if (ospf) ospf->logflush(); // If hitless restart preparation done, start ospfd again if (simsys->hitless_preparation_complete) { simsys->hitless_preparation_complete = false; delete ospf; ospf = 0; } // Add connection to controller n_fd = simsys->ctl_fd; FD_SET(simsys->ctl_fd, &fdset); if (simsys->ctl_pkt.xmt_pending()) FD_SET(simsys->ctl_fd, &wrset); // Add our private port n_fd = MAX(n_fd, simsys->uni_fd); FD_SET(simsys->uni_fd, &fdset); // Add monitoring connection simsys->mon_fd_set(n_fd, &fdset, &wrset); // Wait for I/O if (select(n_fd+1, &fdset, &wrset, 0, 0) < 0) simsys->halt(1, "select failed"); // Process received data if (FD_ISSET(simsys->ctl_fd, &wrset)) simsys->ctl_pkt.sendpkt(); // Received OSPF packets? if (FD_ISSET(simsys->uni_fd, &fdset)) { ifc_data = true; simsys->process_uni_fd(); } // Instructions from controller? if (!ifc_data && FD_ISSET(simsys->ctl_fd, &fdset)) simsys->recv_ctl_command(); // Process monitor queries and responses simsys->process_mon_io(&fdset, &wrset); } exit(0);}/* Process packets received on our private socket. * These are packets that have been sent directly * to us. If the destination address belongs to us, * forward it to the demux. Otherwise, do a routing lookup * on the packet and forward it further. */void SimSys::process_uni_fd(){ int plen; sockaddr_in addr; socklen fromlen=sizeof(addr); SimPktHdr *pkthdr; InPkt *pkt; SPFtime rcvd; SPFtime limit; plen = recvfrom(uni_fd, buffer, sizeof(buffer), 0, (sockaddr *)&addr, &fromlen); pkthdr = (SimPktHdr *) buffer; pkt = (InPkt *) (pkthdr+1); if (plen < (int) sizeof(SimPktHdr) || plen < (int) (sizeof(SimPktHdr) + ntoh16(pkt->i_len))) { perror("recvfrom"); return; } rcvd = pkthdr->ts; time_add(rcvd, LINK_DELAY, &pkthdr->ts); time_add(sys_etime, 1000/TICKS_PER_SECOND, &limit); if (time_less(pkthdr->ts, limit)) rxpkt(pkthdr); else queue_rcv(pkthdr, plen);}/* Process a received packet. Determine whether it is for us. * if not, try to forward, otherwise perform the local demux * functions. */void SimSys::rxpkt(SimPktHdr *pkthdr){ InPkt *pkt; InAddr daddr; SimRte *rte; pkt = (InPkt *) (pkthdr+1); daddr = ntoh32(pkt->i_dest); xmt_stamp = pkthdr->ts; if (!IN_CLASSD(daddr)) { InAddr home; if ((!get_port_addr(daddr, home)) || (home != my_id)) { if (!(rte = rttbl.best_match(daddr))) { sendicmp(ICMP_TYPE_UNREACH, ICMP_CODE_UNREACH_HOST, 0, 0, pkt, 0, 0, 0); } // Decrement TTL. We don't use checksums in the // IP header of simulated packets else if (pkt->i_ttl == 0 || pkt->i_ttl-- == 1) { sendicmp(ICMP_TYPE_TTL_EXCEED, 0, 0, 0, pkt, 0, 0, 0); } else { InAddr gw; gw = rte->gw; if (gw != 0 && rte->if_addr == 0) gw = (InAddr) -1; sendpkt(pkt, rte->phyint, gw); } } else local_demux(pkthdr); } else { mc_fwd(ntoh32(pkthdr->phyint), pkt); local_demux(pkthdr); }}/* Have received an IP packet that is addressed to * us (may be a multicast). * Fir determine if we are a member of the multicast group, * and then dispatch on protocol number. */void SimSys::local_demux(SimPktHdr *pkthdr){ InAddr dest; PhyintMap *phyp; InPkt *pkt; int phyint; pkt = (InPkt *) (pkthdr+1); phyint = ntoh32(pkthdr->phyint); if (!(phyp = (PhyintMap *)port_map.find(phyint,0))) return; if (phyp->promiscuous && pkt->i_prot == PROT_IGMP) { igmp_demux(phyint, pkt); return; } dest = ntoh32(pkt->i_dest); if (IN_CLASSD(dest)) { if (!membership.find(dest, phyint)) return; } switch(pkt->i_prot) { case PROT_OSPF: // Discard packet if OSPF not ready if (ospf) ospf->rxpkt(phyint, pkt, ntoh16(pkt->i_len)); break; case PROT_ICMP: IcmpPkt *icmphdr; SPFtime *timep; IcmpErrMsg emsg; uns16 s_id; TRSession *tr; icmphdr = (IcmpPkt *) (pkt + 1); switch (icmphdr->ic_type) { case ICMP_TYPE_ECHO: sendicmp(ICMP_TYPE_ECHOREPLY, 0, 0, 0, pkt, 0, 0, 0); break; case ICMP_TYPE_ECHOREPLY: s_id = ntoh16(icmphdr->ic_id); timep = (SPFtime *) (icmphdr+1); if ((tr = (TRSession *)traceroutes.find(s_id,0))) { emsg.src = ntoh32(pkt->i_src); emsg.type = icmphdr->ic_type; emsg.code = icmphdr->ic_code; emsg.msd = time_diff(pkthdr->ts, *timep); emsg.icmp_seq = ntoh16(icmphdr->ic_seqno); ctl_pkt.queue_xpkt(&emsg, SIM_ICMP_ERROR, s_id, sizeof(emsg)); tr->response_received(ICMP_TYPE_ECHOREPLY); } else { EchoReplyMsg msg; msg.src = ntoh32(pkt->i_src); msg.msd = time_diff(pkthdr->ts, *timep); msg.icmp_seq = ntoh16(icmphdr->ic_seqno); msg.ttl = pkt->i_ttl; ctl_pkt.queue_xpkt(&msg, SIM_ECHO_REPLY, s_id, sizeof(msg)); } break; // ICMP error messages come here! default: InPkt *encap_hdr; s_id = 0; emsg.src = ntoh32(pkt->i_src); emsg.type = icmphdr->ic_type; emsg.code = icmphdr->ic_code; encap_hdr = (InPkt *) (icmphdr +1); if (encap_hdr->i_prot == PROT_ICMP) { IcmpPkt *encap_icmp; encap_icmp = (IcmpPkt *) (encap_hdr + 1); s_id = ntoh16(encap_icmp->ic_id); timep = (SPFtime *) (encap_icmp+1); emsg.msd = time_diff(pkthdr->ts, *timep); emsg.icmp_seq = ntoh16(encap_icmp->ic_seqno); } ctl_pkt.queue_xpkt(&emsg, SIM_ICMP_ERROR, s_id, sizeof(emsg)); if ((tr = (TRSession *)traceroutes.find(s_id,0))) tr->response_received(emsg.type); break; } break; case PROT_IGMP: igmp_demux(phyint, pkt); break; default: break; }}/* Initialize the Simulation environment. * Connect to the controller * Start the random number generator. */SimSys::SimSys(int fd) : OSInstance(0), ctl_pkt(fd){// rlimit rlim; sockaddr_in addr; socklen size; SimHello hello; grace_period = sys_etime; hitless_preparation = false; hitless_preparation_complete = false; ctl_fd = fd; my_addr = 0; // Initialize time ticks = 0; // Allow core files// rlim.rlim_max = RLIM_INFINITY;// (void) setrlimit(RLIMIT_CORE, &rlim); // Open our unicast socket, where people send packets // addressed to us (unicasts and multicasts) uni_fd = socket(AF_INET, SOCK_DGRAM, 0); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(uni_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) perror("bind fails"); size = sizeof(addr); if (getsockname(uni_fd, (struct sockaddr *) &addr, &size) < 0) { perror("getsockname"); exit (1); } uni_port = ntohs(addr.sin_port); // Identify ourselves to the server hello.rtrid = my_id; hello.myport = hton16(uni_port); ctl_pkt.queue_xpkt(&hello, SIM_HELLO, 0, sizeof(hello)); // Open monitoring listen socket monitor_listen(); // Set transmission timestamp xmt_stamp = sys_etime; // Initialize mtrace query IDs mtrace_qid = 0;}/* Destructor not expected to be called during the life * of the program. */SimSys::~SimSys(){}/* Process command received over the controller * connection. */void SimSys::recv_ctl_command(){ uns16 type; uns16 subtype; int nbytes; char *msg; char *end; nbytes = ctl_pkt.receive((void **)&msg, type, subtype); if (nbytes < 0) simsys->halt(1, "Lost controller connection"); else if (type != 0) { AddrMap *addrmap; PingSession *ping; TRSession *tr; PingStartMsg *pm; MTraceHdr *mtrm; MTraceSession *mtrace; HitlessRestartMsg *htlm; int phyint; end = msg + nbytes; xmt_stamp = sys_etime; switch (type) { TickBody *tm; GroupMsg *grpm; case SIM_FIRST_TICK: // Init time before any configuration is downloaded tm = (TickBody *) msg; ticks = tm->tick; sys_etime.sec = ticks/TICKS_PER_SECOND; sys_etime.msec = (ticks%TICKS_PER_SECOND) * 1000/TICKS_PER_SECOND; xmt_stamp = sys_etime; // Start OSPF, delayed so that time is initialized // correctly ospf = new OSPF(my_id, sys_etime); break; case SIM_TICK: // Advance time tm = (TickBody *) msg; ticks = tm->tick; sys_etime.sec = ticks/TICKS_PER_SECOND; sys_etime.msec = (ticks%TICKS_PER_SECOND) * 1000/TICKS_PER_SECOND; xmt_stamp = sys_etime; // Process any pending timers if (ospf) ospf->tick(); // Process any queued receives process_rcvqueue(); // Send tick reponse send_tick_response(); break; case SIM_CONFIG: case SIM_CONFIG_DEL: config(type, subtype, msg); break; case SIM_SHUTDOWN: if (ospf) ospf->shutdown(10); break; case SIM_ADDRMAP: addrmap = (AddrMap *) msg; for (; (char *)(addrmap + 1) <= end; addrmap++) { AddressMap *entry; InAddr addr; InAddr home; addr = addrmap->addr; home = addrmap->home; if (!(entry = (AddressMap *) address_map.find(addr, home))) { entry = new AddressMap(addr, home); address_map.add(entry); } if (addrmap->port == 0) { address_map.remove(entry); delete entry; } else { entry->port = (uns16) addrmap->port; entry->home = addrmap->home; } } break; case SIM_START_PING: pm = (PingStartMsg *) msg; ping = new PingSession(subtype, pm->src, pm->dest, pm->ttl); pings.add(ping); ping->start(Timer::SECOND, false); break; case SIM_STOP_PING: if ((ping = (PingSession *)pings.find(subtype, 0))) { ping->stop(); pings.remove(ping); delete ping; } break; case SIM_START_TR: pm = (PingStartMsg *) msg; tr = new TRSession(subtype, pm->dest, pm->ttl); traceroutes.add(tr); tr->response_received(255); break; case SIM_ADD_MEMBER: grpm = (GroupMsg *) msg; if (ospf) ospf->join_indication(grpm->group, grpm->phyint); join(grpm->group, grpm->phyint); break; case SIM_DEL_MEMBER: grpm = (GroupMsg *) msg; if (ospf) ospf->leave_indication(grpm->group, grpm->phyint); leave(grpm->group, grpm->phyint); break; case SIM_START_MTRACE: mtrm = (MTraceHdr *) msg; phyint = (int) mtrm->ttl_qid; mtrm->ttl_qid = 0; mtrace = new MTraceSession(subtype, phyint, mtrm); mtraces.add(mtrace); mtrace->send_query(); break; case SIM_RESTART: close_monitor_connections(); delete ospf; ospf = 0; // Will then get First tick, and config break; case SIM_RESTART_HITLESS: htlm = (HitlessRestartMsg *) msg; if (ospf) ospf->hitless_restart(htlm->period, 1); else ospf = new OSPF(my_id, grace_period); break; default: break; } }}/* Configuration request. Dispatch to the correct routine * to do specific processing. */void SimSys::config(int type, int subtype, void *msg){ int status; status = (type == SIM_CONFIG) ? ADD_ITEM : DELETE_ITEM; if (!ospf) return; switch(subtype) { PhyintMap *phyp; CfgIfc *ifcmsg; case CfgType_Gen:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -