Connect all Compound Module Gates to Submodule in Omnet++ - omnet++

I am relatively new to Omnet++. Currently I am trying to encapsulate a flooding (simple) module inside a compound module. This is what I came up with:
Node.ned:
module Node
{
gates:
inout g[];
submodules:
floodingModule: FloodingModule;
connections allowunconnected:
g++ <--> floodingModule.g++;
}
FloodingModule.ned
simple FloodingNode
{
parameters:
bool sendInitialMessage = default(false);
gates:
inout g[] #loose;
}
Network.ned
network FloodingNetworkSmall {
submodules:
node0 : Node;
node1 : Node;
node2 : Node;
node3 : Node;
node4 : Node;
node5 : Node;
node6 : Node;
node7 : Node;
node8 : Node;
node9 : Node;
connections:
node0.g++ <--> Link <--> node1.g++;
node0.g++ <--> Link <--> node3.g++;
node0.g++ <--> Link <--> node5.g++;
node1.g++ <--> Link <--> node2.g++;
node1.g++ <--> Link <--> node4.g++;
node1.g++ <--> Link <--> node6.g++;
node1.g++ <--> Link <--> node7.g++;
node1.g++ <--> Link <--> node9.g++;
node2.g++ <--> Link <--> node5.g++;
node2.g++ <--> Link <--> node8.g++;
node3.g++ <--> Link <--> node4.g++;
node3.g++ <--> Link <--> node6.g++;
node4.g++ <--> Link <--> node6.g++;
node4.g++ <--> Link <--> node8.g++;
node6.g++ <--> Link <--> node7.g++;
node7.g++ <--> Link <--> node8.g++;
}
I am calling the flooding in the initialize method of the floodingModule like this:
for (GateIterator i(this); !i.end(); i++) {
cGate *gate = *i;
if (gate->getType() == cGate::OUTPUT) {
SimpleMessage *csmsg = smsg->dup();
send(csmsg, gate);
}
}
The problem I am facing is, that the flooding only happens on the first link that is created. This means, there must be a problem mapping the compound module gates to the submodule gates, or not? Am I doing something wrong here which is obvious? Do you need more code?
Thanks for any advice!

