Table Of Contents
Table Of Contents

Using Different Traffic Shapers for Different Traffic Classes


In INET, it is possible to use different traffic shapers for different traffic classes in a TSN switch. In this showcase, we demonstrate using a Credit-Based Shaper (CBS) and an Asynchronous Traffic Shaper (ATS), together in the same switch.


You might be interested in looking at another showcase, in which multiple traffic shapers are combined in the same traffic stream: Combining Time-Aware and Credit-Based Shaping.

INET version: 4.4

The Model

In this demonstration, similarly to the Credit-Based Shaping and Asynchronous Traffic Shaping showcases, we employ a Ieee8021qTimeAwareShaper module with two traffic classes. However, unlike the previously mentioned two showcases, here one class is shaped using a CBS, and the other class is shaped by an ATS. Time-aware shaping is not enabled.

There are three network nodes in the network. The client and the server are TsnDevice modules, and the switch is a TsnSwitch module. The links between them use 100 Mbps EthernetLink channels. The client generates two traffic streams, and transmits them to the switch. In the switch, these streams undergo traffic shaping, and are transmitted to the server. In the results section, we plot the traffic in the switch before and after shapers, to see the effects of traffic shaping.


There are four applications in the network creating two independent data streams between the client and the server. The data rate of both streams are ~48 Mbps at the application level in the client.

# client applications
*.client.numApps = 2
*[*].typename = "UdpSourceApp"
*[0].display-name = "best effort"
*[1].display-name = "video"
*[*].io.destAddress = "server"
*[0].io.destPort = 1000
*[1].io.destPort = 1001
*[*].source.packetLength = 1000B# - 54B # 42B = 8B (UDP) + 20B (IP) + 14B (ETH MAC) + 4B (ETH FCS) + 8B (ETH PHY)
*[0].source.productionInterval = replaceUnit(sin(dropUnit(simTime() * 1)) + sin(dropUnit(simTime() * 8)) + 5, "ms") / 25	# ~40Mbps
*[1].source.productionInterval = replaceUnit(sin(dropUnit(simTime() * 2)) + 5, "ms") / 12.5					# ~20Mbps

# server applications
*.server.numApps = 2
*[*].typename = "UdpSinkApp"
*[0].display-name = "best effort"
*[1].display-name = "video"
*[0].io.localPort = 1000
*[1].io.localPort = 1001

The two streams have two different traffic classes: best effort and video. The bridging layer identifies the outgoing packets by their UDP destination port. The client encodes and the switch decodes the streams using the IEEE 802.1Q PCP field.

# enable outgoing streams
*.client.hasOutgoingStreams = true

# client stream identification
*.client.bridging.streamIdentifier.identifier.mapping = [{stream: "best effort", packetFilter: expr(udp.destPort == 1000)},
                                                         {stream: "video", packetFilter: expr(udp.destPort == 1001)}]

# client stream encoding
*.client.bridging.streamCoder.encoder.mapping = [{stream: "best effort", pcp: 0},
                                                 {stream: "video", pcp: 4}]

# disable forwarding IEEE 802.1Q C-Tag
*.switch.bridging.directionReverser.reverser.excludeEncapsulationProtocols = ["ieee8021qctag"]

# switch stream decoding
*.switch.bridging.streamCoder.decoder.mapping = [{pcp: 0, stream: "best effort"},
                                                 {pcp: 4, stream: "video"}]

The asynchronous traffic shaper requires the transmission eligibility time for each packet to be already calculated by the ingress per-stream filtering.

# enable ingress per-stream filtering
*.switch.hasIngressTrafficFiltering = true

# per-stream filtering for video stream
*.switch.bridging.streamFilter.ingress.numStreams = 1
*.switch.bridging.streamFilter.ingress.classifier.mapping = {video: 0}
*.switch.bridging.streamFilter.ingress.*[0].display-name = "video"
*.switch.bridging.streamFilter.ingress.meter[0].typename = "EligibilityTimeMeter"
*.switch.bridging.streamFilter.ingress.meter[0].committedInformationRate = 20.84Mbps	# shaper data rate
*.switch.bridging.streamFilter.ingress.meter[0].committedBurstSize = 10kB
*.switch.bridging.streamFilter.ingress.meter[0].packetOverheadLength = 18B				# 1046-1028 (14 MAC header + 4 FCS)
*.switch.bridging.streamFilter.ingress.filter[0].typename = "EligibilityTimeFilter"

The traffic shaping takes place in the outgoing network interface of the switch where both streams pass through. The traffic shaper limits the data rate of the best effort stream to 40 Mbps and the data rate of the video stream to 20 Mbps. The excess traffic is stored in the MAC layer subqueues of the corresponding traffic class.

# enable egress traffic shaping
*.switch.hasEgressTrafficShaping = true

# traffic classes
*.switch.eth[*].macLayer.queue.numTrafficClasses = 2

# credit-based traffic shaping
*.switch.eth[*].macLayer.queue.*[0].display-name = "best effort"
*.switch.eth[*].macLayer.queue.transmissionSelectionAlgorithm[0].typename = "Ieee8021qCreditBasedShaper"
*.switch.eth[*].macLayer.queue.transmissionSelectionAlgorithm[0].idleSlope = 42.64Mbps		# channel data rate

# asynchronous traffic shaping
*.switch.eth[*].macLayer.queue.*[1].display-name = "video"
*.switch.eth[*].macLayer.queue.queue[1].typename = "EligibilityTimeQueue"
*.switch.eth[*].macLayer.queue.transmissionSelectionAlgorithm[1].typename = "Ieee8021qAsynchronousShaper"


Let’s examine the traffic shaping process within the switch. The chart below illustrates the incoming and outgoing data rates within the base time-aware shaper module for the two traffic streams:


The CBS shapes the best effort traffic by restricting the data rate to a fixed value of 40 Mbps without any bursts. The ATS shapes the video stream by not only limiting the data rate to the desired nominal value but also allowing for bursts when the traffic exceeds the nominal rate.

Sources: omnetpp.ini


Use this page in the GitHub issue tracker for commenting on this showcase.