📄 sim.c
字号:
/* * OSPFD routing simulation controller * Copyright (C) 1999 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 <sys/param.h>#include <unistd.h>#include <tcl.h>#include <tk.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <signal.h>#include <syslog.h>#include "../src/ospfinc.h"#include "../src/monitor.h"#include "../src/system.h"#include "tcppkt.h"#include "machtype.h"#include "sim.h"#include "simctl.h"#include <time.h>#include "mtrace.h"/* Forward references */bool get_prefix(char *prefix, InAddr &net, InMask &mask);// Tk/Tcl callbacksvoid tick(ClientData);int StartRouter(ClientData, Tcl_Interp *, int, char *argv[]);int ToggleRouter(ClientData, Tcl_Interp *, int, char *argv[]);int RestartRouter(ClientData, Tcl_Interp *, int, char *argv[]);int HitlessRestart(ClientData, Tcl_Interp *, int, char *argv[]);int StartPing(ClientData, Tcl_Interp *, int, char *argv[]);int StopPing(ClientData, Tcl_Interp *, int, char *argv[]);int StartTraceroute(ClientData, Tcl_Interp *, int, char *argv[]);int StartMtrace(ClientData, Tcl_Interp *, int, char *argv[]);int PrefixMatch(ClientData, Tcl_Interp *, int, char *argv[]);int AddMapping(ClientData, Tcl_Interp *, int, char *argv[]);int AddNetMember(ClientData, Tcl_Interp *interp, int, char *argv[]);int TimeStop(ClientData, Tcl_Interp *, int, char *argv[]);int TimeResume(ClientData, Tcl_Interp *, int, char *argv[]);int SendGeneral(ClientData, Tcl_Interp *, int, char *argv[]);int SendArea(ClientData, Tcl_Interp *, int, char *argv[]);int SendInterface(ClientData, Tcl_Interp *, int, char *argv[]);int SendVL(ClientData, Tcl_Interp *, int, char *argv[]);int SendNeighbor(ClientData, Tcl_Interp *, int, char *argv[]);int SendAggregate(ClientData, Tcl_Interp *, int, char *argv[]);int SendHost(ClientData, Tcl_Interp *, int, char *argv[]);int SendExtRt(ClientData, Tcl_Interp *, int, char *argv[]);int SendGroup(ClientData, Tcl_Interp *, int, char *argv[]);int LeaveGroup(ClientData, Tcl_Interp *, int, char *argv[]);// Global variableschar *sim_tcl_src = "/ospf_sim.tcl";char *cfgfile = 0;SimCtl *sim;/* Process messages received from simulated nodes. */bool SimCtl::process_replies(){ int n_fd; fd_set fdset; int err; SimNode *node; timeval timeout; bool active = false; FD_ZERO(&fdset); // Add listen socket n_fd = server_fd; FD_SET(server_fd, &fdset); // Add one connection per simulated router for (int i = 0; i <= maxfd; i++) { if (!(node = nodes[i])) continue; n_fd = MAX(n_fd, node->fd); FD_SET(node->fd, &fdset); } // Poll for I/O timeout.tv_sec = 0; timeout.tv_usec = 0; err = select(n_fd+1, &fdset, 0, 0, &timeout); // Handle errors in select if (err == -1 && errno != EINTR) { perror("select failed"); exit(1); } // Handle new connections if (FD_ISSET(server_fd, &fdset)) { active = true; incoming_call(); } // Handle replies from simulated routers for (int i = 0; i <= maxfd; i++) { if (!(node = nodes[i])) continue; if (FD_ISSET(node->fd, &fdset)) { active = true; simnode_handler_read(node->fd); } } return(active);}/* Send data to simulated nodes. */bool SimCtl::send_data(){ int n_fd; fd_set wrset; int err; SimNode *node; timeval timeout; bool active=false; FD_ZERO(&wrset); n_fd = -1; // Add one connection per simulated router // If we have data pending to that node for (int i = 0; i <= maxfd; i++) { if (!(node = nodes[i])) continue; if (node->pktdata.xmt_pending()) { n_fd = MAX(n_fd, node->fd); FD_SET(node->fd, &wrset); } } // No data to send? if (n_fd == -1) return(active); // Poll for I/O timeout.tv_sec = 0; timeout.tv_usec = 0; err = select(n_fd+1, 0, &wrset, 0, &timeout); // Handle errors in select if (err == -1 && errno != EINTR) { perror("select failed"); exit(1); } // Write pending data if there is space for (int i = 0; i <= maxfd; i++) { if (!(node = nodes[i])) continue; if ((node == nodes[i]) && FD_ISSET(node->fd, &wrset)) { active = true; if (!node->pktdata.sendpkt()) delete_router(node); } } return(active);}/* Controlling process for the OSPF simulator. * After initialization, simply send timer ticks * to each simulated OSPF router and wait for their * replies. Their replies indicate whether they have * synchronized databases. Also can receiving logging * messages from the simulated routers, which are * written to a file. */int main(int argc, char *argv[]){ Tcl_Interp *interp; // Interpretation of config commands if (argc > 2) { printf("Syntax: ospf_sim [config_filename]\n"); exit(1); } if (argc == 2) cfgfile = argv[1]; interp = Tcl_CreateInterp(); Tcl_AppInit(interp); // Main loop, never exits Tk_MainLoop(); exit(0);}/* Initialize the simulation. * First read the TCL commands, and register * those that are written in C++. Then read the configuration * file (if any), and start separate processes for each * simulated router. When the router connects * to the controller, send it its complete configuration. */int Tcl_AppInit(Tcl_Interp *interp){// rlimit rlim; int fd; struct sockaddr_in addr; socklen size; int namlen; char *filename; // Allow core files// rlim.rlim_max = RLIM_INFINITY;// (void) setrlimit(RLIMIT_CORE, &rlim); // Create simulation controller sim = new SimCtl(interp); // Complete interpreter initialization if (Tcl_Init(interp) != TCL_OK) { printf("Error in Tcl_Init(): %s\n", interp->result); exit(1); } if (Tk_Init(interp) != TCL_OK) { printf("Error in Tk_Init(): %s\n", interp->result); exit(1); } // Install C-language TCl commands Tcl_CreateCommand(interp, "startrtr", StartRouter, 0, 0); Tcl_CreateCommand(interp, "togglertr", ToggleRouter, 0, 0); Tcl_CreateCommand(interp, "rstrtr", RestartRouter, 0, 0); Tcl_CreateCommand(interp, "hitlessrtr", HitlessRestart, 0, 0); Tcl_CreateCommand(interp, "start_ping", StartPing, 0, 0); Tcl_CreateCommand(interp, "stop_ping", StopPing, 0, 0); Tcl_CreateCommand(interp, "start_traceroute", StartTraceroute, 0, 0); Tcl_CreateCommand(interp, "start_mtrace", StartMtrace, 0, 0); Tcl_CreateCommand(interp, "prefix_match", PrefixMatch, 0, 0); Tcl_CreateCommand(interp, "add_mapping", AddMapping, 0, 0); Tcl_CreateCommand(interp, "add_net_membership", AddNetMember, 0, 0); Tcl_CreateCommand(interp, "time_stop", TimeStop, 0, 0); Tcl_CreateCommand(interp, "time_resume", TimeResume, 0, 0); Tcl_CreateCommand(interp, "sendgen", SendGeneral, 0, 0); Tcl_CreateCommand(interp, "sendarea", SendArea, 0, 0); Tcl_CreateCommand(interp, "sendifc", SendInterface, 0, 0); Tcl_CreateCommand(interp, "sendvl", SendVL, 0, 0); Tcl_CreateCommand(interp, "sendnbr", SendNeighbor, 0, 0); Tcl_CreateCommand(interp, "sendagg", SendAggregate, 0, 0); Tcl_CreateCommand(interp, "sendhost", SendHost, 0, 0); Tcl_CreateCommand(interp, "sendextrt", SendExtRt, 0, 0); Tcl_CreateCommand(interp, "sendgrp", SendGroup, 0, 0); Tcl_CreateCommand(interp, "leavegrp", LeaveGroup, 0, 0); // Read additional TCL commands namlen = strlen(INSTALL_DIR) + strlen(sim_tcl_src); filename = new char[namlen+1]; strcpy(filename, INSTALL_DIR); strcat(filename, sim_tcl_src); if (Tcl_EvalFile(interp, filename) != TCL_OK) { printf("Error in %s, line %d\r\n", filename, interp->errorLine); exit(1); } delete [] filename; // Create server socket fd = socket(AF_INET, SOCK_STREAM, 0); sim->server_fd = fd; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("bind"); exit (1); } size = sizeof(addr); if (getsockname(fd, (struct sockaddr *) &addr, &size) < 0) { perror("getsockname"); exit (1); } sim->assigned_port = ntohs(addr.sin_port); // Read config file if (cfgfile) { if (Tcl_EvalFile(interp, cfgfile) != TCL_OK) { printf("Error in %s, line %d", cfgfile, interp->errorLine); exit(1); } // Tell TCL the config file name if (Tcl_VarEval(sim->interp, "ConfigFile ", cfgfile, 0) != TCL_OK) printf("ConfigFile: %s\n", sim->interp->result); } // Use the sample.cfg configuration else { extern char *sample_cfg; int size; char *cmd; size = strlen(sample_cfg); cmd = new char[size+1]; strcpy(cmd, sample_cfg); if (Tcl_Eval(sim->interp, cmd) != TCL_OK) { printf("sample.cfg: %s\n", sim->interp->result); exit(1); } } // Now we're up and running sim->running = true; // Listen for simulated nodes that are initializing listen(fd, 150); // Start timer ticks Tk_CreateTimerHandler(1000/TICKS_PER_SECOND, tick, 0); return(TCL_OK);}/* Accept an incoming connection from a simulated router. * We don't add a simulated node yet, because we have to get * the first message to find out the router ID of the other * end. */void SimCtl::incoming_call(){ int fd; struct sockaddr_in addr; socklen len; SimNode *temp; len = sizeof(addr); if (!(fd = accept(server_fd, (struct sockaddr *) &addr, &len))) { perror("incoming_call:accept"); return; } // Allocate placeholder SimNode temp = new SimNode(0, fd);}/* Tick processing. If all nodes have responded, increase * the current time and send out a new round of ticks. */void tick(ClientData){ bool all_responded=true; AVLsearch *iter; SimNode *node; int max_sync = 0; NodeStats *max_dbstats=0; // Process all I/O from simulated nodes while (sim->process_replies()) ; // Check to see that all have responded iter = new AVLsearch(&sim->simnodes); while ((node = (SimNode *)iter->next())) { if (!node->got_tick) { all_responded = false; break; } } delete iter; // Recolor map according to latest database // statistics received iter = new AVLsearch(&sim->simnodes); while ((node = (SimNode *)iter->next())) { if (node->dbstats && node->dbstats->refct >= max_sync) { max_sync = node->dbstats->refct; max_dbstats = node->dbstats; } } delete iter; iter = new AVLsearch(&sim->simnodes); while ((node = (SimNode *)iter->next())) { in_addr addr; int old_color=node->color; char *color; if (!node->dbstats || node->dbstats->refct == 1) node->color = SimNode::WHITE; else if (node->dbstats == max_dbstats) node->color = SimNode::GREEN; else node->color = SimNode::ORANGE; if (old_color == node->color) continue; switch (node->color) { default: case SimNode::WHITE: color = " white"; break; case SimNode::GREEN: color = " green"; break; case SimNode::ORANGE: color = " orange"; break; } addr.s_addr = hton32(node->id()); if (Tcl_VarEval(sim->interp, "color_router ", inet_ntoa(addr), color, 0) != TCL_OK) printf("color_router: %s\n", sim->interp->result); } delete iter; // If all responded, and we're not frozen // Send out new timer ticks if (all_responded && !sim->frozen) { char display_buffer[20]; sim->n_ticks++; sprintf(display_buffer, "%d", sim->n_ticks); // Update displayed time if (Tcl_VarEval(sim->interp, "show_time ",display_buffer, 0) != TCL_OK) printf("show_time: %s\n", sim->interp->result); iter = new AVLsearch(&sim->simnodes); while ((node = (SimNode *)iter->next())) { TickBody tm; node->got_tick = false; tm.tick = sim->n_ticks; node->pktdata.queue_xpkt(&tm, SIM_TICK, 0, sizeof(tm)); } delete iter; } // Send all pending data to simulated routers while (sim->send_data()) ; // Regardless, schedule next tick() invocation Tk_CreateTimerHandler(1000/TICKS_PER_SECOND, tick, 0);}/* I/0 activity on the connection to a simulated router. * Process any reads, and send pending data if there is * room. */void SimCtl::simnode_handler_read(int fd){ SimNode *node; void *msg; uns16 type; uns16 subtype; int nbytes; if (!(node = sim->nodes[fd])) return; nbytes = node->pktdata.receive(&msg, type, subtype); if (nbytes < 0) { sim->delete_router(node); return; } if (type != 0) { SimHello *hello; DBStats *dbstats; in_addr addr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -