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?