omnet++中的routing案例
Node.ned
module Node
{
parameters:
int address;
string appType;
@display("i=misc/node_vs,gold");
gates:
inout port[];
submodules:
app: <appType> like IApp {
parameters:
address = parent.address;
@display("p=140,60");
}
routing: Routing {
parameters:
@display("p=140,130");
gates:
in[sizeof(parent.port)];
out[sizeof(parent.port)];
}
queue[sizeof(port)]: L2Queue {
parameters:
@display("p=80,200,row");
}
connections:
routing.localOut --> app.in;
routing.localIn <-- app.out;
for i=0..sizeof(port)-1 {
routing.out[i] --> queue[i].in;
routing.in[i] <-- queue[i].out;
queue[i].line <--> port[i];
}
}
每一个节点模块叫Node,每一个Node中包括了3个小模块,1是app模块,2是routing模块,这个模块的下端接口可能有多个,每一个接口都会连接一个queue模块,3是queue模块,这个大的Node模块有几个总的port接口,queue就与几个。
app.ned
package node;
//
// Application model to generate traffic for the network.
//
simple App like IApp
{
parameters:
int address; // local node address
string destAddresses; // destination addresses
volatile double sendIaTime @unit(s) = default(exponential(1s)); // time between generating packets
volatile int packetLength @unit(byte); // length of one message (fixed! no "volatile" modifier)
@display("i=block/browser");
@signal[endToEndDelay](type="simtime_t");
@signal[hopCount](type="long");
@signal[sourceAddress](type="long");
@statistic[endToEndDelay](title="end-to-end delay of arrived packets";unit=s;record=vector,mean,max;interpolationmode=none);
@statistic[hopCount](title="hop count of arrived packets";interpolationmode=none;record=vector?,mean,max);
@statistic[sourceAddress](title="source address of arrived packets";interpolationmode=none;record=vector?);
gates:
input in;
output out;
}
app.cc
//
// This file is part of an OMNeT++/OMNEST simulation example.
//
// Copyright (C) 1992-2015 Andras Varga
//
// This file is distributed WITHOUT ANY WARRANTY. See the file
// `license' for details on this and other legal matters.
//
#ifdef _MSC_VER
#pragma warning(disable:4786)
#endif
#include <vector>
#include <omnetpp.h>
#include "Packet_m.h"
using namespace omnetpp;
/**
* Generates traffic for the network.
*/
class App : public cSimpleModule
{
private:
// configuration
int myAddress;
std::vector<int> destAddresses;
cPar *sendIATime;
cPar *packetLengthBytes;
// state
cMessage *generatePacket = nullptr;
long pkCounter;
// signals
simsignal_t endToEndDelaySignal;
simsignal_t hopCountSignal;
simsignal_t sourceAddressSignal;
public:
virtual ~App();
protected:
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
};
Define_Module(App);
App::~App()
{
cancelAndDelete(generatePacket);
}
void App::initialize()
{
myAddress = par("address");
packetLengthBytes = &par("packetLength");
sendIATime = &par("sendIaTime"); // volatile parameter
pkCounter = 0;
WATCH(pkCounter);
WATCH(myAddress);
const char *destAddressesPar = par("destAddresses");
cStringTokenizer tokenizer(destAddressesPar);
const char *token;
while ((token = tokenizer.nextToken()) != nullptr)
destAddresses.push_back(atoi(token));
if (destAddresses.size() == 0)
throw cRuntimeError("At least one address must be specified in the destAddresses parameter!");
generatePacket = new cMessage("nextPacket");
scheduleAt(sendIATime->doubleValue(), generatePacket);
endToEndDelaySignal = registerSignal("endToEndDelay");
hopCountSignal = registerSignal("hopCount");
sourceAddressSignal = registerSignal("sourceAddress");
}
void App::handleMessage(cMessage *msg)
{
if (msg == generatePacket) {
// Sending packet
int destAddress = destAddresses[intuniform(0, destAddresses.size()-1)];
char pkname[40];
sprintf(pkname, "pk-%d-to-%d-#%ld", myAddress, destAddress, pkCounter++);
EV << "generating packet " << pkname << endl;
Packet *pk = new Packet(pkname);
pk->setByteLength(packetLengthBytes->intValue());
pk->setKind(intuniform(0, 7));
pk->setSrcAddr(myAddress);
pk->setDestAddr(destAddress);
send(pk, "out");
scheduleAt(simTime() + sendIATime->doubleValue(), generatePacket);
if (hasGUI())
getParentModule()->bubble("Generating packet...");
}
else {
// Handle incoming packet
Packet *pk = check_and_cast<Packet *>(msg);
EV << "received packet " << pk->getName() << " after " << pk->getHopCount() << "hops" << endl;
emit(endToEndDelaySignal, simTime() - pk->getCreationTime());
emit(hopCountSignal, pk->getHopCount());
emit(sourceAddressSignal, pk->getSrcAddr());
delete pk;
if (hasGUI())
getParentModule()->bubble("Arrived!");
}
}
routing.ned
package node;
//
// Models a router.
//
simple Routing
{
parameters:
@display("i=block/switch");
@signal[drop](type="long");
@signal[outputIf](type="long");
@statistic[drop](title="dropped packet byte length";unit=bytes;record=vector?,count,sum;interpolationmode=none);
@statistic[outputIf](title="output interface for each routed packet";record=histogram;interpolationmode=none);
gates:
input in[];
output out[];
input localIn;
output localOut;
}
routing.cc
//
// This file is part of an OMNeT++/OMNEST simulation example.
//
// Copyright (C) 1992-2015 Andras Varga
//
// This file is distributed WITHOUT ANY WARRANTY. See the file
// `license' for details on this and other legal matters.
//
#ifdef _MSC_VER
#pragma warning(disable:4786)
#endif
#include <map>
#include <omnetpp.h>
#include "Packet_m.h"
using namespace omnetpp;
/**
* Demonstrates static routing, utilizing the cTopology class.
*/
class Routing : public cSimpleModule
{
private:
int myAddress;
typedef std::map<int, int> RoutingTable; // destaddr -> gateindex目的地址到索引门,给哪个点传信号应该从哪个门发出去
RoutingTable rtable;
simsignal_t dropSignal;
simsignal_t outputIfSignal;
protected:
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
};
Define_Module(Routing);
void Routing::initialize()
{
myAddress = getParentModule()->par("address");
dropSignal = registerSignal("drop");
outputIfSignal = registerSignal("outputIf");
//
// Brute force approach -- every node does topology discovery on its own,
// and finds routes to all other nodes independently, at the beginning
// of the simulation. This could be improved: (1) central routing database,
// (2) on-demand route calculation
//
cTopology *topo = new cTopology("topo");
std::vector<std::string> nedTypes;
nedTypes.push_back(getParentModule()->getNedTypeName());
topo->extractByNedTypeName(nedTypes);
EV << "cTopology found " << topo->getNumNodes() << " nodes\n";
cTopology::Node *thisNode = topo->getNodeFor(getParentModule());
// find and store next hops
for (int i = 0; i < topo->getNumNodes(); i++) {
if (topo->getNode(i) == thisNode)
continue; // skip ourselves
topo->calculateUnweightedSingleShortestPathsTo(topo->getNode(i));
if (thisNode->getNumPaths() == 0)
continue; // not connected
cGate *parentModuleGate = thisNode->getPath(0)->getLocalGate();
int gateIndex = parentModuleGate->getIndex();
int address = topo->getNode(i)->getModule()->par("address");
rtable[address] = gateIndex;
EV << " towards address " << address << " gateIndex is " << gateIndex << endl;
}
delete topo;
}
void Routing::handleMessage(cMessage *msg)
{
Packet *pk = check_and_cast<Packet *>(msg);
int destAddr = pk->getDestAddr();
if (destAddr == myAddress) {
EV << "local delivery of packet " << pk->getName() << endl;
send(pk, "localOut");
emit(outputIfSignal, -1); // -1: local
return;
}
RoutingTable::iterator it = rtable.find(destAddr);
if (it == rtable.end()) {
EV << "address " << destAddr << " unreachable, discarding packet " << pk->getName() << endl;
emit(dropSignal, (intval_t)pk->getByteLength());
delete pk;
return;
}
int outGateIndex = (*it).second;
EV << "forwarding packet " << pk->getName() << " on gate index " << outGateIndex << endl;
pk->setHopCount(pk->getHopCount()+1);
emit(outputIfSignal, outGateIndex);
send(pk, "out", outGateIndex);
}
l2queue.ned
simple L2Queue
{
parameters:
int frameCapacity = default(0); // max number of packets; 0 means no limit
bool useCutThroughSwitching = default(false); // use cut-through switching instead of store-and-forward
@display("i=block/queue;q=queue");
@signal[qlen](type="long");
@signal[busy](type="bool");
@signal[queueingTime](type="simtime_t");
@signal[drop](type="long");
@signal[txBytes](type="long");
@signal[rxBytes](type="long");
@statistic[qlen](title="queue length";record=vector?,timeavg,max;interpolationmode=sample-hold);
@statistic[busy](title="server busy state";record=vector?,timeavg;interpolationmode=sample-hold);
@statistic[queueingTime](title="queueing time at dequeue";unit=s;interpolationmode=none);
@statistic[drop](title="dropped packet byte length";unit=bytes;record=vector?,count,sum;interpolationmode=none);
@statistic[txBytes](title="transmitting packet byte length";unit=bytes;record=vector?,count,sum,histogram;interpolationmode=none);
@statistic[rxBytes](title="received packet byte length";unit=bytes;record=vector?,count,sum,histogram;interpolationmode=none);
gates:
input in;
output out;
inout line;
}
l2queue.cc
//
// This file is part of an OMNeT++/OMNEST simulation example.
//
// Copyright (C) 1992-2015 Andras Varga
//
// This file is distributed WITHOUT ANY WARRANTY. See the file
// `license' for details on this and other legal matters.
//
#include <stdio.h>
#include <string.h>
#include <omnetpp.h>
using namespace omnetpp;
/**
* Point-to-point interface module. While one frame is transmitted,
* additional frames get queued up; see NED file for more info.
*/
class L2Queue : public cSimpleModule
{
private:
intval_t frameCapacity;
cQueue queue;
cMessage *endTransmissionEvent = nullptr;
bool isBusy;
simsignal_t qlenSignal;
simsignal_t busySignal;
simsignal_t queueingTimeSignal;
simsignal_t dropSignal;
simsignal_t txBytesSignal;
simsignal_t rxBytesSignal;
public:
virtual ~L2Queue();
protected:
virtual void initialize() override;
virtual void handleMessage(cMessage *msg) override;
virtual void refreshDisplay() const override;
virtual void startTransmitting(cMessage *msg);
};
Define_Module(L2Queue);
L2Queue::~L2Queue()
{
cancelAndDelete(endTransmissionEvent);
}
void L2Queue::initialize()
{
queue.setName("queue");
endTransmissionEvent = new cMessage("endTxEvent");
if (par("useCutThroughSwitching"))
{gate("line$i")->setDeliverImmediately(true);}
frameCapacity = par("frameCapacity");
qlenSignal = registerSignal("qlen");
busySignal = registerSignal("busy");
queueingTimeSignal = registerSignal("queueingTime");
dropSignal = registerSignal("drop");
txBytesSignal = registerSignal("txBytes");
rxBytesSignal = registerSignal("rxBytes");
emit(qlenSignal, queue.getLength());
emit(busySignal, false);
isBusy = false;
}
void L2Queue::startTransmitting(cMessage *msg)
{
EV << "Starting transmission of " << msg << endl;
isBusy = true;
int64_t numBytes = check_and_cast<cPacket *>(msg)->getByteLength();
send(msg, "line$o");
emit(txBytesSignal, numBytes);
// Schedule an event for the time when last bit will leave the gate.
simtime_t endTransmission = gate("line$o")->getTransmissionChannel()->getTransmissionFinishTime();
scheduleAt(endTransmission, endTransmissionEvent);
}
void L2Queue::handleMessage(cMessage *msg)
{
if (msg == endTransmissionEvent) {
// Transmission finished, we can start next one.
EV << "Transmission finished.\n";
isBusy = false;
if (queue.isEmpty()) {
emit(busySignal, false);
}
else {
msg = (cMessage *)queue.pop();
emit(queueingTimeSignal, simTime() - msg->getTimestamp());
emit(qlenSignal, queue.getLength());
startTransmitting(msg);
}
}
else if (msg->arrivedOn("line$i")) {
// pass up
emit(rxBytesSignal, (intval_t)check_and_cast<cPacket *>(msg)->getByteLength());
send(msg, "out");
}
else { // arrived on gate "in"
if (endTransmissionEvent->isScheduled()) {
// We are currently busy, so just queue up the packet.
if (frameCapacity && queue.getLength() >= frameCapacity) {
EV << "Received " << msg << " but transmitter busy and queue full: discarding\n";
emit(dropSignal, (intval_t)check_and_cast<cPacket *>(msg)->getByteLength());
delete msg;
}
else {
EV << "Received " << msg << " but transmitter busy: queueing up\n";
msg->setTimestamp();
queue.insert(msg);
emit(qlenSignal, queue.getLength());
}
}
else {
// We are idle, so we can start transmitting right away.
EV << "Received " << msg << endl;
emit(queueingTimeSignal, SIMTIME_ZERO);
startTransmitting(msg);
emit(busySignal, true);
}
}
}
void L2Queue::refreshDisplay() const
{
getDisplayString().setTagArg("t", 0, isBusy ? "transmitting" : "idle");
getDisplayString().setTagArg("i", 1, isBusy ? (queue.getLength() >= 3 ? "red" : "yellow") : "");
}
packet.msg
packet Packet
{
int srcAddr @packetData;
int destAddr @packetData;
int hopCount @packetData;
}