Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions WHATSNEW
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,22 @@ Notable backward incompatible changes are the following:
negotiation. The MacQosWithBlockAck example fingerprints are updated; the
QoS and NonQos showcase fingerprint controls remain unchanged.

17. A Random Early Detection queue with useEcn marks IPv6 packets

A RedDropper (Random Early Detection, RED) with useEcn = true set
Congestion Experienced (CE) on an Explicit Congestion Notification (ECN)
capable IPv4 packet above its threshold, but dropped an ECN-capable IPv6
packet in the same state. It now marks both. The cause was the
EcnMarker::getEcn() and EcnMarker::setEcn() helpers, which read and wrote
only the ECN field of an IPv4 header; they now also handle the ECN
field of the IPv6 Traffic Class, which RFC 3168 section 5 defines
identically. For the same reason, the EcnMarker module now applies an
EcnReq tag to IPv6 packets too.

This changes the results of simulations that send Explicit Congestion
Notification (ECN) capable IPv6 traffic through a RedDropper with
useEcn = true or through an EcnMarker. IPv4 traffic is unaffected.

Notable backward compatible changes are the following:

1. IEEE 802.11 per-station rate statistics
Expand Down
23 changes: 23 additions & 0 deletions src/inet/queueing/marker/EcnMarker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
#include "inet/networklayer/ipv4/Ipv4Header_m.h"
#endif // ifdef INET_WITH_IPv4

#ifdef INET_WITH_IPv6
#include "inet/networklayer/ipv6/Ipv6Header.h"
#endif // ifdef INET_WITH_IPv6

namespace inet {
namespace queueing {

Expand Down Expand Up @@ -67,6 +71,19 @@ void EcnMarker::setEcn(Packet *packet, IpEcnCode ecn)
packet->insertDataAt(ipv4Header, offset);
#else
throw cRuntimeError("IPv4 feature is disabled");
#endif
}
else if (protocol == &Protocol::ipv6) {
#ifdef INET_WITH_IPv6
packet->removeTagIfPresent<NetworkProtocolInd>();
auto ipv6Header = packet->removeDataAt<Ipv6Header>(offset);
ipv6Header->setEcn(ecn);
auto networkProtocolInd = packet->addTagIfAbsent<NetworkProtocolInd>();
networkProtocolInd->setProtocol(protocol);
networkProtocolInd->setNetworkProtocolHeader(ipv6Header);
packet->insertDataAt(ipv6Header, offset);
#else
throw cRuntimeError("IPv6 feature is disabled");
#endif
}
}
Expand All @@ -93,6 +110,12 @@ IpEcnCode EcnMarker::getEcn(const Packet *packet)
#ifdef INET_WITH_IPv4
auto ipv4Header = packet->peekDataAt<Ipv4Header>(offset);
return static_cast<IpEcnCode>(ipv4Header->getEcn());
#endif
}
else if (protocol == &Protocol::ipv6) {
#ifdef INET_WITH_IPv6
auto ipv6Header = packet->peekDataAt<Ipv6Header>(offset);
return static_cast<IpEcnCode>(ipv6Header->getEcn());
#endif
}
return IP_ECN_NOT_ECT;
Expand Down
4 changes: 2 additions & 2 deletions src/inet/queueing/marker/EcnMarker.ned
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ package inet.queueing.marker;
import inet.queueing.base.PacketMarkerBase;

//
// Sets Explicit Congestion Notification (ECN) bits in the IPv4 header based on the
// attached `EcnReq` tag on the packets.
// Sets Explicit Congestion Notification (ECN) bits in the IPv4 header or in the
// Traffic Class of the IPv6 header based on the attached `EcnReq` tag on the packets.
//
simple EcnMarker extends PacketMarkerBase
{
Expand Down
87 changes: 87 additions & 0 deletions tests/module/IPv6_red_ecn_marking.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
%description:
A Random Early Detection (RED) queue with useEcn marks an IPv6 packet that is
Explicit Congestion Notification (ECN) capable with Congestion Experienced (CE)
instead of dropping it (RFC 3168 section 5; the ECN field is the low two bits
of the IPv6 Traffic Class).

Topology: client --100Mbps-- router --10Mbps-- server. The RedDropperQueue on
the router's bottleneck interface has minth = 0, maxth = 1 and wq = 1, so a
packet that finds another packet waiting in the queue is above maxth. At 10 s,
after IPv6 address autoconfiguration, the client sends 5 User Datagram Protocol
(UDP) packets with the ECN codepoint ECT(0) (ECN-Capable Transport, traffic
class 2), faster than the bottleneck forwards them. Expected:
- UdpBasicAppData-2, -3 and -4, which arrive above maxth, reach the server
with traffic class 3 (CE);
- all 5 packets reach the server: RED drops none of them.

%#--------------------------------------------------------------------------------------------------------------
%file: test.ned

import inet.networklayer.configurator.ipv6.Ipv6FlatNetworkConfigurator;
import inet.node.ipv6.Router6;
import inet.node.ipv6.StandardHost6;
import ned.DatarateChannel;

network Ipv6RedEcnTestNetwork
{
submodules:
configurator: Ipv6FlatNetworkConfigurator;
client: StandardHost6;
router: Router6;
server: StandardHost6;
connections:
client.ethg++ <--> DatarateChannel { datarate = 100Mbps; delay = 0.1us; } <--> router.ethg++;
router.ethg++ <--> DatarateChannel { datarate = 10Mbps; delay = 0.1us; } <--> server.ethg++;
}

%#--------------------------------------------------------------------------------------------------------------
%inifile: omnetpp.ini

[General]
record-vector-results = false
network = Ipv6RedEcnTestNetwork
ned-path = .;../../../../src
sim-time-limit = 11s
cmdenv-express-mode = false
cmdenv-log-prefix = "%C: "

**.router.eth[1].queue.typename = "RedDropperQueue"
**.router.eth[1].queue.red.useEcn = true
**.router.eth[1].queue.red.minth = 0
**.router.eth[1].queue.red.maxth = 1
**.router.eth[1].queue.red.wq = 1
**.router.eth[1].queue.red.packetCapacity = 100

**.client.numApps = 1
**.client.app[0].typename = "UdpBasicApp"
**.client.app[0].destAddresses = "server"
**.client.app[0].destPort = 1000
**.client.app[0].messageLength = 1000B
**.client.app[0].sendInterval = 0.1ms
**.client.app[0].startTime = 10s
**.client.app[0].stopTime = 10.00049s
**.client.app[0].tos = 2

**.server.numApps = 1
**.server.app[0].typename = "UdpSink"
**.server.app[0].localPort = 1000

%#--------------------------------------------------------------------------------------------------------------
%subst: /omnetpp:://
%#--------------------------------------------------------------------------------------------------------------
%contains-regex: stdout
Ipv6RedEcnTestNetwork\.server\.app\[0\]: Received packet: \(inet::Packet\)UdpBasicAppData-2 .* TOS=3 DSCP
%#--------------------------------------------------------------------------------------------------------------
%contains-regex: stdout
Ipv6RedEcnTestNetwork\.server\.app\[0\]: Received packet: \(inet::Packet\)UdpBasicAppData-3 .* TOS=3 DSCP
%#--------------------------------------------------------------------------------------------------------------
%contains-regex: stdout
Ipv6RedEcnTestNetwork\.server\.app\[0\]: Received packet: \(inet::Packet\)UdpBasicAppData-4 .* TOS=3 DSCP
%#--------------------------------------------------------------------------------------------------------------
%contains: stdout
Ipv6RedEcnTestNetwork.server.app[0]: received 5 packets
%#--------------------------------------------------------------------------------------------------------------
%postrun-command: grep "undisposed object:" test.out > test_undisposed.out || true
%not-contains: test_undisposed.out
undisposed object: (
%#--------------------------------------------------------------------------------------------------------------
Loading