I couldn't even start the simulation with your code unmodified, because there were unconnected gates. (And there are some mildly annoying inconsistencies between file and module names, with the words Node and Module, but that is beside the point.)
To solve this, you need to change the connections segment of your Node module to something similar to what's in the Node module of the routing sample simulation included with OMNeT++:
module Node
{
gates:
inout g[];
submodules:
floodingModule: FloodingNode;
connections:
for i=0..sizeof(g)-1 { // <= this is the important part
g++ <--> floodingModule.g++;
}
}
The point is that for every "outside" connection between Nodes in the network, there has to be a corresponding connection (to continue the path) inside the Node module (at each end), between it and the floodingNode submodule. There is no "automatic merging/diverging" of connection paths at the gate vectors on compound module boundaries.
Yes, this means that if any given node has, say, five other nodes connected to it on the same gate vector, then there has to be five "parallel" connections inside that node, all leading to the gate vector of the submodule - in this case.
And there is no need for the allowunconnected specifier, nor the #loose property anywhere, in this case they do more harm by allowing "invalid" networks, than good. They are mostly useful for wireless simulations anyway.
Also, you should consider only scheduling a simple "timer" self-message (even if it's at T=0) in initialize(), and sending the "real" messages in the handleMessage() method when receiving said timer, this way the visualization of the graphical environments work better, and it is also arguably better design.

Related

Cut-through switching is not working when integrating with Time Aware Shaper (TAS) in INET4.0 showcases

Hello dear researchers:
I am trying to integrate three INET showcases: cut-through switching, Time Aware Shaper, gPTP.
The topology is simplpe as follows: Two senders, one clock, one switch, and one receiver. For simplicity, the gate is always open.
According to the sample code in combine features, I add the following codes to enable the cut-through switching.
#enable cut-through in all network nodes
*.*.hasCutthroughSwitching = true
*.switch.eth[*].typename = "LayeredEthernetInterface"
*.switch.eth[*].phyLayer.typename = "EthernetStreamingPhyLayer"
Currently, the simulation is working. However, the behavior from the animation is still like store and forward. The packets are not transmitted until the whole packets are inside the switch.
If we only enable the first line and comment the other two lines,
*.*.hasCutthroughSwitching = true
#*.switch.eth[*].typename = "LayeredEthernetInterface"
#*.switch.eth[*].phyLayer.typename = "EthernetStreamingPhyLayer"
then there is an error message showing :
Another packet streaming operation is already in progress -- in module (inet::physicallayer::EthernetPhyHeaderInserter) streamisolation.switch.eth[3].phyLayer.phyHeaderInserter (id=493), at t=0.000000226s, event #20
I would like to know how to fix this problem. Thank you.
My *.ini and *.ned files are below.
streamIsolation.ini
[General]
network = tsn_scalability.simulations.streamisolation
description = "stream isolation latency testing"
**.displayGateSchedules = true
**.gateFilter = "**.eth[1].**"#"**"#"**.eth[1].**"
**.gateScheduleVisualizer.height = 20
**.gateScheduleVisualizer.placementHint = "top"
# avoid ARP
#**.hasGlobalArp = true
#####################
# Clock Configuration
# use TSN clock
**.referenceClock = "tsnClock.clock"
*.tsnClock.clock.typename = "IdealClock"
*.tsnDevice.clock.typename = "OscillatorBasedClock"
*.switch.clock.typename = "OscillatorBasedClock"
*.server.clock.typename = "OscillatorBasedClock"
*.tsnClock.clock.oscillator.typename = "IdealOscillator"
*.tsnDevice.clock.oscillator.typename = "ConstantDriftOscillator"
*.switch.clock.oscillator.typename = "ConstantDriftOscillator"
*.server.clock.oscillator.typename = "ConstantDriftOscillator"
*.tsnDevice.clock.oscillator.driftRate = uniform(-100ppm, 100ppm)
*.switch.clock.oscillator.driftRate = uniform(-100ppm, 100ppm)
*.server.clock.oscillator.driftRate = uniform(-100ppm, 100ppm)
####################################
# Time Synchronization Configuration
# enable time synchronization in all network nodes
#*.*.hasTimeSynchronization = true
# time synchronization starts from the master clock
*.tsnClock.gptp.gptpNodeType = "MASTER_NODE"
*.tsnClock.gptp.masterPorts = ["eth0"]
*.switch.hasGptp = true
*.switch.gptp.gptpNodeType = "BRIDGE_NODE"
*.switch.gptp.masterPorts = ["eth1", "eth2"]
*.switch.gptp.syncInterval = 500us
*.switch.gptp.pdelayInterval = 1ms
*.switch.gptp.pdelayInitialOffset = 0ms
# application traffic sources use the local clock of the network node
*.*.app[*].source.clockModule = "^.^.clock"
# periodic gates in all traffic shapers use the local clock of the network node
*.*.eth[*].macLayer.queue.transmissionGate[*].clockModule = "^.^.^.^.clock"
# client application
*.tsnDevice.numApps = 1
*.tsnDevice.app[0].typename = "UdpSourceApp"
*.tsnDevice.app[0].io.destAddress = "server"
*.tsnDevice.app[0].io.destPort = 1000
*.tsnDevice.app[0].display-name = "tactile"
*.tsnDevice1.numApps = 1
*.tsnDevice1.app[0].typename = "UdpSourceApp"
*.tsnDevice1.app[0].io.destAddress = "server"
*.tsnDevice1.app[0].io.destPort = 1001
*.tsnDevice1.app[0].display-name = "besteff"
# server applications
*.server.numApps = 2
*.server.app[*].typename = "UdpSinkApp"
*.server.app[0].io.localPort = 1000
*.server.app[1].io.localPort = 1001
# enable outgoing streams
*.*.hasOutgoingStreams = true
# enable streams
# enable egress traffic shaping
*.switch.hasEgressTrafficShaping = true
# time-aware traffic shaping
*.switch.eth[*].macLayer.queue.numTrafficClasses = 2
*.switch.eth[*].macLayer.queue.queue[0].display-name = "q0"
*.switch.eth[*].macLayer.queue.queue[1].display-name = "q1"
# enable cut-through in all network nodes
*.*.hasCutthroughSwitching = true
*.switch.eth[*].typename = "LayeredEthernetInterface"
*.switch.eth[*].phyLayer.typename = "EthernetStreamingPhyLayer"
# client application
*.tsnDevice.app[0].source.packetLength = 1500B - 50B # 42B = 8B (UDP) + 20B (IP) + 14B (ETH MAC) + 4B (ETH FCS) + 8B (ETH PHY)
*.tsnDevice.app[0].source.productionInterval = 0.1ms
*.tsnDevice.bridging.streamIdentifier.identifier.mapping = [{stream: "tactile", packetFilter: expr(has(udp) && udp.destPort == 1000)}]
*.tsnDevice.bridging.streamCoder.encoder.mapping = [{stream: "tactile", pcp: 6}]
*.tsnDevice1.app[0].source.packetLength = 1500B - 50B # 42B = 8B (UDP) + 20B (IP) + 14B (ETH MAC) + 4B (ETH FCS) + 8B (ETH PHY)
*.tsnDevice1.app[0].source.productionInterval = 0.2ms
*.tsnDevice1.bridging.streamIdentifier.identifier.mapping = [{stream: "besteff", packetFilter: expr(has(udp) && udp.destPort == 1001)}]
*.tsnDevice1.bridging.streamCoder.encoder.mapping = [{stream: "besteff", pcp: 0}]
streamIsolation.ned
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.
//
package tsn_scalability.simulations;
import inet.networks.base.TsnNetworkBase;
import inet.node.contract.IEthernetNetworkNode;
import inet.node.ethernet.EthernetLink;
import inet.common.scenario.ScenarioManager;
import inet.networks.base.TsnNetworkBase;
import inet.node.ethernet.EthernetLink;
import inet.node.ethernet.EthernetSwitch;
import inet.node.tsn.TsnClock;
import inet.node.tsn.TsnDevice;
import inet.node.tsn.TsnSwitch;
import inet.node.inet.StandardHost;
//import inet.networklayer.configurator.ipv4.Ipv4NetworkConfigurator;
network streamisolation extends TsnNetworkBase
{
parameters:
*.eth[*].bitrate = default(1000Mbps);
submodules:
tsnClock: TsnClock {
#display("p=550,424");
}
tsnDevice: TsnDevice {
#display("p=350,200");
}
switch: TsnSwitch {
#display("p=550,200");
}
server: TsnDevice {
#display("p=750,200");
}
tsnDevice1: TsnDevice {
#display("p=350,300");
}
connections:
tsnClock.ethg++ <--> EthernetLink <--> switch.ethg++;
tsnDevice1.ethg++ <--> EthernetLink <--> switch.ethg++;
tsnDevice.ethg++ <--> EthernetLink <--> switch.ethg++;
switch.ethg++ <--> EthernetLink <--> server.ethg++;
}
This is a bug in the cut-through mechanism. The EthernetCuthroughSource modeul checks if the cut-through gate is ready to be pushed with a packet that is eligible for cut-through transmission. In your simulation two packets arrive at the switch from two different Ethernet interfaces at the same time. Both are eligible for cut-through transmission, but obviously only the first one should be transmitted using cut-through. For some reason the backpressure doesn't propagate back to the EthernetCuthroughtSource in the other incoming Ethernet interface from the outgoing interface PHY transmitter, so the other packet is also forwarded using cut-through, which is not possible and thus results in the above error.
Could you please create a bug in the github bug tracker, including your example?
This might be enough to activate cut-through switching:
*.*.hasCutthroughSwitching = true
The type of the Ethernet PHY and MAC is set automatically.

Graphviz - Connect cluster (subgraph) directly to a node

I want to connect a cluster edge to a node. Please find a simple Graphviz code below. Here is the online demo.
digraph G {
compound=true;
node1
subgraph cluster0 {
label="cluster"
node2;
}
node2 -> node1 [ltail="cluster0"]
}
It produces this output:
So, in the above method the cluster0 is connected to a node1. node2 is inside the cluster.
To connect the cluster itself to node we need compound=true and [ltail="cluster0"]. So we are just connecting node2 to node1 behind the scene and generating the edge from behind the cluster.
node2 -> node1 [ltail="cluster0"]
What I really want is to connect the cluster itself in the code like:
digraph G {
compound=true;
node1
subgraph cluster0 {
label="cluster"
node2;
}
cluster0 -> node1 [ltail="cluster0"]
}
But unfortunately, it produces this:
Well, the first one produces the image as desired but not the right approach. I'm working with State machines and generating the Graphviz code programmatically. Logically speaking, there is only one transition in the state digram:
cluster -> node1
But to do so we're trasitioning from node2 to node1 which is logically not right. I am curious that there is a way to achieve this and connect the cluster directly to a node instead of using a node inside the cluster.
Thanks in advance!
The ltail attribute is what is connecting it with the cluster edge.
(It seems like what you say is correct, that it's connecting the nodes on the back end but covering the edge when it gets to the cluster.)
Removing the ltail attribute should fix it:
digraph G {
compound=true;
node1
subgraph cluster0 {
label="cluster"
node2;
}
node2 -> node1
}

error while sending a message from aodvRouter to adhocHost using veins_inet

I'm using inet and veins_inet to simulate vanet. I wanted my nodes to use Aodv to route packets when a packet is sent from one node to another or from one node to rsu to achieve this I did the following :
I declared nodes as aodvRouters and set their mobility to VeinsInetMobility:
*.node[*].typename = "AodvRouter"
*.node[*].mobility.typename = "VeinsInetMobility"
and rsu as AdhocHost with stationary mobility
*.rsu.typename = "AdhocHost"
*.rsu.mobility.typename = "StationaryMobility":
when I use the following code to send a message from a node[43] to node[101] or other nodes it works :
bool nodeApp::startApplication(){
if (getParentModule()->getIndex() == 43) {
destAddress = L3AddressResolver().addressOf(getModuleByPath("node[101]"),27);
auto tipChunk = makeShared<tip>();
timestampPayload(tipChunk);
tipChunk->setChunkLength(B(100));
tipChunk->setPacket_type("tip");
auto packet = createPacket("tip");
packet->insertAtBack(tipChunk);
socket.sendTo(packet.release(), destAddress, 9001);
}
return true;
}
but when I change the dest address to the rsu address it doesn't work I get the following error :
A runtime error occurred:
handlePacket(): Unknown protocol: id = 55, name = nexthopforwarding -- in module (inet::MessageDispatcher) Network.node[34].tn (id=3241), at t=20.000076211898s, event #1103
to solve this error I added the following tag
auto req = packet->addTagIfAbsent<DispatchProtocolReq>();
req->setProtocol(&Protocol::udp);
auto packetProtocolTag = packet->addTagIfAbsent<PacketProtocolTag>();
packetProtocolTag->setProtocol(&Protocol::udp
but I have the followwing error
A runtime error occurred:
Implicit chunk serialization is disabled to prevent unpredictable performance degradation (you may consider changing the Chunk::enableImplicitChunkSerialization flag or passing the PF_ALLOW_SERIALIZATION flag to peek) -- in module (inet::Udp) Network.node[12].udp (id=1216), at t=2.000076936898s, event #378
can anyone help me to send a message from a node to the rsu without broadcasting the packet

Is there a way to sniff/listen an unicast packet/message on Omnet?

I am doing development for WSN in Omnet. I want to sniff a unicast message but I don't have an idea how can i do it in Omnet. I made some research but i couldn't found any method for that
When I send data to another node, I am sending it as an unicast with this method :
cModule *nodeIndex = flatTopolojiModulu->getSubmodule("n", i);//n is array
sendDirect(new cMessage("msg"), nodeIndex, "in");
I am using sendDirect method because I am working on wireless network. According to this description : https://stackoverflow.com/a/36082721/5736731
sendDirect method is usually the case in wireless networks.
But when send message with sendDirect, a message is being handled by receiver node. For example, according to code example above:
if i=2, message that is sent only can handle by node which has index "2" from
void AnyClassName::handleMessage(cMessage *msg) function
An example of broadcasting messages can be found in OMNeT++ Manual.
You should create only one instance of message that all nodes have to receive, and then send a new copy of this message to each node in loop. The dup() method has to be used to create the copy of a message.
cMessage * msg = new cMessage("msg");
// totalN is the total number of nodes
for (int i = 0; i < totalN; ++i) {
cModule *nodeIndex = flatTopolojiModulu->getSubmodule("n", i);
sendDirect(msg->dup(), nodeIndex, "in");
}
// original message is no longer needed
delete msg;

How to use DatarateChannel connection?

I hope you be fine As you see I have created this topology , every device has different .ned file . their input and output element I coded like this
inout gate[];
In Network.ned File i use below for connection
import ned.DatarateChannel;
But I got error when I use "C" instead of "DatarateChannel"
computer.gate++ <--> C <--> switch11.gate++;
So how can I handle it ???
Best regards
Probably you forgot to declare C channel. Add something like this in your ned file:
channel C extends ned.DatarateChannel {
// parameters of this channel, for example:
datarate = 1Mbps;
}
For available parameters of channel look at OMNeT++ Simulation Manual - Chapter 3.5

Resources