├── .gitignore ├── .gitmodules ├── README.rst ├── examples ├── rmcat-example.cc └── wscript ├── model ├── apps │ ├── rmcat-constants.h │ ├── rmcat-receiver.cc │ ├── rmcat-receiver.h │ ├── rmcat-sender.cc │ ├── rmcat-sender.h │ ├── rtp-header.cc │ └── rtp-header.h ├── congestion-control │ ├── dummy-controller.cc │ ├── dummy-controller.h │ ├── nada-controller.cc │ ├── nada-controller.h │ ├── sender-based-controller.cc │ └── sender-based-controller.h └── topo │ ├── topo.cc │ ├── topo.h │ ├── wifi-topo.cc │ ├── wifi-topo.h │ ├── wired-topo.cc │ └── wired-topo.h ├── test ├── rmcat-common-test.cc ├── rmcat-common-test.h ├── rmcat-wifi-test-case.cc ├── rmcat-wifi-test-case.h ├── rmcat-wifi-test-suite.cc ├── rmcat-wired-test-case.cc ├── rmcat-wired-test-case.h ├── rmcat-wired-test-suite.cc └── rmcat-wired-varyparam-test-suite.cc ├── tools ├── plot_tests.py ├── process_test_logs.py ├── test.csh ├── test.py.diff └── test_v2.csh └── wscript /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cisco/ns3-rmcat/adb3f8e5c17829a61c29e6adb637a93212e21198/.gitignore -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "model/syncodecs"] 2 | path = model/syncodecs 3 | url = https://github.com/cisco/syncodecs.git 4 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. contents:: 2 | 3 | ns3-rmcat Documentation 4 | ---------------------------- 5 | 6 | .. heading hierarchy: 7 | ------------- Chapter 8 | ************* Section (#.#) 9 | ============= Subsection (#.#.#) 10 | ############# Paragraph (no number) 11 | 12 | ns3-rmcat is an `ns3 `_ module (Currently ns-3.26 is supported) used for `IETF RMCAT `_ candidate algorithm testing. 13 | 14 | It can be used in one of these ways: 15 | 16 | 1. As complementary tests for the unit test and integration test in emulator environment. 17 | 18 | 2. Algorithm tuning. It's easier to support different topologies using ns3, as ns3 provides sophisticated LTE and WiFi models, which make it easier to peek the internals than a real world system and emulator testbed. 19 | 20 | 3. Algorithm comparison. Simulation testbed is more reproducible than real world test and emulator testbed. The different candidate algorithms can be easily switched, thus making side-by-side comparison of different algorithms an easy and fair task. 21 | 22 | 23 | Model 24 | ***************** 25 | 26 | The model for real-time media congestion is documented at `"Framework for Real-time Media Congestion Avoidance Techniques" `_, and ns3-rmcat is a simplified implementation focussing on evaluation of real-time media congestion control algorithms in a simulation environment. 27 | 28 | ns3-rmcat defines ns3 applications (see `model/apps `_) running on different network topologies. These ns3 applications send fake video codec data (`model/syncodecs `_, more on `syncodecs `_), according to the congestion control algorithm under test. 29 | 30 | The sender application, ``RmcatSender``, sends fake video codec data in media packets to the receiver application, ``RmcatReceiver``. ``RmcatReceiver`` gets the sequence of packets and takes reception timestamp information, and sends it back to ``RmcatSender`` in feedback packets. The (sender-based) congestion control algorithm running on ``RmcatSender`` processes the feedback information (see `model/congestion-control `_), to get bandwidth estimation. The sender application then uses this bandwidth estimation to control the fake video encoder by adjusting its target video bitrate. 31 | 32 | Different topologies (see `model/topo `_) are currently supported, currently only point-to-point wired topology and WIFI topologies are used. We will add LTE support later. 33 | 34 | Testcases 35 | ***************** 36 | 37 | The test cases are in `test/rmcat-wired-test-suite `_ and `test/rmcat-wifi-test-suite `_; and currently organized in three test suites: 38 | 39 | - `rmcat-wifi `_ 40 | 41 | - `rmcat-wired `_ 42 | 43 | - rmcat-wired-vparam, which is based on some of the wired test cases, but varying other parameters such as bottleneck bandwidth, propagation delay, etc. 44 | 45 | `LTE `_ test case are not implemented yet. 46 | 47 | Examples 48 | ***************** 49 | 50 | `examples `_ is provided as an application template for experimenting new test cases and algorithm changes. 51 | 52 | Write your own congestion control algorithm 53 | *************************************************** 54 | 55 | You can create your own congestion control algorithm by inheriting from `SenderBasedController `_, `DummyController `_ is an example which just prints the packet loss, queuing delay and receive rate without doing any congestion control: the bandwidth estimation is hard-coded. 56 | 57 | To reuse the plotting tool, the following logs are expected to be written (see `NadaController `_, `process_test_logs.py `_): 58 | 59 | :: 60 | 61 | # rmcat flow 0, this is the flow id, SenderBasedController::m_id 62 | # ts, current timestamp when receving the rmcat feedback in millionseconds 63 | # loglen, packet history size, SenderBasedController::m_packetHistory.size() 64 | # qdel, queuing delay, SenderBasedController::getCurrentQdelay() 65 | # rtt, round trip time, SenderBasedController::getCurrentRTT() 66 | # ploss, packet loss count in last 500 ms, SenderBasedController::getPktLossInfo() 67 | # plr, packet loss ratio, SenderBasedController::getPktLossInfo() 68 | # xcurr, aggregated congestion signal that accounts for queuing delay, ECN 69 | # rrate, current receive rate in bps, SenderBasedController::getCurrentRecvRate() 70 | # srate, current estimated available bandwidth in bps 71 | # avgint, average inter-loss interval in packets, SenderBasedController::getLossIntervalInfo() 72 | # curint, most recent (currently growing) inter-loss interval in packets, SenderBasedController::getLossIntervalInfo() 73 | 74 | rmcat_0 ts: 158114 loglen: 60 qdel: 286 rtt: 386 ploss: 0 plr: 0.00 xcurr: 4.72 rrate: 863655.56 srate: 916165.81 avgint: 437.10 curint: 997 75 | 76 | 77 | Usage 78 | ***************** 79 | 80 | 1. Download ns3 (ns-3.26 is currently supported, other version may also work but are untested). 81 | 82 | 2. Git clone ns3-rmcat into ``ns-3.xx/src``. Initialize syncodecs submodule (``git submodule update --init --recursive``) 83 | 84 | 3. configure the workspace, ``CXXFLAGS="-std=c++11 -Wall -Werror -Wno-potentially-evaluated-expression -Wno-unused-local-typedefs" ./waf configure --enable-examples --enable-tests``. 85 | 86 | 4. build, ``./waf build`` 87 | 88 | 5. run tests, ``./test.py -s rmcat-wired -w rmcat.html -r``, where ``rmcat.html`` is the test report. 89 | 90 | 7. [optional] run examples, ``./waf --run "rmcat-example --log"``, ``--log`` will turn on RmcatSender/RmcatReceiver logs for debugging. 91 | 92 | 8. draw the plots (need to install the python module `matplotlib `_), ``python src/ns3-rmcat/tools/process_test_logs.py testpy-output/2017-08-11-18-52-15-CUT; python src/ns3-rmcat/tools/plot_tests.py testpy-output/2017-08-11-18-52-15-CUT`` 93 | 94 | You can also use `test.csh `_ to run the testcases and the plot scripts in one shot. If you do so, logs with testcase names will be located in the "testpy-output/[CURRENT UTC TIME]" directory, if none specified. 95 | 96 | :: 97 | 98 | # run from ns3 root directory: ns-3.xx/ 99 | # 100 | # Example: 101 | # ./src/ns3-rmcat/tools/test.csh wired 2017-07-21-rmcat-wired 102 | # ./src/ns3-rmcat/tools/test.csh vparam 2017-07-21-rmcat-wired-vparam 103 | # ./src/ns3-rmcat/tools/test.csh wifi 2017-07-21-rmcat-wifi 104 | # 105 | # The second parameter, output directory, is optional. If not specified, 106 | # the script will use a folder with a name based on current GMT time 107 | 108 | 109 | Note that in ns-3.26, the testing script (test.py) only works with python2. So one may want to point the python alias to python to ensure that the `test.csh` script runs out of box: 110 | 111 | :: 112 | alias python=python2.7.3 113 | :: 114 | 115 | Alternatively, you can use `test_v2.csh `_ to explicitly invoke python2 for running the testing script and python3 for running the processing and plotting scripts. The latter works with both python2 and python3. 116 | 117 | 118 | Troubleshooting 119 | ***************** 120 | 121 | To build ns-3.26 on newer compilers: see tips `here `_. To disable warnings from breaking your build, do the following: 122 | :: 123 | 124 | CXXFLAGS="-Wall" ./waf configure 125 | ./waf -vv 126 | :: 127 | 128 | 129 | 130 | To debug "rmcat-wired" test suite: 131 | 132 | :: 133 | 134 | ./waf --command-template="gdb %s" --run "test-runner" 135 | r --assert-on-failure --suite=rmcat-wired 136 | 137 | To debug rmcat example, enter ns3 source directory: 138 | 139 | :: 140 | 141 | ./waf --command-template="gdb %s" --run src/ns3-rmcat/examples/rmcat-example 142 | 143 | Future work 144 | ********************************** 145 | 146 | Adding LTE topology and test cases 147 | 148 | Add support for ECN marking 149 | 150 | Encapsulate Sender's rate shaping buffer in a C++ interface or class 151 | 152 | Wired test cases: implement time-varying bottleneck capacity by changing the physical link properties 153 | -------------------------------------------------------------------------------- /examples/rmcat-example.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * You may obtain a copy of the License at * 7 | * * 8 | * http://www.apache.org/licenses/LICENSE-2.0 * 9 | * * 10 | * Unless required by applicable law or agreed to in writing, software * 11 | * distributed under the License is distributed on an "AS IS" BASIS, * 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 13 | * See the License for the specific language governing permissions and * 14 | * limitations under the License. * 15 | ******************************************************************************/ 16 | 17 | /** 18 | * @file 19 | * Simple example demonstrating the usage of the rmcat ns3 module, using: 20 | * - NADA as controller for rmcat flows 21 | * - Statistics-based traffic source as codec 22 | * - [Optionally] TCP flows 23 | * - [Optionally] UDP flows 24 | * 25 | * @version 0.1.1 26 | * @author Jiantao Fu 27 | * @author Sergio Mena 28 | * @author Xiaoqing Zhu 29 | */ 30 | 31 | #include "ns3/nada-controller.h" 32 | #include "ns3/rmcat-sender.h" 33 | #include "ns3/rmcat-receiver.h" 34 | #include "ns3/rmcat-constants.h" 35 | #include "ns3/point-to-point-helper.h" 36 | #include "ns3/data-rate.h" 37 | #include "ns3/bulk-send-helper.h" 38 | #include "ns3/packet-sink-helper.h" 39 | #include "ns3/udp-client-server-helper.h" 40 | #include "ns3/internet-stack-helper.h" 41 | #include "ns3/traffic-control-helper.h" 42 | #include "ns3/ipv4-address-helper.h" 43 | #include "ns3/core-module.h" 44 | 45 | const uint32_t RMCAT_DEFAULT_RMIN = 150000; // in bps: 150Kbps 46 | const uint32_t RMCAT_DEFAULT_RMAX = 1500000; // in bps: 1.5Mbps 47 | const uint32_t RMCAT_DEFAULT_RINIT = 150000; // in bps: 150Kbps 48 | 49 | const uint32_t TOPO_DEFAULT_BW = 1000000; // in bps: 1Mbps 50 | const uint32_t TOPO_DEFAULT_PDELAY = 50; // in ms: 50ms 51 | const uint32_t TOPO_DEFAULT_QDELAY = 300; // in ms: 300ms 52 | 53 | using namespace ns3; 54 | 55 | static NodeContainer BuildExampleTopo (uint64_t bps, 56 | uint32_t msDelay, 57 | uint32_t msQdelay) 58 | { 59 | NodeContainer nodes; 60 | nodes.Create (2); 61 | 62 | PointToPointHelper pointToPoint; 63 | pointToPoint.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (bps))); 64 | pointToPoint.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (msDelay))); 65 | auto bufSize = std::max (DEFAULT_PACKET_SIZE, bps * msQdelay / 8000); 66 | pointToPoint.SetQueue ("ns3::DropTailQueue", 67 | "Mode", StringValue ("QUEUE_MODE_BYTES"), 68 | "MaxBytes", UintegerValue (bufSize)); 69 | NetDeviceContainer devices = pointToPoint.Install (nodes); 70 | 71 | InternetStackHelper stack; 72 | stack.Install (nodes); 73 | Ipv4AddressHelper address; 74 | address.SetBase ("10.1.1.0", "255.255.255.0"); 75 | address.Assign (devices); 76 | 77 | // Uncomment to capture simulated traffic 78 | // pointToPoint.EnablePcapAll ("rmcat-example"); 79 | 80 | // disable tc for now, some bug in ns3 causes extra delay 81 | TrafficControlHelper tch; 82 | tch.Uninstall (devices); 83 | 84 | return nodes; 85 | } 86 | 87 | static void InstallTCP (Ptr sender, 88 | Ptr receiver, 89 | uint16_t port, 90 | float startTime, 91 | float stopTime) 92 | { 93 | // configure TCP source/sender/client 94 | auto serverAddr = receiver->GetObject ()->GetAddress (1,0).GetLocal (); 95 | BulkSendHelper source{"ns3::TcpSocketFactory", 96 | InetSocketAddress{serverAddr, port}}; 97 | // Set the amount of data to send in bytes. Zero is unlimited. 98 | source.SetAttribute ("MaxBytes", UintegerValue (0)); 99 | source.SetAttribute ("SendSize", UintegerValue (DEFAULT_PACKET_SIZE)); 100 | 101 | auto clientApps = source.Install (sender); 102 | clientApps.Start (Seconds (startTime)); 103 | clientApps.Stop (Seconds (stopTime)); 104 | 105 | // configure TCP sink/receiver/server 106 | PacketSinkHelper sink{"ns3::TcpSocketFactory", 107 | InetSocketAddress{Ipv4Address::GetAny (), port}}; 108 | auto serverApps = sink.Install (receiver); 109 | serverApps.Start (Seconds (startTime)); 110 | serverApps.Stop (Seconds (stopTime)); 111 | 112 | } 113 | 114 | static Time GetIntervalFromBitrate (uint64_t bitrate, uint32_t packetSize) 115 | { 116 | if (bitrate == 0u) { 117 | return Time::Max (); 118 | } 119 | const auto secs = static_cast (packetSize + IPV4_UDP_OVERHEAD) / 120 | (static_cast (bitrate) / 8. ); 121 | return Seconds (secs); 122 | } 123 | 124 | static void InstallUDP (Ptr sender, 125 | Ptr receiver, 126 | uint16_t serverPort, 127 | uint64_t bitrate, 128 | uint32_t packetSize, 129 | uint32_t startTime, 130 | uint32_t stopTime) 131 | { 132 | // configure UDP source/sender/client 133 | auto serverAddr = receiver->GetObject ()->GetAddress (1,0).GetLocal (); 134 | const auto interPacketInterval = GetIntervalFromBitrate (bitrate, packetSize); 135 | uint32_t maxPacketCount = 0XFFFFFFFF; 136 | UdpClientHelper client{serverAddr, serverPort}; 137 | client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); 138 | client.SetAttribute ("Interval", TimeValue (interPacketInterval)); 139 | client.SetAttribute ("PacketSize", UintegerValue (packetSize)); 140 | 141 | auto clientApps = client.Install (sender); 142 | clientApps.Start (Seconds (startTime)); 143 | clientApps.Stop (Seconds (stopTime)); 144 | 145 | // configure TCP sink/receiver/server 146 | UdpServerHelper server{serverPort}; 147 | auto serverApps = server.Install (receiver); 148 | serverApps.Start (Seconds (startTime)); 149 | serverApps.Stop (Seconds (stopTime)); 150 | } 151 | 152 | static void InstallApps (bool nada, 153 | Ptr sender, 154 | Ptr receiver, 155 | uint16_t port, 156 | float initBw, 157 | float minBw, 158 | float maxBw, 159 | float startTime, 160 | float stopTime) 161 | { 162 | Ptr sendApp = CreateObject (); 163 | Ptr recvApp = CreateObject (); 164 | sender->AddApplication (sendApp); 165 | receiver->AddApplication (recvApp); 166 | 167 | if (nada) { 168 | sendApp->SetController (std::make_shared ()); 169 | } 170 | Ptr ipv4 = receiver->GetObject (); 171 | Ipv4Address receiverIp = ipv4->GetAddress (1, 0).GetLocal (); 172 | sendApp->Setup (receiverIp, port); // initBw, minBw, maxBw); 173 | 174 | const auto fps = 25.; 175 | auto innerCodec = new syncodecs::StatisticsCodec{fps}; 176 | auto codec = new syncodecs::ShapedPacketizer{innerCodec, DEFAULT_PACKET_SIZE}; 177 | sendApp->SetCodec (std::shared_ptr{codec}); 178 | 179 | recvApp->Setup (port); 180 | 181 | sendApp->SetStartTime (Seconds (startTime)); 182 | sendApp->SetStopTime (Seconds (stopTime)); 183 | 184 | recvApp->SetStartTime (Seconds (startTime)); 185 | recvApp->SetStopTime (Seconds (stopTime)); 186 | } 187 | 188 | int main (int argc, char *argv[]) 189 | { 190 | int nRmcat = 1; 191 | int nTcp = 0; 192 | int nUdp = 0; 193 | bool log = false; 194 | bool nada = true; 195 | std::string strArg = "strArg default"; 196 | 197 | CommandLine cmd; 198 | cmd.AddValue ("rmcat", "Number of RMCAT (NADA) flows", nRmcat); 199 | cmd.AddValue ("tcp", "Number of TCP flows", nTcp); 200 | cmd.AddValue ("udp", "Number of UDP flows", nUdp); 201 | cmd.AddValue ("log", "Turn on logs", log); 202 | cmd.AddValue ("nada", "true: use NADA, false: use dummy", nada); 203 | cmd.Parse (argc, argv); 204 | 205 | if (log) { 206 | LogComponentEnable ("RmcatSender", LOG_INFO); 207 | LogComponentEnable ("RmcatReceiver", LOG_INFO); 208 | LogComponentEnable ("Packet", LOG_FUNCTION); 209 | } 210 | 211 | // configure default TCP parameters 212 | Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (0)); 213 | Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue ("ns3::TcpNewReno")); 214 | Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1000)); 215 | 216 | const uint64_t linkBw = TOPO_DEFAULT_BW; 217 | const uint32_t msDelay = TOPO_DEFAULT_PDELAY; 218 | const uint32_t msQDelay = TOPO_DEFAULT_QDELAY; 219 | 220 | const float minBw = RMCAT_DEFAULT_RMIN; 221 | const float maxBw = RMCAT_DEFAULT_RMAX; 222 | const float initBw = RMCAT_DEFAULT_RINIT; 223 | 224 | const float endTime = 300.; 225 | 226 | NodeContainer nodes = BuildExampleTopo (linkBw, msDelay, msQDelay); 227 | 228 | int port = 8000; 229 | nRmcat = std::max (0, nRmcat); // No negative RMCAT flows 230 | for (size_t i = 0; i < (unsigned int) nRmcat; ++i) { 231 | auto start = 10. * i; 232 | auto end = std::max (start + 1., endTime - start); 233 | InstallApps (nada, nodes.Get (0), nodes.Get (1), port++, 234 | initBw, minBw, maxBw, start, end); 235 | } 236 | 237 | nTcp = std::max (0, nTcp); // No negative TCP flows 238 | for (size_t i = 0; i < (unsigned int) nTcp; ++i) { 239 | auto start = 17. * i; 240 | auto end = std::max (start + 1., endTime - start); 241 | InstallTCP (nodes.Get (0), nodes.Get (1), port++, start, end); 242 | } 243 | 244 | // UDP parameters 245 | const uint64_t bandwidth = RMCAT_DEFAULT_RMAX / 4; 246 | const uint32_t pktSize = DEFAULT_PACKET_SIZE; 247 | 248 | nUdp = std::max (0, nUdp); // No negative UDP flows 249 | for (size_t i = 0; i < (unsigned int) nUdp; ++i) { 250 | auto start = 23. * i; 251 | auto end = std::max (start + 1., endTime - start); 252 | InstallUDP (nodes.Get (0), nodes.Get (1), port++, 253 | bandwidth, pktSize, start, end); 254 | } 255 | 256 | std::cout << "Running Simulation..." << std::endl; 257 | Simulator::Stop (Seconds (endTime)); 258 | Simulator::Run (); 259 | Simulator::Destroy (); 260 | std::cout << "Done" << std::endl; 261 | 262 | return 0; 263 | } 264 | -------------------------------------------------------------------------------- /examples/wscript: -------------------------------------------------------------------------------- 1 | # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- 2 | 3 | ############################################################################### 4 | # Copyright 2016-2017 Cisco Systems, Inc. # 5 | # # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); # 7 | # you may not use this file except in compliance with the License. # 8 | # # 9 | # You may obtain a copy of the License at # 10 | # # 11 | # http://www.apache.org/licenses/LICENSE-2.0 # 12 | # # 13 | # Unless required by applicable law or agreed to in writing, software # 14 | # distributed under the License is distributed on an "AS IS" BASIS, # 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 16 | # See the License for the specific language governing permissions and # 17 | # limitations under the License. # 18 | ############################################################################### 19 | 20 | def build(bld): 21 | obj = bld.create_ns3_program('rmcat-example', ['ns3-rmcat']) 22 | obj.source = 'rmcat-example.cc', 23 | -------------------------------------------------------------------------------- /model/apps/rmcat-constants.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Global constants for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | 29 | #ifndef RMCAT_CONSTANTS_H 30 | #define RMCAT_CONSTANTS_H 31 | 32 | #include 33 | 34 | const uint32_t DEFAULT_PACKET_SIZE = 1000; 35 | const uint32_t IPV4_HEADER_SIZE = 20; 36 | const uint32_t UDP_HEADER_SIZE = 8; 37 | const uint32_t IPV4_UDP_OVERHEAD = IPV4_HEADER_SIZE + UDP_HEADER_SIZE; 38 | const uint64_t RMCAT_FEEDBACK_PERIOD_US = 100 * 1000; 39 | 40 | // syncodec parameters 41 | const uint32_t SYNCODEC_DEFAULT_FPS = 30; 42 | enum SyncodecType { 43 | SYNCODEC_TYPE_PERFECT = 0, 44 | SYNCODEC_TYPE_FIXFPS, 45 | SYNCODEC_TYPE_STATS, 46 | SYNCODEC_TYPE_TRACE, 47 | SYNCODEC_TYPE_SHARING, 48 | SYNCODEC_TYPE_HYBRID 49 | }; 50 | 51 | /** 52 | * Parameters for the rate shaping buffer as specified in draft-ietf-rmcat-nada 53 | * These are the default values according to the draft 54 | * The rate shaping buffer is currently implemented in the sender ns3 55 | * application (#ns3::RmcatSender ). For other congestion controllers 56 | * that do not need the rate shaping buffer, you can disable it by 57 | * setting USE_BUFFER to false. 58 | */ 59 | const bool USE_BUFFER = true; 60 | const float BETA_V = 0.0; 61 | const float BETA_S = 0.0; 62 | const uint32_t MAX_QUEUE_SIZE_SANITY = 80 * 1000 * 1000; //bytes 63 | 64 | /* topology parameters */ 65 | const uint32_t T_MAX_S = 500; // maximum simulation duration in seconds 66 | const double T_TCP_LOG = 2; // sample interval for log TCP flows 67 | 68 | /* Default topology setting parameters */ 69 | const uint32_t WIFI_TOPO_MACQUEUE_MAXNPKTS = 1000; 70 | const uint32_t WIFI_TOPO_ARPCACHE_ALIVE_TIMEOUT = 24 * 60 * 60; // 24 hours 71 | const float WIFI_TOPO_2_4GHZ_PATHLOSS_EXPONENT = 3.0f; 72 | const float WIFI_TOPO_2_4GHZ_PATHLOSS_REFLOSS = 40.0459f; 73 | const uint32_t WIFI_TOPO_CHANNEL_WIDTH = 20; // default channel width: 20MHz 74 | 75 | #endif /* RMCAT_CONSTANTS_H */ 76 | -------------------------------------------------------------------------------- /model/apps/rmcat-receiver.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Receiver application implementation for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #include "rmcat-receiver.h" 29 | #include "rmcat-constants.h" 30 | #include "ns3/udp-socket-factory.h" 31 | #include "ns3/packet.h" 32 | #include "ns3/simulator.h" 33 | #include "ns3/log.h" 34 | 35 | NS_LOG_COMPONENT_DEFINE ("RmcatReceiver"); 36 | 37 | namespace ns3 { 38 | RmcatReceiver::RmcatReceiver () 39 | : m_running{false} 40 | , m_waiting{false} 41 | , m_ssrc{0} 42 | , m_remoteSsrc{0} 43 | , m_srcIp{} 44 | , m_srcPort{} 45 | , m_socket{NULL} 46 | , m_header{} 47 | , m_sendEvent{} 48 | , m_periodUs{RMCAT_FEEDBACK_PERIOD_US} 49 | {} 50 | 51 | RmcatReceiver::~RmcatReceiver () {} 52 | 53 | void RmcatReceiver::Setup (uint16_t port) 54 | { 55 | m_socket = Socket::CreateSocket (GetNode (), UdpSocketFactory::GetTypeId ()); 56 | auto local = InetSocketAddress{Ipv4Address::GetAny (), port}; 57 | auto ret = m_socket->Bind (local); 58 | NS_ASSERT (ret == 0); 59 | m_socket->SetRecvCallback (MakeCallback (&RmcatReceiver::RecvPacket, this)); 60 | 61 | m_running = false; 62 | m_waiting = true; 63 | } 64 | 65 | void RmcatReceiver::StartApplication () 66 | { 67 | m_running = true; 68 | m_ssrc = rand (); 69 | m_header.SetSendSsrc (m_ssrc); 70 | Time tFirst {MicroSeconds (m_periodUs)}; 71 | m_sendEvent = Simulator::Schedule (tFirst, &RmcatReceiver::SendFeedback, this, true); 72 | } 73 | 74 | void RmcatReceiver::StopApplication () 75 | { 76 | m_running = false; 77 | m_waiting = true; 78 | m_header.Clear (); 79 | Simulator::Cancel (m_sendEvent); 80 | } 81 | 82 | void RmcatReceiver::RecvPacket (Ptr socket) 83 | { 84 | if (!m_running) { 85 | return; 86 | } 87 | 88 | Address remoteAddr{}; 89 | auto packet = m_socket->RecvFrom (remoteAddr); 90 | NS_ASSERT (packet); 91 | RtpHeader header{}; 92 | NS_LOG_INFO ("RmcatReceiver::RecvPacket, " << packet->ToString ()); 93 | packet->RemoveHeader (header); 94 | auto srcIp = InetSocketAddress::ConvertFrom (remoteAddr).GetIpv4 (); 95 | const auto srcPort = InetSocketAddress::ConvertFrom (remoteAddr).GetPort (); 96 | if (m_waiting) { 97 | m_waiting = false; 98 | m_remoteSsrc = header.GetSsrc (); 99 | m_srcIp = srcIp; 100 | m_srcPort = srcPort; 101 | } else { 102 | // Only one flow supported 103 | NS_ASSERT (m_remoteSsrc == header.GetSsrc ()); 104 | NS_ASSERT (m_srcIp == srcIp); 105 | NS_ASSERT (m_srcPort == srcPort); 106 | } 107 | 108 | uint64_t recvTimestampUs = Simulator::Now ().GetMicroSeconds (); 109 | AddFeedback (header.GetSequence (), recvTimestampUs); 110 | } 111 | 112 | void RmcatReceiver::AddFeedback (uint16_t sequence, 113 | uint64_t recvTimestampUs) 114 | { 115 | auto res = m_header.AddFeedback (m_remoteSsrc, sequence, recvTimestampUs); 116 | if (res == CCFeedbackHeader::CCFB_TOO_LONG) { 117 | SendFeedback (false); 118 | res = m_header.AddFeedback (m_remoteSsrc, sequence, recvTimestampUs); 119 | } 120 | NS_ASSERT (res == CCFeedbackHeader::CCFB_NONE); 121 | } 122 | 123 | void RmcatReceiver::SendFeedback (bool reschedule) 124 | { 125 | if (m_running && !m_header.Empty ()) { 126 | //TODO (authors): If packet empty, easiest is to send it as is. Propose to authors 127 | auto packet = Create (); 128 | packet->AddHeader (m_header); 129 | NS_LOG_INFO ("RmcatReceiver::SendFeedback, " << packet->ToString ()); 130 | m_socket->SendTo (packet, 0, InetSocketAddress{m_srcIp, m_srcPort}); 131 | 132 | m_header.Clear (); 133 | m_header.SetSendSsrc (m_ssrc); 134 | } 135 | 136 | if (reschedule) { 137 | Time tNext {MicroSeconds (m_periodUs)}; 138 | m_sendEvent = Simulator::Schedule (tNext, &RmcatReceiver::SendFeedback, this, true); 139 | } 140 | } 141 | 142 | } 143 | 144 | -------------------------------------------------------------------------------- /model/apps/rmcat-receiver.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Receiver application interface for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #ifndef RMCAT_RECEIVER_H 29 | #define RMCAT_RECEIVER_H 30 | 31 | #include "rtp-header.h" 32 | #include "ns3/socket.h" 33 | #include "ns3/application.h" 34 | 35 | namespace ns3 { 36 | 37 | class RmcatReceiver: public Application 38 | { 39 | public: 40 | RmcatReceiver (); 41 | virtual ~RmcatReceiver (); 42 | 43 | void Setup (uint16_t port); 44 | 45 | private: 46 | virtual void StartApplication (); 47 | virtual void StopApplication (); 48 | 49 | void RecvPacket (Ptr socket); 50 | void AddFeedback (uint16_t sequence, 51 | uint64_t recvTimestampUs); 52 | void SendFeedback (bool reschedule); 53 | 54 | private: 55 | bool m_running; 56 | bool m_waiting; 57 | uint32_t m_ssrc; 58 | uint32_t m_remoteSsrc; 59 | Ipv4Address m_srcIp; 60 | uint16_t m_srcPort; 61 | Ptr m_socket; 62 | CCFeedbackHeader m_header; 63 | EventId m_sendEvent; 64 | uint64_t m_periodUs; 65 | }; 66 | 67 | } 68 | 69 | #endif /* RMCAT_RECEIVER_H */ 70 | -------------------------------------------------------------------------------- /model/apps/rmcat-sender.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Sender application implementation for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #include "rmcat-sender.h" 29 | #include "rtp-header.h" 30 | #include "ns3/dummy-controller.h" 31 | #include "ns3/nada-controller.h" 32 | #include "ns3/udp-socket-factory.h" 33 | #include "ns3/packet.h" 34 | #include "ns3/simulator.h" 35 | #include "ns3/uinteger.h" 36 | #include "ns3/log.h" 37 | 38 | #include 39 | 40 | NS_LOG_COMPONENT_DEFINE ("RmcatSender"); 41 | 42 | namespace ns3 { 43 | 44 | RmcatSender::RmcatSender () 45 | : m_destIP{} 46 | , m_destPort{0} 47 | , m_initBw{0} 48 | , m_minBw{0} 49 | , m_maxBw{0} 50 | , m_paused{false} 51 | , m_ssrc{0} 52 | , m_sequence{0} 53 | , m_rtpTsOffset{0} 54 | , m_socket{NULL} 55 | , m_enqueueEvent{} 56 | , m_sendEvent{} 57 | , m_sendOversleepEvent{} 58 | , m_fps{30.} 59 | , m_rVin{0.} 60 | , m_rSend{0.} 61 | , m_rateShapingBytes{0} 62 | , m_nextSendTstmpUs{0} 63 | {} 64 | 65 | RmcatSender::~RmcatSender () {} 66 | 67 | void RmcatSender::PauseResume (bool pause) 68 | { 69 | NS_ASSERT (pause != m_paused); 70 | if (pause) { 71 | Simulator::Cancel (m_enqueueEvent); 72 | Simulator::Cancel (m_sendEvent); 73 | Simulator::Cancel (m_sendOversleepEvent); 74 | m_rateShapingBuf.clear (); 75 | m_rateShapingBytes = 0; 76 | } else { 77 | m_rVin = m_initBw; 78 | m_rSend = m_initBw; 79 | m_enqueueEvent = Simulator::ScheduleNow (&RmcatSender::EnqueuePacket, this); 80 | m_nextSendTstmpUs = 0; 81 | } 82 | m_paused = pause; 83 | } 84 | 85 | void RmcatSender::SetCodec (std::shared_ptr codec) 86 | { 87 | m_codec = codec; 88 | } 89 | 90 | // TODO (deferred): allow flexible input of video traffic trace path via config file, etc. 91 | void RmcatSender::SetCodecType (SyncodecType codecType) 92 | { 93 | syncodecs::Codec* codec = NULL; 94 | switch (codecType) { 95 | case SYNCODEC_TYPE_PERFECT: 96 | { 97 | codec = new syncodecs::PerfectCodec{DEFAULT_PACKET_SIZE}; 98 | break; 99 | } 100 | case SYNCODEC_TYPE_FIXFPS: 101 | { 102 | m_fps = SYNCODEC_DEFAULT_FPS; 103 | auto innerCodec = new syncodecs::SimpleFpsBasedCodec{m_fps}; 104 | codec = new syncodecs::ShapedPacketizer{innerCodec, DEFAULT_PACKET_SIZE}; 105 | break; 106 | } 107 | case SYNCODEC_TYPE_STATS: 108 | { 109 | m_fps = SYNCODEC_DEFAULT_FPS; 110 | auto innerStCodec = new syncodecs::StatisticsCodec{m_fps}; 111 | codec = new syncodecs::ShapedPacketizer{innerStCodec, DEFAULT_PACKET_SIZE}; 112 | break; 113 | } 114 | case SYNCODEC_TYPE_TRACE: 115 | case SYNCODEC_TYPE_HYBRID: 116 | { 117 | const std::vector candidatePaths = { 118 | ".", // If run from top directory (e.g., with gdb), from ns-3.26/ 119 | "../", // If run from with test_new.py with designated directory, from ns-3.26/2017-xyz/ 120 | "../..", // If run with test.py, from ns-3.26/testpy-output/201... 121 | }; 122 | 123 | const std::string traceSubDir{"src/ns3-rmcat/model/syncodecs/video_traces/chat_firefox_h264"}; 124 | std::string traceDir{}; 125 | 126 | for (auto c : candidatePaths) { 127 | std::ostringstream currPathOss; 128 | currPathOss << c << "/" << traceSubDir; 129 | struct stat buffer; 130 | if (::stat (currPathOss.str ().c_str (), &buffer) == 0) { 131 | //filename exists 132 | traceDir = currPathOss.str (); 133 | break; 134 | } 135 | } 136 | 137 | NS_ASSERT_MSG (!traceDir.empty (), "Traces file not found in candidate paths"); 138 | 139 | auto filePrefix = "chat"; 140 | auto innerCodec = (codecType == SYNCODEC_TYPE_TRACE) ? 141 | new syncodecs::TraceBasedCodecWithScaling{ 142 | traceDir, // path to traces directory 143 | filePrefix, // video filename 144 | SYNCODEC_DEFAULT_FPS, // Default FPS: 30fps 145 | true} : // fixed mode: image resolution doesn't change 146 | new syncodecs::HybridCodec{ 147 | traceDir, // path to traces directory 148 | filePrefix, // video filename 149 | SYNCODEC_DEFAULT_FPS, // Default FPS: 30fps 150 | true}; // fixed mode: image resolution doesn't change 151 | m_fps = SYNCODEC_DEFAULT_FPS; 152 | codec = new syncodecs::ShapedPacketizer{innerCodec, DEFAULT_PACKET_SIZE}; 153 | break; 154 | } 155 | case SYNCODEC_TYPE_SHARING: 156 | { 157 | auto innerShCodec = new syncodecs::SimpleContentSharingCodec{}; 158 | codec = new syncodecs::ShapedPacketizer{innerShCodec, DEFAULT_PACKET_SIZE}; 159 | break; 160 | } 161 | default: // defaults to perfect codec 162 | codec = new syncodecs::PerfectCodec{DEFAULT_PACKET_SIZE}; 163 | } 164 | 165 | // update member variable 166 | m_codec = std::shared_ptr{codec}; 167 | } 168 | 169 | void RmcatSender::SetController (std::shared_ptr controller) 170 | { 171 | m_controller = controller; 172 | } 173 | 174 | void RmcatSender::Setup (Ipv4Address destIP, 175 | uint16_t destPort) 176 | { 177 | if (!m_codec) { 178 | m_codec = std::make_shared (DEFAULT_PACKET_SIZE); 179 | } 180 | 181 | if (!m_controller) { 182 | m_controller = std::make_shared (); 183 | } else { 184 | m_controller->reset (); 185 | } 186 | 187 | m_destIP = destIP; 188 | m_destPort = destPort; 189 | } 190 | 191 | void RmcatSender::SetRinit (float r) 192 | { 193 | m_initBw = r; 194 | if (m_controller) m_controller->setInitBw (m_initBw); 195 | } 196 | 197 | void RmcatSender::SetRmin (float r) 198 | { 199 | m_minBw = r; 200 | if (m_controller) m_controller->setMinBw (m_minBw); 201 | } 202 | 203 | void RmcatSender::SetRmax (float r) 204 | { 205 | m_maxBw = r; 206 | if (m_controller) m_controller->setMaxBw (m_maxBw); 207 | } 208 | 209 | void RmcatSender::StartApplication () 210 | { 211 | m_ssrc = rand (); 212 | // RTP initial values for sequence number and timestamp SHOULD be random (RFC 3550) 213 | m_sequence = rand (); 214 | m_rtpTsOffset = rand (); 215 | 216 | NS_ASSERT (m_minBw <= m_initBw); 217 | NS_ASSERT (m_initBw <= m_maxBw); 218 | 219 | m_rVin = m_initBw; 220 | m_rSend = m_initBw; 221 | 222 | if (m_socket == NULL) { 223 | m_socket = Socket::CreateSocket (GetNode (), UdpSocketFactory::GetTypeId ()); 224 | auto res = m_socket->Bind (); 225 | NS_ASSERT (res == 0); 226 | } 227 | m_socket->SetRecvCallback (MakeCallback (&RmcatSender::RecvPacket, this)); 228 | 229 | m_enqueueEvent = Simulator::Schedule (Seconds (0.0), &RmcatSender::EnqueuePacket, this); 230 | m_nextSendTstmpUs = 0; 231 | } 232 | 233 | void RmcatSender::StopApplication () 234 | { 235 | Simulator::Cancel (m_enqueueEvent); 236 | Simulator::Cancel (m_sendEvent); 237 | Simulator::Cancel (m_sendOversleepEvent); 238 | m_rateShapingBuf.clear (); 239 | m_rateShapingBytes = 0; 240 | } 241 | 242 | void RmcatSender::EnqueuePacket () 243 | { 244 | syncodecs::Codec& codec = *m_codec; 245 | codec.setTargetRate (m_rVin); 246 | ++codec; // Advance codec/packetizer to next frame/packet 247 | const auto bytesToSend = codec->first.size (); 248 | NS_ASSERT (bytesToSend > 0); 249 | NS_ASSERT (bytesToSend <= DEFAULT_PACKET_SIZE); 250 | 251 | m_rateShapingBuf.push_back (bytesToSend); 252 | m_rateShapingBytes += bytesToSend; 253 | 254 | NS_LOG_INFO ("RmcatSender::EnqueuePacket, packet enqueued, packet length: " << bytesToSend 255 | << ", buffer size: " << m_rateShapingBuf.size () 256 | << ", buffer bytes: " << m_rateShapingBytes); 257 | 258 | double secsToNextEnqPacket = codec->second; 259 | Time tNext{Seconds (secsToNextEnqPacket)}; 260 | m_enqueueEvent = Simulator::Schedule (tNext, &RmcatSender::EnqueuePacket, this); 261 | 262 | if (!USE_BUFFER) { 263 | m_sendEvent = Simulator::ScheduleNow (&RmcatSender::SendPacket, this, 264 | secsToNextEnqPacket * 1000. * 1000.); 265 | return; 266 | } 267 | 268 | if (m_rateShapingBuf.size () == 1) { 269 | // Buffer was empty 270 | const uint64_t nowUs = Simulator::Now ().GetMicroSeconds (); 271 | const uint64_t usToNextSentPacket = nowUs < m_nextSendTstmpUs ? 272 | m_nextSendTstmpUs - nowUs : 0; 273 | NS_LOG_INFO ("(Re-)starting the send timer: nowUs " << nowUs 274 | << ", bytesToSend " << bytesToSend 275 | << ", usToNextSentPacket " << usToNextSentPacket 276 | << ", m_rSend " << m_rSend 277 | << ", m_rVin " << m_rVin 278 | << ", secsToNextEnqPacket " << secsToNextEnqPacket); 279 | 280 | Time tNext{MicroSeconds (usToNextSentPacket)}; 281 | m_sendEvent = Simulator::Schedule (tNext, &RmcatSender::SendPacket, this, usToNextSentPacket); 282 | } 283 | } 284 | 285 | void RmcatSender::SendPacket (uint64_t usSlept) 286 | { 287 | NS_ASSERT (m_rateShapingBuf.size () > 0); 288 | NS_ASSERT (m_rateShapingBytes < MAX_QUEUE_SIZE_SANITY); 289 | 290 | const auto bytesToSend = m_rateShapingBuf.front (); 291 | NS_ASSERT (bytesToSend > 0); 292 | NS_ASSERT (bytesToSend <= DEFAULT_PACKET_SIZE); 293 | m_rateShapingBuf.pop_front (); 294 | NS_ASSERT (m_rateShapingBytes >= bytesToSend); 295 | m_rateShapingBytes -= bytesToSend; 296 | 297 | NS_LOG_INFO ("RmcatSender::SendPacket, packet dequeued, packet length: " << bytesToSend 298 | << ", buffer size: " << m_rateShapingBuf.size () 299 | << ", buffer bytes: " << m_rateShapingBytes); 300 | 301 | // Synthetic oversleep: random uniform [0% .. 1%] 302 | uint64_t oversleepUs = usSlept * (rand () % 100) / 10000; 303 | Time tOver{MicroSeconds (oversleepUs)}; 304 | m_sendOversleepEvent = Simulator::Schedule (tOver, &RmcatSender::SendOverSleep, 305 | this, bytesToSend); 306 | 307 | // schedule next sendData 308 | const double usToNextSentPacketD = double (bytesToSend) * 8. * 1000. * 1000. / m_rSend; 309 | const uint64_t usToNextSentPacket = uint64_t (usToNextSentPacketD); 310 | 311 | if (!USE_BUFFER || m_rateShapingBuf.size () == 0) { 312 | // Buffer became empty 313 | const auto nowUs = Simulator::Now ().GetMicroSeconds (); 314 | m_nextSendTstmpUs = nowUs + usToNextSentPacket; 315 | return; 316 | } 317 | 318 | Time tNext{MicroSeconds (usToNextSentPacket)}; 319 | m_sendEvent = Simulator::Schedule (tNext, &RmcatSender::SendPacket, this, usToNextSentPacket); 320 | } 321 | 322 | void RmcatSender::SendOverSleep (uint32_t bytesToSend) { 323 | const auto nowUs = Simulator::Now ().GetMicroSeconds (); 324 | 325 | m_controller->processSendPacket (nowUs, m_sequence, bytesToSend); 326 | 327 | ns3::RtpHeader header{96}; // 96: dynamic payload type, according to RFC 3551 328 | header.SetSequence (m_sequence++); 329 | NS_ASSERT (nowUs >= 0); 330 | // Most video payload types in RFC 3551, Table 5, use a 90 KHz clock 331 | // Therefore, assuming 90 KHz clock for RTP timestamps 332 | header.SetTimestamp (m_rtpTsOffset + uint32_t (nowUs * 90 / 1000));; 333 | header.SetSsrc (m_ssrc); 334 | 335 | auto packet = Create (bytesToSend); 336 | packet->AddHeader (header); 337 | 338 | NS_LOG_INFO ("RmcatSender::SendOverSleep, " << packet->ToString ()); 339 | m_socket->SendTo (packet, 0, InetSocketAddress{m_destIP, m_destPort}); 340 | } 341 | 342 | void RmcatSender::RecvPacket (Ptr socket) 343 | { 344 | Address remoteAddr; 345 | auto Packet = m_socket->RecvFrom (remoteAddr); 346 | NS_ASSERT (Packet); 347 | 348 | auto rIPAddress = InetSocketAddress::ConvertFrom (remoteAddr).GetIpv4 (); 349 | auto rport = InetSocketAddress::ConvertFrom (remoteAddr).GetPort (); 350 | NS_ASSERT (rIPAddress == m_destIP); 351 | NS_ASSERT (rport == m_destPort); 352 | 353 | // get the feedback header 354 | const uint64_t nowUs = Simulator::Now ().GetMicroSeconds (); 355 | CCFeedbackHeader header{}; 356 | NS_LOG_INFO ("RmcatSender::RecvPacket, " << Packet->ToString ()); 357 | Packet->RemoveHeader (header); 358 | std::set ssrcList{}; 359 | header.GetSsrcList (ssrcList); 360 | if (ssrcList.count (m_ssrc) == 0) { 361 | NS_LOG_INFO ("RmcatSender::Received Feedback packet with no data for SSRC " << m_ssrc); 362 | CalcBufferParams (nowUs); 363 | return; 364 | } 365 | std::vector > feedback{}; 367 | const bool res = header.GetMetricList (m_ssrc, feedback); 368 | NS_ASSERT (res); 369 | std::vector fbBatch{}; 370 | for (auto& item : feedback) { 371 | const rmcat::SenderBasedController::FeedbackItem fbItem{ 372 | .sequence = item.first, 373 | .rxTimestampUs = item.second.m_timestampUs, 374 | .ecn = item.second.m_ecn 375 | }; 376 | fbBatch.push_back (fbItem); 377 | } 378 | m_controller->processFeedbackBatch (nowUs, fbBatch); 379 | CalcBufferParams (nowUs); 380 | } 381 | 382 | void RmcatSender::CalcBufferParams (uint64_t nowUs) 383 | { 384 | //Calculate rate shaping buffer parameters 385 | const auto r_ref = m_controller->getBandwidth (nowUs); // bandwidth in bps 386 | float bufferLen; 387 | //Purpose: smooth out timing issues between send and receive 388 | // feedback for the common case: buffer oscillating between 0 and 1 packets 389 | if (m_rateShapingBuf.size () > 1) { 390 | bufferLen = static_cast (m_rateShapingBytes); 391 | } else { 392 | bufferLen = 0; 393 | } 394 | 395 | syncodecs::Codec& codec = *m_codec; 396 | 397 | // TODO (deferred): encapsulate rate shaping buffer in a separate class 398 | if (USE_BUFFER && static_cast (codec)) { 399 | float r_diff = 8. * bufferLen * m_fps; 400 | float r_diff_v = std::min(BETA_V*r_diff, r_ref*0.05); // limit change to 5% of reference rate 401 | float r_diff_s = std::min(BETA_S*r_diff, r_ref*0.05); // limit change to 5% of reference rate 402 | m_rVin = std::max (m_minBw, r_ref - r_diff_v); 403 | m_rSend = std::min(m_maxBw, r_ref + r_diff_s); 404 | NS_LOG_INFO ("New rate shaping buffer parameters: r_ref " << r_ref/1000. // in Kbps 405 | << ", m_rVin " << m_rVin/1000. 406 | << ", m_rSend " << m_rSend/1000. 407 | << ", fps " << m_fps 408 | << ", buffer length " << bufferLen); // in Bytes 409 | } else { 410 | m_rVin = r_ref; 411 | m_rSend = r_ref; 412 | } 413 | } 414 | 415 | } 416 | -------------------------------------------------------------------------------- /model/apps/rmcat-sender.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Sender application interface for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #ifndef RMCAT_SENDER_H 29 | #define RMCAT_SENDER_H 30 | 31 | #include "rmcat-constants.h" 32 | #include "ns3/syncodecs.h" 33 | #include "ns3/sender-based-controller.h" 34 | #include "ns3/socket.h" 35 | #include "ns3/application.h" 36 | #include 37 | 38 | namespace ns3 { 39 | 40 | class RmcatSender: public Application 41 | { 42 | public: 43 | 44 | RmcatSender (); 45 | virtual ~RmcatSender (); 46 | 47 | void PauseResume (bool pause); 48 | 49 | void SetCodec (std::shared_ptr codec); 50 | void SetCodecType (SyncodecType codecType); 51 | 52 | void SetController (std::shared_ptr controller); 53 | 54 | void SetRinit (float Rinit); 55 | void SetRmin (float Rmin); 56 | void SetRmax (float Rmax); 57 | 58 | void Setup (Ipv4Address dest_ip, uint16_t dest_port); 59 | 60 | private: 61 | virtual void StartApplication (); 62 | virtual void StopApplication (); 63 | 64 | void EnqueuePacket (); 65 | void SendPacket (uint64_t usSlept); 66 | void SendOverSleep (uint32_t bytesToSend); 67 | void RecvPacket (Ptr socket); 68 | void CalcBufferParams (uint64_t nowUs); 69 | 70 | private: 71 | std::shared_ptr m_codec; 72 | std::shared_ptr m_controller; 73 | Ipv4Address m_destIP; 74 | uint16_t m_destPort; 75 | float m_initBw; 76 | float m_minBw; 77 | float m_maxBw; 78 | bool m_paused; 79 | uint32_t m_ssrc; 80 | uint16_t m_sequence; 81 | uint32_t m_rtpTsOffset; 82 | Ptr m_socket; 83 | EventId m_enqueueEvent; 84 | EventId m_sendEvent; 85 | EventId m_sendOversleepEvent; 86 | 87 | float m_fps; // frames-per-second 88 | double m_rVin; //bps 89 | double m_rSend; //bps 90 | std::deque m_rateShapingBuf; 91 | uint32_t m_rateShapingBytes; 92 | uint64_t m_nextSendTstmpUs; 93 | }; 94 | 95 | } 96 | 97 | #endif /* RMCAT_SENDER_H */ 98 | -------------------------------------------------------------------------------- /model/apps/rtp-header.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2018 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Header interface of RTP packets (RFC 3550), and RTCP Feedback 21 | * packets (draft-ietf-avtcore-cc-feedback-message-01) for ns3-rmcat. 22 | 23 | * @version 0.1.1 24 | * @author Jiantao Fu 25 | * @author Sergio Mena 26 | * @author Xiaoqing Zhu 27 | */ 28 | 29 | #ifndef RTP_HEADER_H 30 | #define RTP_HEADER_H 31 | 32 | #include "ns3/header.h" 33 | #include "ns3/type-id.h" 34 | #include 35 | #include 36 | 37 | namespace ns3 { 38 | 39 | void RtpHdrSetBit (uint8_t& val, uint8_t pos, bool bit); 40 | bool RtpHdrGetBit (uint8_t val, uint8_t pos); 41 | 42 | const uint8_t RTP_VERSION = 2; 43 | 44 | //-------------------- RTP HEADER (RFC 3550) ----------------------// 45 | // 0 1 2 3 46 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 47 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 48 | // |V=2|P|X| CC |M| PT | sequence number | 49 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 50 | // | timestamp | 51 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 52 | // | synchronization source (SSRC) identifier | 53 | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 54 | // | contributing source (CSRC) identifiers | 55 | // | .... | 56 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 57 | class RtpHeader : public Header 58 | { 59 | public: 60 | RtpHeader (); 61 | RtpHeader (uint8_t payloadType); 62 | virtual ~RtpHeader (); 63 | 64 | static ns3::TypeId GetTypeId (); 65 | virtual ns3::TypeId GetInstanceTypeId () const; 66 | virtual uint32_t GetSerializedSize () const; 67 | virtual void Serialize (ns3::Buffer::Iterator start) const; 68 | virtual uint32_t Deserialize (ns3::Buffer::Iterator start); 69 | virtual void Print (std::ostream& os) const; 70 | 71 | bool IsPadding () const; 72 | void SetPadding (bool padding); 73 | bool IsExtension () const; 74 | void SetExtension (bool extension); 75 | bool IsMarker () const; 76 | void SetMarker (bool marker); 77 | uint8_t GetPayloadType () const; 78 | void SetPayloadType (uint8_t payloadType); 79 | uint16_t GetSequence () const; 80 | void SetSequence (uint16_t sequence); 81 | uint32_t GetSsrc () const; 82 | void SetSsrc (uint32_t ssrc); 83 | uint32_t GetTimestamp () const; 84 | void SetTimestamp (uint32_t timestamp); 85 | const std::set& GetCsrcs () const; 86 | bool AddCsrc (uint32_t csrc); 87 | 88 | protected: 89 | bool m_padding; 90 | bool m_extension; 91 | bool m_marker; 92 | uint8_t m_payloadType; 93 | uint16_t m_sequence; 94 | uint32_t m_timestamp; 95 | uint32_t m_ssrc; 96 | std::set m_csrcs; 97 | }; 98 | 99 | 100 | //----------------- Common RCTP HEADER (RFC 3550) -----------------// 101 | // 0 1 2 3 102 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 103 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 104 | // |V=2|P| Type/Cnt| PT | length | 105 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 106 | // | SSRC of RTCP packet sender | 107 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 108 | class RtcpHeader : public Header 109 | { 110 | public: 111 | enum PayloadType { 112 | RTCP_SMPTETC = 194, 113 | RTCP_IJ = 195, 114 | RTCP_SR = 200, 115 | RTCP_RR = 201, 116 | RTCP_SDES = 202, 117 | RTCP_BYE = 203, 118 | RTCP_APP = 204, 119 | RTP_FB = 205, 120 | RTP_PSFB = 206, 121 | RTP_XR = 207, 122 | RTP_RSI = 209, 123 | RTP_TOKEN = 210, 124 | RTP_IDMS = 211, 125 | RTP_RSNM = 213, 126 | }; 127 | 128 | enum SdesType{ 129 | RTCP_SDES_END = 0, 130 | RTCP_SDES_CNAME = 1, 131 | RTCP_SDES_NAME = 2, 132 | RTCP_SDES_EMAIL = 3, 133 | RTCP_SDES_PHONE = 4, 134 | RTCP_SDES_LOC = 5, 135 | RTCP_SDES_TOOL = 6, 136 | RTCP_SDES_NOTE = 7, 137 | RTCP_SDES_PRIV = 8, 138 | RTCP_SDES_APSI = 10, 139 | }; 140 | 141 | enum RtpFeedbackType { 142 | RTCP_RTPFB_GNACK = 1, 143 | RTCP_RTPFB_TMMBR = 3, 144 | RTCP_RTPFB_TMMBN = 4, 145 | RTCP_RTPFB_SR_REQ = 5, 146 | RTCP_RTPFB_RAMS = 6, 147 | RTCP_RTPFB_TLLEI = 7, 148 | RTCP_RTPFB_ECN_FB = 8, 149 | RTCP_RTPFB_PR = 9, 150 | RTCP_RTPFB_CC = 15, // TODO (deferred): Change to IANA-assigned value 151 | }; 152 | 153 | RtcpHeader (); 154 | RtcpHeader (uint8_t packetType); 155 | RtcpHeader (uint8_t packetType, uint8_t subType); 156 | virtual ~RtcpHeader (); 157 | virtual void Clear (); 158 | 159 | static ns3::TypeId GetTypeId (); 160 | virtual ns3::TypeId GetInstanceTypeId () const; 161 | virtual uint32_t GetSerializedSize () const; 162 | virtual void Serialize (ns3::Buffer::Iterator start) const; 163 | virtual uint32_t Deserialize (ns3::Buffer::Iterator start); 164 | virtual void Print (std::ostream& os) const; 165 | 166 | bool IsPadding () const; 167 | void SetPadding (bool padding); 168 | uint8_t GetTypeOrCount () const; 169 | void SetTypeOrCount (uint8_t typeOrCnt); 170 | uint8_t GetPacketType () const; 171 | void SetPacketType (uint8_t packetType); 172 | uint32_t GetSendSsrc () const; 173 | void SetSendSsrc (uint32_t sendSsrc); 174 | 175 | protected: 176 | void PrintN (std::ostream& os) const; 177 | void SerializeCommon (ns3::Buffer::Iterator& start) const; 178 | uint32_t DeserializeCommon (ns3::Buffer::Iterator& start); 179 | 180 | bool m_padding; 181 | uint8_t m_typeOrCnt; 182 | uint8_t m_packetType; 183 | uint16_t m_length; 184 | uint32_t m_sendSsrc; 185 | }; 186 | 187 | //-- RCTP CCFB HEADER (draft-ietf-avtcore-cc-feedback-message-01) -// 188 | // 0 1 2 3 189 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 190 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 191 | // |V=2|P| FMT=CCFB| PT=RTPFB=205 | length | 192 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 193 | // | SSRC of RTCP packet sender | 194 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 195 | // | SSRC of 1st RTP Stream | 196 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 197 | // | begin_seq | end_seq | 198 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 199 | // |L|ECN| Arrival time offset | ... . 200 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 201 | // . . 202 | // . . 203 | // . . 204 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 205 | // | SSRC of nth RTP Stream | 206 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 207 | // | begin_seq | end_seq | 208 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 209 | // |L|ECN| Arrival time offset | ... | 210 | // . . 211 | // . . 212 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 213 | // | Report Timestamp | 214 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 215 | class CCFeedbackHeader : public RtcpHeader 216 | { 217 | public: 218 | class MetricBlock 219 | { 220 | public: 221 | static constexpr uint16_t m_overrange = 0x1FFE; 222 | static constexpr uint16_t m_unavailable = 0x1FFF; 223 | uint8_t m_ecn; 224 | uint64_t m_timestampUs; 225 | uint16_t m_ato; 226 | }; 227 | 228 | enum RejectReason { 229 | CCFB_NONE, /**< Feedback was added correctly */ 230 | CCFB_DUPLICATE, /**< Feedback of duplicate packet */ 231 | CCFB_BAD_ECN, /**< ECN value takes more than two bits */ 232 | CCFB_TOO_LONG, /**< Adding this sequence number would make the packet too long */ 233 | }; 234 | typedef std::map ReportBlock_t; 235 | 236 | CCFeedbackHeader (); 237 | virtual ~CCFeedbackHeader (); 238 | virtual void Clear (); 239 | 240 | static ns3::TypeId GetTypeId (); 241 | virtual ns3::TypeId GetInstanceTypeId () const; 242 | virtual uint32_t GetSerializedSize () const; 243 | virtual void Serialize (ns3::Buffer::Iterator start) const; 244 | virtual uint32_t Deserialize (ns3::Buffer::Iterator start); 245 | virtual void Print (std::ostream& os) const; 246 | 247 | RejectReason AddFeedback (uint32_t ssrc, uint16_t seq, uint64_t timestampUs, uint8_t ecn=0); 248 | bool Empty () const; 249 | void GetSsrcList (std::set& rv) const; 250 | bool GetMetricList (uint32_t ssrc, std::vector >& rv) const; 251 | 252 | protected: 253 | static std::pair CalculateBeginStopSeq (const ReportBlock_t& rb); 254 | static uint64_t NtpToUs (uint32_t ntp); 255 | static uint32_t UsToNtp (uint64_t tsUs); 256 | static uint16_t NtpToAto (uint32_t ntp, uint32_t ntpRef); 257 | static uint32_t AtoToNtp (uint16_t ato, uint32_t ntpRef); 258 | 259 | bool UpdateLength (); 260 | std::map m_reportBlocks; 261 | uint64_t m_latestTsUs; 262 | }; 263 | 264 | } 265 | 266 | #endif /* RTP_HEADER_H */ 267 | -------------------------------------------------------------------------------- /model/congestion-control/dummy-controller.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Dummy controller (CBR) implementation for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | #include "dummy-controller.h" 28 | #include 29 | #include 30 | 31 | namespace rmcat { 32 | 33 | DummyController::DummyController() : 34 | SenderBasedController{}, 35 | m_lastTimeCalcUs{0}, 36 | m_lastTimeCalcValid{false}, 37 | m_QdelayUs{0}, 38 | m_ploss{0}, 39 | m_plr{0.f}, 40 | m_RecvR{0.} {} 41 | 42 | DummyController::~DummyController() {} 43 | 44 | void DummyController::setCurrentBw(float newBw) { 45 | m_initBw = newBw; 46 | } 47 | 48 | void DummyController::reset() { 49 | m_lastTimeCalcUs = 0; 50 | m_lastTimeCalcValid = false; 51 | 52 | m_QdelayUs = 0; 53 | m_ploss = 0; 54 | m_plr = 0.f; 55 | m_RecvR = 0.; 56 | 57 | SenderBasedController::reset(); 58 | } 59 | 60 | bool DummyController::processFeedback(uint64_t nowUs, 61 | uint16_t sequence, 62 | uint64_t rxTimestampUs, 63 | uint8_t ecn) { 64 | // First of all, call the superclass 65 | const bool res = SenderBasedController::processFeedback(nowUs, sequence, 66 | rxTimestampUs, ecn); 67 | const uint64_t calcIntervalUs = 200 * 1000; 68 | if (m_lastTimeCalcValid) { 69 | assert(lessThan(m_lastTimeCalcUs, nowUs + 1)); 70 | if (nowUs - m_lastTimeCalcUs >= calcIntervalUs) { 71 | updateMetrics(); 72 | logStats(nowUs); 73 | m_lastTimeCalcUs = nowUs; 74 | } 75 | } else { 76 | m_lastTimeCalcUs = nowUs; 77 | m_lastTimeCalcValid = true; 78 | } 79 | return res; 80 | } 81 | 82 | float DummyController::getBandwidth(uint64_t nowUs) const { 83 | 84 | return m_initBw; 85 | } 86 | 87 | void DummyController::updateMetrics() { 88 | uint64_t qdelayUs; 89 | bool qdelayOK = getCurrentQdelay(qdelayUs); 90 | if (qdelayOK) m_QdelayUs = qdelayUs; 91 | 92 | float rrate; 93 | bool rrateOK = getCurrentRecvRate(rrate); 94 | if (rrateOK) m_RecvR = rrate; 95 | 96 | uint32_t nLoss; 97 | float plr; 98 | bool plrOK = getPktLossInfo(nLoss, plr); 99 | if (plrOK) { 100 | m_ploss = nLoss; 101 | m_plr = plr; 102 | } 103 | } 104 | 105 | void DummyController::logStats(uint64_t nowUs) const { 106 | 107 | std::ostringstream os; 108 | os << std::fixed; 109 | os.precision(RMCAT_LOG_PRINT_PRECISION); 110 | 111 | os << " algo:dummy " << m_id 112 | << " ts: " << (nowUs / 1000) 113 | << " loglen: " << m_packetHistory.size() 114 | << " qdel: " << (m_QdelayUs / 1000) 115 | << " ploss: " << m_ploss 116 | << " plr: " << m_plr 117 | << " rrate: " << m_RecvR 118 | << " srate: " << m_initBw; 119 | logMessage(os.str()); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /model/congestion-control/dummy-controller.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Dummy controller (CBR) interface for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #ifndef DUMMY_CONTROLLER_H 29 | #define DUMMY_CONTROLLER_H 30 | 31 | #include "sender-based-controller.h" 32 | 33 | namespace rmcat { 34 | 35 | /** 36 | * Simplistic implementation of a sender-based congestion controller. The 37 | * algorithm simply returns a constant, hard-coded bandwidth when queried. 38 | */ 39 | class DummyController: public SenderBasedController 40 | { 41 | public: 42 | /** Class constructor */ 43 | DummyController(); 44 | 45 | /** Class destructor */ 46 | virtual ~DummyController(); 47 | 48 | /** 49 | * Set the current bandwidth estimation. This can be useful in test environments 50 | * to temporarily disrupt the current bandwidth estimation 51 | * 52 | * @param [in] newBw Bandwidth estimation to overwrite the current estimation 53 | */ 54 | virtual void setCurrentBw(float newBw); 55 | 56 | /** 57 | * Reset the internal state of the congestion controller 58 | */ 59 | virtual void reset(); 60 | 61 | /** 62 | * Simplistic implementation of feedback packet processing. It simply 63 | * prints calculated metrics at regular intervals 64 | */ 65 | virtual bool processFeedback(uint64_t nowUs, 66 | uint16_t sequence, 67 | uint64_t rxTimestampUs, 68 | uint8_t ecn=0); 69 | /** 70 | * Simplistic implementation of bandwidth getter. It returns a hard-coded 71 | * bandwidth value in bits per second 72 | */ 73 | virtual float getBandwidth(uint64_t nowUs) const; 74 | 75 | private: 76 | void updateMetrics(); 77 | void logStats(uint64_t nowUs) const; 78 | 79 | uint64_t m_lastTimeCalcUs; 80 | bool m_lastTimeCalcValid; 81 | 82 | uint64_t m_QdelayUs; /**< estimated queuing delay in microseconds */ 83 | uint32_t m_ploss; /**< packet loss count within configured window */ 84 | float m_plr; /**< packet loss ratio within packet history window */ 85 | float m_RecvR; /**< updated receiving rate in bps */ 86 | }; 87 | 88 | } 89 | 90 | #endif /* DUMMY_CONTROLLER_H */ 91 | -------------------------------------------------------------------------------- /model/congestion-control/nada-controller.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * NADA controller interface for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #ifndef NADA_CONTROLLER_H 29 | #define NADA_CONTROLLER_H 30 | 31 | #include "sender-based-controller.h" 32 | 33 | namespace rmcat { 34 | 35 | /** 36 | * This class corresponds to the congestion control scheme 37 | * named Network-Assisted Dynamic Adaptation (NADA). Details 38 | * of the algorithm are documented in the following IETF 39 | * draft (rmcat-nada): 40 | * 41 | * NADA: A Unified Congestion Control Scheme for Real-Time Media 42 | * https://tools.ietf.org/html/draft-ietf-rmcat-nada-04 43 | * 44 | */ 45 | class NadaController: public SenderBasedController { 46 | public: 47 | /* class constructor */ 48 | NadaController(); 49 | 50 | /* class destructor */ 51 | virtual ~NadaController(); 52 | 53 | /** 54 | * Set the current bandwidth estimation. This can be useful in test environments 55 | * to temporarily disrupt the current bandwidth estimation 56 | * 57 | * @param [in] newBw Bandwidth estimation to overwrite the current estimation 58 | */ 59 | virtual void setCurrentBw(float newBw); 60 | 61 | /** 62 | * NADA's implementation of the #reset virtual function; 63 | * resets internal states to initial values 64 | */ 65 | virtual void reset(); 66 | 67 | /** NADA's implementation of the #processSendPacket API */ 68 | virtual bool processSendPacket(uint64_t txTimestampUs, 69 | uint16_t sequence, 70 | uint32_t size); // in Bytes 71 | 72 | /** NADA's implementation of the #processFeedback API */ 73 | virtual bool processFeedback(uint64_t nowUs, 74 | uint16_t sequence, 75 | uint64_t rxTimestampUs, 76 | uint8_t ecn=0); 77 | 78 | /** NADA's implementation of the #processFeedbackBatch API */ 79 | virtual bool processFeedbackBatch(uint64_t nowUs, 80 | const std::vector& feedbackBatch); 81 | 82 | /** NADA's realization of the #getBandwidth API */ 83 | virtual float getBandwidth(uint64_t nowUs) const; 84 | 85 | private: 86 | 87 | /** 88 | * Function for retrieving updated estimates 89 | * (by the base class SenderBasedController) of 90 | * delay, loss, and receiving rate metrics and 91 | * copying them to local member variables 92 | */ 93 | void updateMetrics(); 94 | 95 | /** 96 | * Function for printing losses, delay, and rate 97 | * metrics to log in a pre-formatted manner 98 | * @param [in] nowUs current timestamp in microseconds 99 | */ 100 | void logStats(uint64_t nowUs, uint64_t deltaUs) const; 101 | 102 | /** 103 | * Function for calculating the target bandwidth 104 | * following the NADA algorithm 105 | * 106 | * @param [in] deltaUs interval from last bandwidth calculation 107 | * in microseconds 108 | */ 109 | void updateBw(uint64_t deltaUs); 110 | 111 | /** 112 | * Function for calculating the reference rate (r_ref) 113 | * during the gradual update mode. Typically this is during 114 | * the steay-state phase of the algorithm. 115 | * 116 | * See Section 4.3 and Eq.(5)-(7) in the rmcat-nada draft 117 | * for greater detail. 118 | * 119 | * @param [in] deltaUs interval from last bandwidth calculation in microseconds 120 | */ 121 | void calcGradualRateUpdate(uint64_t deltaUs); 122 | 123 | /** 124 | * Function for calculating the reference rate (r_ref) 125 | * during the accelerated ramp-up mode. Typically this 126 | * is carried out during the congestion-free periods of 127 | * the flow, e.g., when a flow enters an empty link 128 | * or when existing background flows exit and opens up 129 | * more available bandwidth. 130 | * 131 | * See Section 4.3 and Eq. (3)-(4) in the rmcat-nada 132 | * draft for greater detail. 133 | * 134 | */ 135 | void calcAcceleratedRampUp(); 136 | 137 | /** 138 | * Function for determining wether the sender should 139 | * operate in accelerated ramp-up mode or gradual 140 | * update model. 141 | * 142 | * @retval 0 if the sender should operate in accelerated 143 | * ramp-up mode (rmode == 0 as in draft-rmcat-nada) 144 | * and 1 if the sender should operate in 145 | * gradual update mode (rmode == 1 as in 146 | * draft-rmcat-nada) 147 | */ 148 | int getRampUpMode(); 149 | 150 | /** 151 | * Function for calculating the aggregated congestion 152 | * signal (x_curr) based on packet statistics both 153 | * in terms of loss and delay. 154 | */ 155 | void updateXcurr(); 156 | 157 | /** 158 | * Function for calculating the non-linear warping 159 | * of queuing delay in ms (d_tilde in rmcat-nada), 160 | * when the NADA sender is operating in loss-based 161 | * mode 162 | * 163 | * @retval value of the warped delay-based congestion 164 | * signal value in ms (d_tilde in rmcat-nada) 165 | */ 166 | float calcDtilde() const; 167 | 168 | /** 169 | * Following are local member variables recording current 170 | * packet loss/delay information, as well as operational 171 | * mode of the NADA algorithm 172 | */ 173 | uint32_t m_ploss; /**< packet loss count within configured window */ 174 | float m_plr; /**< packet loss ratio within packet history window */ 175 | bool m_warpMode; /**< whether to perform non-linear warping of queuing delay */ 176 | 177 | /** timestamp of when r_ref is last calculated (t_last in rmcat-nada), in microseconds */ 178 | uint64_t m_lastTimeCalcUs; 179 | /** whether value m_lastTimeCalc is valid: not valid before first rate update */ 180 | bool m_lastTimeCalcValid; 181 | 182 | float m_currBw; /**< calculated reference rate (r_ref in rmcat-nada) */ 183 | 184 | uint64_t m_QdelayUs; /**< estimated queuing delay in microseconds */ 185 | uint64_t m_RttUs; /**< estimated RTT value in microseconds */ 186 | float m_Xcurr; /**< aggregated congestion signal (x_curr in rmcat-nada) in ms */ 187 | float m_Xprev; /**< previous value of the aggregated congestion signal (x_prev in rmcat-nada), in ms */ 188 | float m_RecvR; /**< updated receiving rate in bps */ 189 | float m_avgInt; /**< Average inter-loss interval in packets, according to RFC 5348 */ 190 | uint32_t m_currInt; /**< Most recent (currently growing) inter-loss interval in packets; called I_0 in RFC 5348 */ 191 | bool m_lossesSeen; /**< Whether packet losses/reorderings have been detected so far */ 192 | }; 193 | 194 | } 195 | 196 | #endif /* NADA_CONTROLLER_H */ 197 | -------------------------------------------------------------------------------- /model/topo/topo.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Common network topology setup implementation for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #include "topo.h" 29 | #include "ns3/rmcat-sender.h" 30 | #include "ns3/rmcat-receiver.h" 31 | #include "ns3/nada-controller.h" 32 | #include 33 | #include 34 | #include 35 | 36 | NS_LOG_COMPONENT_DEFINE ("Topo"); 37 | 38 | namespace ns3 { 39 | 40 | /* Implementations of utility functions */ 41 | 42 | static Ipv4Address GetIpv4AddressOfNode (Ptr node, 43 | uint32_t interface, 44 | uint32_t addressIndex) 45 | { 46 | // interface index 0 is the loopback 47 | auto ipv4 = node->GetObject (); 48 | auto iaddr = ipv4->GetAddress (interface, addressIndex); 49 | return iaddr.GetLocal (); 50 | } 51 | 52 | 53 | static std::string GetPrefix (Ptr node, 54 | const std::string& logName, 55 | const std::string& flowId, 56 | uint16_t port=0) 57 | { 58 | std::ostringstream os; 59 | os << "["; 60 | GetIpv4AddressOfNode (node, 1, 0).Print (os); 61 | os << ":" << port << "] " << logName << ": " << flowId; 62 | return os.str (); 63 | } 64 | 65 | static Time GetIntervalFromBitrate (uint64_t bitrate, uint32_t packetSize) 66 | { 67 | if (bitrate == 0u) { 68 | return Time::Max (); 69 | } 70 | const auto secs = static_cast (packetSize + IPV4_UDP_OVERHEAD) / 71 | (static_cast (bitrate) / 8. ); 72 | return Seconds (secs); 73 | } 74 | 75 | static void PacketSinkLogging (const std::string& nameAndId, 76 | Ptr app, 77 | double interval, 78 | uint32_t oldRecv) 79 | { 80 | TimeValue startT, stopT; 81 | app->GetAttribute ("StartTime", startT); 82 | app->GetAttribute ("StopTime", stopT); 83 | const auto now = Simulator::Now ().GetMilliSeconds (); 84 | const auto start = startT.Get ().GetMilliSeconds (); 85 | const auto stop = stopT.Get ().GetMilliSeconds (); 86 | auto recv = oldRecv; 87 | if (start <= now && now <= stop) { 88 | Ptr sink = DynamicCast (app); 89 | recv = sink->GetTotalRx (); 90 | std::ostringstream os; 91 | os << std::fixed; 92 | os.precision (4); 93 | os << nameAndId << " ts: " << now 94 | << " recv: " << recv // Number of bytes received so far for this flow 95 | << " rrate: " << static_cast (recv - oldRecv) / interval * 8.; 96 | // Subtraction will wrap properly 97 | NS_LOG_INFO (os.str ()); 98 | } 99 | Time tNext{Seconds (interval)}; 100 | Simulator::Schedule (tNext, &PacketSinkLogging, nameAndId, app, interval, recv); 101 | } 102 | 103 | 104 | /* 105 | * Implementations of: 106 | * -- InstallTCP 107 | * -- InstallCBR 108 | * -- InstallRMCAT 109 | */ 110 | 111 | ApplicationContainer Topo::InstallTCP (const std::string& flowId, 112 | Ptr sender, 113 | Ptr receiver, 114 | uint16_t serverPort) 115 | { 116 | BulkSendHelper source ("ns3::TcpSocketFactory", 117 | InetSocketAddress{GetIpv4AddressOfNode (receiver, 1, 0), serverPort}); 118 | 119 | // Set the amount of data to send in bytes. Zero denotes unlimited. 120 | source.SetAttribute ("MaxBytes", UintegerValue (0)); 121 | source.SetAttribute ("SendSize", UintegerValue (DEFAULT_PACKET_SIZE)); 122 | 123 | auto clientApps = source.Install (sender); 124 | clientApps.Start (Seconds (0)); 125 | clientApps.Stop (Seconds (T_MAX_S)); 126 | 127 | PacketSinkHelper sink ("ns3::TcpSocketFactory", 128 | InetSocketAddress{Ipv4Address::GetAny (), serverPort}); 129 | auto serverApps = sink.Install (receiver); 130 | serverApps.Start (Seconds (0)); 131 | serverApps.Stop (Seconds (T_MAX_S)); 132 | 133 | const auto interval = T_TCP_LOG; 134 | Simulator::Schedule (Seconds (interval), 135 | &PacketSinkLogging, 136 | GetPrefix (sender, "tcp_log", flowId, serverPort), 137 | serverApps.Get (0), 138 | interval, 139 | 0); 140 | 141 | ApplicationContainer apps; 142 | apps.Add (clientApps); 143 | apps.Add (serverApps); 144 | return apps; 145 | } 146 | 147 | 148 | ApplicationContainer Topo::InstallCBR (Ptr sender, 149 | Ptr receiver, 150 | uint16_t serverPort, 151 | uint64_t bitrate, 152 | uint32_t packetSize) 153 | { 154 | UdpServerHelper server (serverPort); 155 | ApplicationContainer serverApps = server.Install (receiver); 156 | serverApps.Start (Seconds (0)); 157 | serverApps.Stop (Seconds (T_MAX_S)); 158 | 159 | const auto interPacketInterval = GetIntervalFromBitrate (bitrate, packetSize); 160 | const auto maxPacketCount = std::numeric_limits::max (); 161 | UdpClientHelper client (GetIpv4AddressOfNode (receiver, 1, 0), serverPort); 162 | client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount)); 163 | client.SetAttribute ("Interval", TimeValue (interPacketInterval)); 164 | client.SetAttribute ("PacketSize", UintegerValue (packetSize)); 165 | ApplicationContainer clientApps = client.Install (sender); 166 | clientApps.Start (Seconds (0)); 167 | clientApps.Stop (Seconds (T_MAX_S)); 168 | 169 | ApplicationContainer apps; 170 | apps.Add (clientApps); 171 | apps.Add (serverApps); 172 | return apps; 173 | } 174 | 175 | ApplicationContainer Topo::InstallRMCAT (const std::string& flowId, 176 | Ptr sender, 177 | Ptr receiver, 178 | uint16_t serverPort) 179 | { 180 | 181 | auto rmcatAppSend = CreateObject (); 182 | auto rmcatAppRecv = CreateObject (); 183 | sender->AddApplication (rmcatAppSend); 184 | receiver->AddApplication (rmcatAppRecv); 185 | 186 | Ipv4Address serverIP = GetIpv4AddressOfNode (receiver, 1, 0); 187 | rmcatAppSend->Setup (serverIP, serverPort); 188 | 189 | /* configure congestion controller */ 190 | auto controller = std::make_shared (); 191 | controller->setLogCallback (logFromController); 192 | controller->setId (flowId); 193 | rmcatAppSend->SetController (controller); 194 | 195 | rmcatAppSend->SetStartTime (Seconds (0)); 196 | rmcatAppSend->SetStopTime (Seconds (T_MAX_S)); 197 | 198 | rmcatAppRecv->Setup (serverPort); 199 | rmcatAppRecv->SetStartTime (Seconds (0)); 200 | rmcatAppRecv->SetStopTime (Seconds (T_MAX_S)); 201 | 202 | ApplicationContainer apps; 203 | apps.Add (rmcatAppSend); 204 | apps.Add (rmcatAppRecv); 205 | return apps; 206 | } 207 | 208 | void Topo::logFromController (const std::string& msg) { 209 | NS_LOG_INFO ("controller_log: " << msg); 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /model/topo/topo.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Common network topology setup for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #ifndef TOPO_H 29 | #define TOPO_H 30 | 31 | #include "ns3/core-module.h" 32 | #include "ns3/network-module.h" 33 | #include "ns3/internet-module.h" 34 | #include "ns3/point-to-point-module.h" 35 | #include "ns3/applications-module.h" 36 | #include "ns3/internet-apps-module.h" 37 | #include "ns3/ipv4-global-routing-helper.h" 38 | #include "ns3/internet-trace-helper.h" 39 | #include "ns3/mobility-module.h" 40 | #include "ns3/stats-module.h" 41 | #include "ns3/wifi-module.h" 42 | #include "ns3/traffic-control-helper.h" 43 | 44 | #include "ns3/rmcat-constants.h" 45 | 46 | namespace ns3 { 47 | 48 | class Topo 49 | { 50 | protected: 51 | /** 52 | * Install two applications (sender and receiver) implementing a TCP flow. 53 | * The sender of application data (resp. receiver) will be installed at the 54 | * sender (resp. receiver) node. 55 | * 56 | * @param [in] flowId A string denoting the flow's id. Useful for 57 | * logging and plotting 58 | * @param [in,out] sender ns3 node that is to contain the sender bulk TCP 59 | * application 60 | * @param [in,out] receiver ns3 node that is to contain the receiver bulk 61 | * TCP application 62 | * @param [in] serverPort TCP port where the server application is 63 | * to listen 64 | * 65 | * @retval A container with the two applications (sender and receiver) 66 | * 67 | */ 68 | static ApplicationContainer InstallTCP (const std::string& flowId, 69 | Ptr sender, 70 | Ptr receiver, 71 | uint16_t serverPort); 72 | 73 | /** 74 | * Install two applications (sender and receiver) implementing a constant 75 | * bitrate (CBR) flow over UDP. 76 | * The sender of application data (resp. receiver) will be installed at the 77 | * sender (resp. receiver) node. 78 | * 79 | * @param [in,out] sender ns3 node that is to contain the sender CBR UDP 80 | * application 81 | * @param [in,out] receiver ns3 node that is to contain the receiver CBR 82 | * UDP application 83 | * @param [in] serverPort UDP port where the receiver application is 84 | * to read datagrams 85 | * @param [in] bitrate Bitrate (constant) at which the flow is to 86 | * operate 87 | * @param [in] packetSize Size of of the data to be shipped in each 88 | * datagram 89 | * 90 | * @retval A container with the two applications (sender and receiver) 91 | * 92 | */ 93 | static ApplicationContainer InstallCBR (Ptr sender, 94 | Ptr receiver, 95 | uint16_t serverPort, 96 | uint64_t bitrate, 97 | uint32_t packetSize = DEFAULT_PACKET_SIZE); 98 | 99 | 100 | /** 101 | * Install two applications (sender and receiver) implementing an RMCAT 102 | * flow. 103 | * The sender of application data (resp. receiver) will be installed at the 104 | * sender (resp. receiver) node. 105 | * 106 | * @param [in] flowId A string denoting the flow's id. Useful for 107 | * logging and plotting 108 | * @param [in,out] sender ns3 node that is to contain the #RmcatSender 109 | * application 110 | * @param [in,out] receiver ns3 node that is to contain the #RmcatReceiver 111 | * application 112 | * @param [in] serverPort UDP port where the receiver application is 113 | * to read media packets 114 | * 115 | * @retval A container with the two applications (sender and receiver) 116 | */ 117 | 118 | static ApplicationContainer InstallRMCAT (const std::string& flowId, 119 | Ptr sender, 120 | Ptr receiver, 121 | uint16_t serverPort); 122 | 123 | 124 | /** 125 | * Simple logging callback to be passed to the congestion controller 126 | * 127 | * @param [in] msg Message that the congestion controller wants to log 128 | */ 129 | static void logFromController (const std::string& msg); 130 | }; 131 | 132 | } 133 | 134 | #endif /* TOPO_H */ 135 | -------------------------------------------------------------------------------- /model/topo/wifi-topo.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Wifi network topology setup for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #include "wifi-topo.h" 29 | #include 30 | 31 | namespace ns3 { 32 | 33 | WifiTopo::~WifiTopo () {} 34 | 35 | void WifiTopo::Build (uint64_t bandwidthBps, 36 | uint32_t msDelay, 37 | uint32_t msQDelay, 38 | uint32_t nWifi, 39 | WifiPhyStandard standard, 40 | WifiMode rateMode) 41 | { 42 | // Set up wired link 43 | m_wiredNodes.Create (2); 44 | PointToPointHelper wiredLinkHlpr; 45 | wiredLinkHlpr.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (bandwidthBps))); 46 | wiredLinkHlpr.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (msDelay))); 47 | 48 | uint32_t bufSize = bandwidthBps * msQDelay / 8 / 1000; 49 | // At least one full packet with default size must fit 50 | NS_ASSERT (bufSize >= DEFAULT_PACKET_SIZE + IPV4_UDP_OVERHEAD); 51 | wiredLinkHlpr.SetQueue ("ns3::DropTailQueue", 52 | "Mode", StringValue ("QUEUE_MODE_BYTES"), 53 | "MaxBytes", UintegerValue (bufSize)); 54 | 55 | m_wiredDevices = wiredLinkHlpr.Install (m_wiredNodes); 56 | 57 | //Uncomment the line below to ease troubleshooting 58 | //wiredLinkHlpr.EnablePcapAll ("WifiTopo-wired"); 59 | 60 | // Config global settings for wifi mac queue 61 | Config::SetDefault ("ns3::WifiMacQueue::MaxPacketNumber", UintegerValue (WIFI_TOPO_MACQUEUE_MAXNPKTS)); 62 | Config::SetDefault ("ns3::WifiMacQueue::MaxDelay", TimeValue (MilliSeconds (msQDelay))); 63 | 64 | // Workaround for the arp bug, https://groups.google.com/forum/#!topic/ns-3-users/TiY9IUFnrZ4 65 | // http://mailman.isi.edu/pipermail/ns-developers/2007-November/003549.html 66 | // https://www.nsnam.org/bugzilla/show_bug.cgi?id=2057 67 | Config::SetDefault ("ns3::ArpCache::AliveTimeout", TimeValue (Seconds (WIFI_TOPO_ARPCACHE_ALIVE_TIMEOUT))); 68 | 69 | m_wifiStaNodes.Create (nWifi); 70 | m_wifiApNode = m_wiredNodes.Get (0); 71 | 72 | // Create channel 73 | YansWifiPhyHelper wifiPhyHelper = YansWifiPhyHelper::Default (); 74 | wifiPhyHelper.Set ("ChannelNumber",UintegerValue (6)); 75 | YansWifiChannelHelper wifiChannelHelper = YansWifiChannelHelper::Default (); 76 | wifiChannelHelper.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel"); 77 | 78 | // reference loss must be changed when operating at 2.4GHz 79 | if (standard == WIFI_PHY_STANDARD_80211n_2_4GHZ) { 80 | wifiChannelHelper.AddPropagationLoss ("ns3::LogDistancePropagationLossModel", 81 | "Exponent", DoubleValue (WIFI_TOPO_2_4GHZ_PATHLOSS_EXPONENT), 82 | "ReferenceLoss", DoubleValue (WIFI_TOPO_2_4GHZ_PATHLOSS_REFLOSS)); 83 | } 84 | wifiPhyHelper.SetChannel (wifiChannelHelper.Create ()); 85 | 86 | bool qos = false; 87 | bool ht = false; 88 | uint32_t channelWidth = WIFI_TOPO_CHANNEL_WIDTH; 89 | // Set guard interval, qos and ht for 802.11 and ac 90 | if ( standard == WIFI_PHY_STANDARD_80211n_5GHZ \ 91 | || standard == WIFI_PHY_STANDARD_80211n_2_4GHZ \ 92 | || standard == WIFI_PHY_STANDARD_80211ac 93 | ) { 94 | wifiPhyHelper.Set ("ShortGuardEnabled", BooleanValue (false)); 95 | // Set MIMO capabilities for high rate, see YansWifiPhy::ConfigureHtDeviceMcsSet 96 | wifiPhyHelper.Set ("TxAntennas", UintegerValue (8)); 97 | wifiPhyHelper.Set ("RxAntennas", UintegerValue (8)); 98 | 99 | qos = ht = true; 100 | } 101 | 102 | wifiPhyHelper.SetPcapDataLinkType (YansWifiPhyHelper::DLT_IEEE802_11_RADIO); 103 | 104 | //Uncomment the line below to ease troubleshooting 105 | //wifiPhyHelper.EnablePcapAll ("WifiTopo-wifi"); 106 | 107 | // Create wireless channel, see wifi-phy-standard.h 108 | m_wifi.SetStandard (standard); 109 | 110 | // See wifi-phy.h 111 | if (rateMode.GetUid () == 0) { 112 | m_wifi.SetRemoteStationManager ("ns3::MinstrelHtWifiManager"); 113 | } else { 114 | m_wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", 115 | "DataMode", StringValue (rateMode.GetUniqueName ()), 116 | "ControlMode", StringValue (rateMode.GetUniqueName ())); 117 | } 118 | 119 | // Uncomment the line below for debugging purposes 120 | // EnableWifiLogComponents (); 121 | 122 | Packet::EnablePrinting (); 123 | 124 | // Install phy and mac 125 | Ssid ssid = Ssid ("ns-3-ssid"); 126 | 127 | WifiMacHelper wifiMacHelper; 128 | 129 | // Set up station 130 | wifiMacHelper.SetType ("ns3::StaWifiMac", 131 | "Ssid", SsidValue (ssid), 132 | "ActiveProbing", BooleanValue (false), 133 | "QosSupported", BooleanValue (qos), 134 | "HtSupported", BooleanValue (ht)); 135 | m_staDevices = m_wifi.Install (wifiPhyHelper, wifiMacHelper, m_wifiStaNodes); 136 | 137 | // Set up AP 138 | wifiMacHelper.SetType ("ns3::ApWifiMac", 139 | "Ssid", SsidValue (ssid), 140 | "QosSupported", BooleanValue (qos), 141 | "HtSupported", BooleanValue (ht)); 142 | m_apDevices = m_wifi.Install (wifiPhyHelper, wifiMacHelper, m_wifiApNode); 143 | 144 | // Set channel width 145 | Config::Set ("/NodeList/*/DeviceList/*/$ns3::WifiNetDevice/Phy/ChannelWidth", 146 | UintegerValue (channelWidth)); 147 | 148 | // Configure mobility 149 | MobilityHelper mobility; 150 | Ptr positionAlloc = CreateObject (); 151 | for (uint32_t i = 0; i < nWifi; ++i) { 152 | positionAlloc->Add (Vector (1.0, 0.0, 0.0)); 153 | } 154 | positionAlloc->Add (Vector (0.0, 0.0, 0.0)); 155 | mobility.SetPositionAllocator (positionAlloc); 156 | mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); 157 | mobility.Install (m_wifiStaNodes); 158 | mobility.Install (m_wifiApNode); 159 | 160 | // install protocol stack 161 | InternetStackHelper stack; 162 | stack.Install (m_wifiStaNodes); 163 | stack.Install (m_wiredNodes); 164 | 165 | Ipv4AddressHelper address; 166 | 167 | address.SetBase ("10.1.1.0", "255.255.255.0"); 168 | address.Assign (m_wiredDevices); 169 | 170 | address.SetBase ("10.1.2.0", "255.255.255.0"); 171 | address.Assign (m_staDevices); 172 | address.Assign (m_apDevices); 173 | 174 | Ipv4GlobalRoutingHelper::PopulateRoutingTables (); 175 | 176 | // Disable tc now, some bug in ns3 cause extra delay 177 | TrafficControlHelper tch; 178 | tch.Uninstall (m_wiredDevices); 179 | tch.Uninstall (m_staDevices); 180 | tch.Uninstall (m_apDevices); 181 | } 182 | 183 | ApplicationContainer WifiTopo::InstallTCP (const std::string& flowId, 184 | uint32_t nodeId, 185 | uint16_t serverPort, 186 | bool downstream) 187 | { 188 | NS_ASSERT (nodeId < m_wifiStaNodes.GetN ()); 189 | 190 | auto sender = m_wifiStaNodes.Get (nodeId); 191 | auto receiver = m_wiredNodes.Get (1); 192 | 193 | if (downstream) { 194 | std::swap (sender, receiver); 195 | } 196 | 197 | return Topo::InstallTCP (flowId, 198 | sender, 199 | receiver, 200 | serverPort); 201 | } 202 | 203 | ApplicationContainer WifiTopo::InstallCBR (uint32_t nodeId, 204 | uint16_t serverPort, 205 | uint64_t bitrate, 206 | uint32_t packetSize, 207 | bool downstream) 208 | { 209 | NS_ASSERT (nodeId < m_wifiStaNodes.GetN ()); 210 | 211 | auto sender = m_wifiStaNodes.Get (nodeId); 212 | auto receiver = m_wiredNodes.Get (1); 213 | if (downstream) { 214 | std::swap (sender, receiver); 215 | } 216 | 217 | return Topo::InstallCBR (sender, 218 | receiver, 219 | serverPort, 220 | bitrate, 221 | packetSize); 222 | } 223 | 224 | 225 | ApplicationContainer WifiTopo::InstallRMCAT (const std::string& flowId, 226 | uint32_t nodeId, 227 | uint16_t serverPort, 228 | bool downstream) 229 | { 230 | NS_ASSERT (nodeId < m_wifiStaNodes.GetN ()); 231 | 232 | auto sender = m_wifiStaNodes.Get (nodeId); 233 | auto receiver = m_wiredNodes.Get (1); 234 | if (downstream) { 235 | std::swap (sender, receiver); 236 | } 237 | 238 | return Topo::InstallRMCAT (flowId, 239 | sender, 240 | receiver, 241 | serverPort); 242 | } 243 | 244 | Vector WifiTopo::GetPosition (uint32_t idx) const 245 | { 246 | auto node = m_wifiStaNodes.Get (idx); 247 | auto mobility = node->GetObject (); 248 | return mobility->GetPosition (); 249 | } 250 | 251 | void WifiTopo::SetPosition (uint32_t idx, const Vector& position) 252 | { 253 | auto node = m_wifiStaNodes.Get (idx); 254 | auto mobility = node->GetObject (); 255 | mobility->SetPosition (position); 256 | } 257 | 258 | void WifiTopo::EnableWifiLogComponents () 259 | { 260 | LogLevel l = (LogLevel)(LOG_LEVEL_ALL|LOG_PREFIX_TIME|LOG_PREFIX_NODE); 261 | 262 | const char* components[] = { 263 | // For debugging packet loss 264 | "UdpSocketImpl", 265 | "Ipv4L3Protocol", 266 | "Ipv4Interface", 267 | "ArpL3Protocol", 268 | "ArpCache", 269 | // Wifi-related 270 | "WifiNetDevice", 271 | "Aarfcd", 272 | "AdhocWifiMac", 273 | "AmrrWifiRemoteStation", 274 | "ApWifiMac", 275 | "ArfWifiManager", 276 | "Cara", 277 | "DcaTxop", 278 | "DcfManager", 279 | "DsssErrorRateModel", 280 | "EdcaTxopN", 281 | "InterferenceHelper", 282 | "Jakes", 283 | "MacLow", 284 | "MacRxMiddle", 285 | "MsduAggregator", 286 | "MsduStandardAggregator", 287 | "NistErrorRateModel", 288 | "OnoeWifiRemoteStation", 289 | "PropagationLossModel", 290 | "RegularWifiMac", 291 | "RraaWifiManager", 292 | "StaWifiMac", 293 | "SupportedRates", 294 | "WifiChannel", 295 | "WifiPhyStateHelper", 296 | "WifiPhy", 297 | "WifiRemoteStationManager", 298 | "YansErrorRateModel", 299 | "YansWifiChannel", 300 | "YansWifiPhy", 301 | }; 302 | 303 | for (size_t i = 0; i < sizeof (components) / sizeof (components[0]); i++) { 304 | LogComponentEnable (components[i], l); 305 | } 306 | } 307 | 308 | } 309 | -------------------------------------------------------------------------------- /model/topo/wifi-topo.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Wifi network topology setup for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #ifndef WIFI_TOPO_H 29 | #define WIFI_TOPO_H 30 | 31 | #include "topo.h" 32 | 33 | namespace ns3 { 34 | 35 | /** 36 | * Class implementing the network Topology for rmcat Wifi test cases. 37 | * The diagram below depicts the topology and the IP subnets configured. 38 | * 39 | * Infrastructure Wifi Network Topology 40 | * 41 | * <===== upstream direction ========= 42 | * 43 | * Wifi 10.1.2.0 44 | * APs 45 | * * * * ... * 46 | * 10.1.1.0 | | | ... | 47 | * n1 --------------- n2 n3 n4 ... n0 48 | * point-to-point 49 | * 50 | * ======= downstream direction =====> 51 | * 52 | */ 53 | 54 | class WifiTopo: public Topo 55 | { 56 | public: 57 | /** Class destructor */ 58 | virtual ~WifiTopo (); 59 | 60 | /** 61 | * Build the wifi rmcat topology with the attributes passed 62 | * 63 | * The default euclidean position of the AP is (0, 0, 0). 64 | * The default euclidean position of all wifi station nodes is (1, 0, 0), 65 | * in meters 66 | * 67 | * @param [in] bandwidthBps Bandwidth of the wired link (in bps) 68 | * @param [in] msDelay Propagation delay of the wired link (in ms) 69 | * @param [in] msQDelay Capacity of the ingress queue at the wired link 70 | * (in ms), also maximum delay attribute of the wifi 71 | * max queue 72 | * @param [in] nWifi Number of wifi nodes, not counting the AP (i.e., 73 | * wifi stations) 74 | * @param [in] standard Wifi standard to use. See #WifiPhyStandard . 75 | * @param [in] rateMode Wifi transmission mode. 76 | * dynamic rateMode will use Minstrel rate adaptation algorithm 77 | * constant rateMode for 802.11 abg, Configure80211* function, such as "DsssRate11Mbps" 78 | * @see https://www.nsnam.org/doxygen/yans-wifi-phy_8cc_source.html 79 | * constant rateMode for 802.11 n/ac, such as "HtMcs23" 80 | * @see https://www.nsnam.org/doxygen/wifi-phy_8cc_source.html#l01627, 81 | * @see http://mcsindex.com/ for data rate corresponding to specific mcsidx 82 | * @see http://www.digitalairwireless.com/wireless-blog/recent/demystifying-modulation-and-coding-scheme-index-values.html 83 | * for details 84 | */ 85 | void Build (uint64_t bandwidthBps, 86 | uint32_t msDelay, 87 | uint32_t msQDelay, 88 | uint32_t nWifi, 89 | WifiPhyStandard standard, 90 | WifiMode rateMode); 91 | 92 | /** 93 | * Install a one-way TCP flow in a pair of nodes: a wifi node and a 94 | * wired node 95 | * 96 | * @param [in] flowId A string denoting the flow's id. Useful for 97 | * logging and plotting 98 | * @param [in] nodeId index of the wifi node where the TCP flow is 99 | * to be installed. 100 | * @param [in] serverPort TCP port where the server TCP application is 101 | * to listen on 102 | * @param [in] downstream If true, the wifi node is to act as receiver 103 | * (downstream direction); if false, the wifi node 104 | * is to act as sender (upstream direction) 105 | * 106 | * @retval A container with the two applications (sender and receiver) 107 | */ 108 | ApplicationContainer InstallTCP (const std::string& flowId, 109 | uint32_t nodeId, 110 | uint16_t serverPort, 111 | bool downstream); 112 | 113 | /** 114 | * Install a one-way constant bitrate (CBR) flow over UDP in a pair of nodes: 115 | * a wifi node and a wired node 116 | * 117 | * @param [in] nodeId index of the wifi node where the CBR-over-UDP 118 | * flow is to be installed. 119 | * @param [in] serverPort UDP port where the receiver CBR UDP application 120 | * is to receive datagrams 121 | * @param [in] bitrate Bitrate (constant) at which the flow is to operate 122 | * @param [in] packetSize Size of of the data to be shipped in each 123 | * datagram 124 | * @param [in] downstream If true, the wifi node is to act as receiver 125 | * (downstream direction); if false, the wifi node 126 | * is to act as sender (upstream direction) 127 | * 128 | * @retval A container with the two applications (sender and receiver) 129 | */ 130 | ApplicationContainer InstallCBR (uint32_t nodeId, 131 | uint16_t serverPort, 132 | uint64_t bitrate, 133 | uint32_t packetSize, 134 | bool downstream); 135 | 136 | /** 137 | * Install a one-way RMCAT flow in a pair of nodes: a wifi node and a 138 | * wired node 139 | * 140 | * @param [in] flowId A string denoting the flow's id. Useful for 141 | * logging and plotting 142 | * @param [in] nodeId index of the wifi node where the RMCAT flow 143 | * is to be installed. 144 | * @param [in] serverPort UDP port where the #RmcatReceiver application 145 | * is to receive media packets 146 | * @param [in] downstream If true, the wifi node is to act as receiver 147 | * (downstream direction); if false, the wifi node 148 | * is to act as sender (upstream direction) 149 | * 150 | * @retval A container with the two applications (sender and receiver) 151 | */ 152 | ApplicationContainer InstallRMCAT (const std::string& flowId, 153 | uint32_t nodeId, 154 | uint16_t serverPort, 155 | bool downstream); 156 | 157 | /** 158 | * Get the current euclidean position of a wifi station node 159 | * 160 | * @param [in] idx Index of the wifi node 161 | * @retval A vector object containing the wifi station's (x, y, z) 162 | * coordinates 163 | */ 164 | Vector GetPosition (uint32_t idx) const; 165 | 166 | /** 167 | * Set the euclidean position of a wifi station node 168 | * 169 | * @param [in] idx Index of the wifi node 170 | * @param [in] position New position of the wifi node 171 | */ 172 | void SetPosition (uint32_t idx, const Vector& position); 173 | 174 | private: 175 | static void EnableWifiLogComponents (); 176 | 177 | protected: 178 | WifiHelper m_wifi; 179 | NodeContainer m_wiredNodes; 180 | NodeContainer m_wifiStaNodes; 181 | NodeContainer m_wifiApNode; 182 | NetDeviceContainer m_wiredDevices; 183 | NetDeviceContainer m_staDevices; 184 | NetDeviceContainer m_apDevices; 185 | }; 186 | 187 | } 188 | 189 | #endif /* WIFI_TOPO_H */ 190 | -------------------------------------------------------------------------------- /model/topo/wired-topo.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Wired network topology setup implementation for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #include "wired-topo.h" 29 | 30 | namespace ns3 { 31 | 32 | WiredTopo::WiredTopo () 33 | : m_numApps{0}, 34 | m_bufSize{0} 35 | {} 36 | 37 | WiredTopo::~WiredTopo () 38 | {} 39 | 40 | void WiredTopo::Build (uint64_t bandwidthBps, uint32_t msDelay, uint32_t msQDelay) 41 | { 42 | // Set up bottleneck link 43 | m_bottleneckNodes.Create (2); 44 | PointToPointHelper bottleneckLinkHlpr; 45 | bottleneckLinkHlpr.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (bandwidthBps))); 46 | 47 | // We set the the bottleneck link's propagation delay to 90% of the total delay 48 | bottleneckLinkHlpr.SetChannelAttribute ("Delay", TimeValue (MicroSeconds (msDelay * 1000 * 9 / 10))); 49 | m_bufSize = bandwidthBps * msQDelay / 8 / 1000; 50 | // At least one full packet with default size must fit 51 | NS_ASSERT (m_bufSize >= DEFAULT_PACKET_SIZE + IPV4_UDP_OVERHEAD); 52 | 53 | bottleneckLinkHlpr.SetQueue ("ns3::DropTailQueue", 54 | "Mode", StringValue ("QUEUE_MODE_BYTES"), 55 | "MaxBytes", UintegerValue (m_bufSize)); 56 | 57 | m_bottleneckDevices = bottleneckLinkHlpr.Install (m_bottleneckNodes); 58 | 59 | //Uncomment the line below to ease troubleshooting 60 | //bottleneckLinkHlpr.EnablePcapAll ("rmcat-wired-capture", true); 61 | 62 | m_inetStackHlpr.Install (m_bottleneckNodes); 63 | Ipv4AddressHelper address; 64 | address.SetBase ("12.0.1.0", "255.255.255.0"); 65 | address.Assign (m_bottleneckDevices); 66 | 67 | // Set up helpers for applications 68 | NS_ASSERT (m_numApps == 0); 69 | m_appLinkHlpr.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (1u << 30))); // 1 Gbps 70 | 71 | // We set the application link's propagation delay (one on each side of the bottleneck) 72 | // to 5% of the total delay 73 | m_appLinkHlpr.SetChannelAttribute ("Delay", TimeValue (MicroSeconds (msDelay * 1000 * 5 / 100))); 74 | 75 | // Set queue to drop-tail, but don't care much about buffer size 76 | m_appLinkHlpr.SetQueue ("ns3::DropTailQueue", 77 | "Mode", StringValue ("QUEUE_MODE_BYTES"), 78 | "MaxBytes", UintegerValue (m_bufSize)); 79 | 80 | // Disable tc now, some bug in ns3 causes extra delay 81 | TrafficControlHelper tch; 82 | tch.Uninstall (m_bottleneckDevices); 83 | 84 | Packet::EnablePrinting (); 85 | } 86 | 87 | ApplicationContainer WiredTopo::InstallTCP (const std::string& flowId, 88 | uint16_t serverPort, 89 | bool newNode) 90 | { 91 | auto appNodes = SetupAppNodes (0, newNode); 92 | auto sender = appNodes.Get (0); 93 | auto receiver = appNodes.Get (1); 94 | 95 | return Topo::InstallTCP (flowId, sender, receiver, serverPort); 96 | } 97 | 98 | ApplicationContainer WiredTopo::InstallCBR (uint16_t serverPort, 99 | uint32_t bitrate, 100 | uint32_t packetSize, 101 | bool forward) 102 | { 103 | // At least one packet must fit in the bottleneck link's queue 104 | NS_ASSERT (m_bufSize >= packetSize + IPV4_UDP_OVERHEAD); 105 | 106 | auto appNodes = SetupAppNodes (0, true); 107 | auto sender = appNodes.Get (1); 108 | auto receiver = appNodes.Get (0); 109 | if (forward) { 110 | std::swap (sender, receiver); 111 | } 112 | 113 | return Topo::InstallCBR (sender, 114 | receiver, 115 | serverPort, 116 | bitrate, 117 | packetSize); 118 | } 119 | 120 | ApplicationContainer WiredTopo::InstallRMCAT (const std::string& flowId, 121 | uint16_t serverPort, 122 | uint32_t pDelayMs, 123 | bool forward) 124 | { 125 | auto appNodes = SetupAppNodes (pDelayMs, true); 126 | 127 | auto sender = appNodes.Get (1); 128 | auto receiver = appNodes.Get (0); 129 | if (forward) { 130 | std::swap (sender, receiver); 131 | } 132 | 133 | return Topo::InstallRMCAT (flowId, 134 | sender, 135 | receiver, 136 | serverPort); 137 | } 138 | 139 | void WiredTopo::SetupAppNode (Ptr node, int bottleneckIdx, uint32_t pDelayMs) 140 | { 141 | NodeContainer nodes (node, m_bottleneckNodes.Get (bottleneckIdx)); 142 | auto devices = m_appLinkHlpr.Install (nodes); 143 | if (pDelayMs > 0) { 144 | Ptr channel = DynamicCast (devices.Get (0)->GetChannel ()); 145 | TimeValue delay; 146 | channel->GetAttribute ("Delay", delay); 147 | const uint64_t us = delay.Get ().GetMicroSeconds (); 148 | // variable us is 5% of the total base delay 149 | const uint64_t total = us * 100 / 5; 150 | NS_ASSERT (us <= total); 151 | NS_ASSERT (total - us <= pDelayMs * 1000); 152 | delay.Set (MicroSeconds (pDelayMs * 1000 - (total - us))); 153 | channel->SetAttribute ("Delay", delay); 154 | } 155 | Ipv4AddressHelper address; 156 | std::ostringstream stringStream; 157 | const unsigned x = (m_numApps + 1) / 256; 158 | const unsigned y = (m_numApps + 1) % 256; 159 | stringStream << (10 + bottleneckIdx) << "." << x << "." << y << ".0"; 160 | address.SetBase (stringStream.str ().c_str (), "255.255.255.0"); 161 | address.Assign (devices); 162 | 163 | TrafficControlHelper tch; 164 | tch.Uninstall (devices); 165 | 166 | //Uncomment the lines below to ease troubleshooting 167 | //if (bottleneckIdx == 0) { 168 | // std::ostringstream stringStream0; 169 | // stringStream0 << "rmcat-wired-app-capture" << m_numApps; 170 | // m_appLinkHlpr.EnablePcap (stringStream0.str (), devices, true); 171 | //} 172 | } 173 | 174 | NodeContainer WiredTopo::SetupAppNodes (uint32_t pDelayMs, bool newNode) 175 | { 176 | if (newNode) { 177 | NodeContainer appNodes; 178 | appNodes.Create (2); 179 | m_inetStackHlpr.Install (appNodes); 180 | SetupAppNode (appNodes.Get (0), 0, pDelayMs); 181 | SetupAppNode (appNodes.Get (1), 1, 0); 182 | ++m_numApps; 183 | m_appNodes = appNodes; 184 | } 185 | // The first time we set up a flow, newNode must be true 186 | NS_ASSERT (m_numApps > 0); 187 | return m_appNodes; 188 | } 189 | 190 | } 191 | -------------------------------------------------------------------------------- /model/topo/wired-topo.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Wired network topology setup for rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #ifndef WIRED_TOPO_H 29 | #define WIRED_TOPO_H 30 | 31 | #include "topo.h" 32 | 33 | namespace ns3 { 34 | 35 | /** 36 | * Class implementing the network Topology for rmcat wired test cases. 37 | * The diagram below depicts the topology and the IP subnets configured. 38 | * 39 | * +----+ 10.0.1.0 11.0.1.0 +----+ 40 | * | l1 +-----------+ +-----------+ r1 | 41 | * +----+ | | +----+ 42 | * | | 43 | * +----+ 10.0.2.0 +---+ 12.0.1.0 +---+ 11.0.2.0 +----+ 44 | * | l2 +----------+ A +------------+ B +----------+ r2 | 45 | * +----+ +---+ +---+ +----+ 46 | * | | 47 | * ... | | ... 48 | * | | 49 | * +----+ 10.x.y.0 | | 11.x.y.0 +----+ 50 | * | ln +-----------+ +-----------+ rn | 51 | * +----+ +----+ 52 | * where n = 256 * x + y 53 | */ 54 | 55 | class WiredTopo: public Topo 56 | { 57 | public: 58 | /** Class constructor */ 59 | WiredTopo (); 60 | 61 | /** Class destructor */ 62 | virtual ~WiredTopo (); 63 | 64 | /** 65 | * Build the wired rmcat topology with the attributes passed 66 | * 67 | * @param [in] bandwidthBps Bandwidth of the bottleneck link (in bps) 68 | * @param [in] msDelay Total propagation delay (in ms) between left and 69 | * right nodes 70 | * @param [in] msQDelay Capacity of the queue at the bottleneck 71 | * link (in ms) 72 | */ 73 | void Build (uint64_t bandwidthBps, uint32_t msDelay, uint32_t msQDelay); 74 | 75 | /** 76 | * Install a one-way bulk TCP flow in a pair of (left-to-right) nodes 77 | * 78 | * @param [in] flowId A string denoting the flow's id. Useful for logging 79 | * and plotting 80 | * @param [in] serverPort TCP port where the server bulk TCP application is 81 | * to listen 82 | * @param [in] newNode If true, the (sender/receiver) bulk TCP applications 83 | * will be installed in a newly created (left-right) 84 | * node pair; if false, the previously created node 85 | * pair will be reused 86 | * 87 | * @retval A container with the two applications (sender and receiver) 88 | */ 89 | ApplicationContainer InstallTCP (const std::string& flowId, 90 | uint16_t serverPort, 91 | bool newNode); 92 | 93 | /** 94 | * Install a one-way constant bitrate (CBR) UDP flow in a pair of 95 | * (left-right) nodes 96 | * 97 | * @param [in] serverPort UDP port where the receiver CBR UDP application 98 | * is to receive datagrams 99 | * @param [in] bitrate Bitrate (constant) at which the flow is to operate 100 | * @param [in] packetSize Size of of the data to be shipped in each datagram 101 | * @param [in] forward direction of the flow. 102 | * If true (forward direction), the left node (ID=0) 103 | * will act as sender and the right node (ID=1) will 104 | * act as receiver; if false (backward direction), 105 | * the roles are swapped. 106 | * 107 | * @retval A container with the two applications (sender and receiver) 108 | */ 109 | ApplicationContainer InstallCBR (uint16_t serverPort, 110 | uint32_t bitrate = 0, 111 | uint32_t packetSize = DEFAULT_PACKET_SIZE, 112 | bool forward = true); 113 | 114 | /** 115 | * Install a one-way rmcat flow in a pair of (left-right) nodes 116 | * 117 | * @param [in] idx Index of this rmcat flow, in order to distinguish it 118 | * from other flows in the logs and plots 119 | * @param [in] serverPort UDP port where the #RmcatReceiver application 120 | * is to receive media packets 121 | * @param [in] pDelayMs Custom propagation delay between the pair of nodes 122 | * @param [in] forward direction of flow. 123 | * If true (forward direction), the left node (ID=0) 124 | * will act as sender and the right node (ID=1) will 125 | * act as receiver; if false (backward direction), 126 | * the roles are swapped. 127 | * 128 | * @retval A container with the two applications (sender and receiver) 129 | */ 130 | ApplicationContainer InstallRMCAT (const std::string& flowId, 131 | uint16_t serverPort, 132 | uint32_t pDelayMs, 133 | bool forward); 134 | 135 | private: 136 | void SetupAppNode (Ptr node, int subnet, uint32_t pDelayMs); 137 | NodeContainer SetupAppNodes (uint32_t pDelayMs, bool newNode); 138 | 139 | protected: 140 | unsigned m_numApps; 141 | uint32_t m_bufSize; 142 | NodeContainer m_bottleneckNodes; 143 | NodeContainer m_appNodes; // Last application node pair created 144 | NetDeviceContainer m_bottleneckDevices; 145 | InternetStackHelper m_inetStackHlpr; 146 | PointToPointHelper m_appLinkHlpr; 147 | }; 148 | 149 | } 150 | 151 | #endif /* WIRED_TOPO_H */ 152 | -------------------------------------------------------------------------------- /test/rmcat-common-test.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Base class implementation for testing rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #include "rmcat-common-test.h" 29 | #include "ns3/log.h" 30 | 31 | using namespace ns3; 32 | 33 | /* Base class of RMCAT test cases: constructor */ 34 | RmcatTestCase::RmcatTestCase (uint64_t capacity, 35 | uint32_t delay, 36 | uint32_t qdelay, 37 | std::string desc) 38 | : TestCase{desc} 39 | , m_debug{false} 40 | , m_sb{NULL} 41 | , m_capacity{capacity} // bottleneck capacity 42 | , m_delay{delay} // one-way propagation delay 43 | , m_qdelay{qdelay} // bottleneck queue depth 44 | { 45 | 46 | // name of log file same as test case descriptions 47 | std::stringstream ss; 48 | ss << desc << ".log"; 49 | m_logfile = ss.str (); 50 | } 51 | 52 | void RmcatTestCase::DoSetup () 53 | { 54 | // configure logging level 55 | LogLevel l = (LogLevel)(LOG_LEVEL_INFO | 56 | LOG_PREFIX_TIME | 57 | LOG_PREFIX_NODE); 58 | LogComponentEnable ("Topo", l); 59 | 60 | if (m_debug) { 61 | LogComponentEnable ("OnOffApplication", l); 62 | LogComponentEnable ("UdpClient", l); 63 | LogComponentEnable ("BulkSendApplication", l); 64 | LogComponentEnable ("V4Ping", l); 65 | LogComponentEnable ("RmcatSender", l); 66 | LogComponentEnable ("RmcatReceiver", l); 67 | } 68 | 69 | // open output file stream and corresponding streaming buffer 70 | // for logging 71 | m_ofs.open (m_logfile.c_str (), std::ios_base::out); 72 | m_sb = std::clog.rdbuf (m_ofs.rdbuf ()); 73 | } 74 | 75 | void RmcatTestCase::DoTeardown () 76 | { 77 | // close up output file stream 78 | std::clog.rdbuf (m_sb); 79 | m_ofs.close (); 80 | } 81 | -------------------------------------------------------------------------------- /test/rmcat-common-test.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Base classes declaration for testing rmcat ns3 module. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #ifndef RMCAT_COMMON_TEST_H 29 | #define RMCAT_COMMON_TEST_H 30 | 31 | #include "ns3/test.h" 32 | #include 33 | 34 | /* default simulation parameters */ 35 | const uint32_t RMCAT_TC_BG_TSTART = 40; 36 | const uint32_t RMCAT_TC_BG_TFINIS = 80; 37 | const uint32_t RMCAT_TC_SIMTIME = 120; // default simulation duration 38 | 39 | #define RMCAT_TC_TCP_RECVBUF_SIZE 524288 * 2 40 | 41 | const uint32_t RMCAT_TC_UDP_PKTSIZE = 1000; 42 | const uint32_t RMCAT_TC_TCP_PKTSIZE = 1000; 43 | const uint32_t RMCAT_TC_RINIT = 150 * (1u << 10); // R_init: 150 Kbps 44 | const uint32_t RMCAT_TC_RMIN = 150 * (1u << 10); // R_min: 150 Kbps 45 | const uint32_t RMCAT_TC_RMAX = 1500 * (1u << 10); // R_max: 1500 Kbps 46 | 47 | // default port assignment: base numbers 48 | const uint32_t RMCAT_TC_CBR_UDP_PORT = 4000; 49 | const uint32_t RMCAT_TC_LONG_TCP_PORT = 6000; 50 | const uint32_t RMCAT_TC_SHORT_TCP_PORT = 7000; 51 | const uint32_t RMCAT_TC_RMCAT_PORT = 8000; 52 | 53 | // TODO (deferred): These two values should be set to 0 to match eval-test-06 draft 54 | const uint32_t RMCAT_TC_SHORT_TCP_TGAP = 10; 55 | const uint32_t RMCAT_TC_SHORT_TCP_MEAN_OFF_TIME = 10; // mean off duration of each short TCP flow: 10 seconds 56 | const uint32_t RMCAT_TC_SHORT_TCP_MIN_FILE_SIZE = 30 * (1u << 10); // minimum file size: 30KB 57 | const uint32_t RMCAT_TC_SHORT_TCP_MAX_FILE_SIZE = 50 * (1u << 10); // minimum file size: 30KB 58 | 59 | /** Base class of RMCAT test cases */ 60 | class RmcatTestCase : public ns3::TestCase 61 | { 62 | public: 63 | /* Constructor */ 64 | RmcatTestCase (uint64_t capacity, // bottleneck capacity (in bps) 65 | uint32_t delay, // one-way propagation delay (in ms) 66 | uint32_t qdelay, // bottleneck queue depth (in ms) 67 | std::string desc); // test case name/description 68 | 69 | virtual void DoSetup (); 70 | virtual void DoTeardown (); 71 | 72 | protected: 73 | 74 | bool m_debug; // debugging mode 75 | 76 | /* Log file of current test case */ 77 | std::string m_logfile; // name of log file 78 | std::ofstream m_ofs; // output file stream 79 | std::streambuf* m_sb; // output stream buffer 80 | 81 | uint64_t m_capacity; // bottleneck capacity (in bps) 82 | uint32_t m_delay; // one-way propagation delay (in ms) 83 | uint32_t m_qdelay; // bottleneck queue depth (in ms) 84 | }; 85 | 86 | #endif /* RMCAT_COMMON_TEST_H */ 87 | -------------------------------------------------------------------------------- /test/rmcat-wifi-test-case.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Common template for rmcat wifi test cases. 21 | * 22 | * This file contains implementation of the 23 | * RmcatWifiTestCase class. It defines the 24 | * common template for individual rmcat-wifi 25 | * test cases as specified in Section 4 of the 26 | * following IETF draft: 27 | * 28 | * Evaluation Test Cases for Interactive Real-Time 29 | * Media over Wireless Networks 30 | * https://tools.ietf.org/html/draft-ietf-rmcat-wireless-tests-04 31 | * 32 | * @version 0.1.1 33 | * @author Jiantao Fu 34 | * @author Sergio Mena 35 | * @author Xiaoqing Zhu 36 | */ 37 | 38 | #include "rmcat-wifi-test-case.h" 39 | 40 | NS_LOG_COMPONENT_DEFINE ("RmcatSimTestWifi"); 41 | 42 | /* 43 | * Implement common procedures in setting up a 44 | * rmcat-wifi test case: 45 | * -- configuration of network topology, including 46 | * number of wired and wireless nodes; 47 | * -- configuration of capacity and propagation 48 | * delay of the wired connection 49 | * -- configuration of PHY- and MAC-layer parameters 50 | * for the wireless connections 51 | * -- configuration of traversing traffic flows 52 | * in terms of traffic type (i.e., RMCAT/TCP/UDP), 53 | * arrival and departure patterns 54 | */ 55 | 56 | /* Constructor */ 57 | RmcatWifiTestCase::RmcatWifiTestCase (uint64_t capacity, // wired link capacity (in bps) 58 | uint32_t pdelay, // wired link forward propagation delay (in ms) 59 | uint32_t qdelay, // wired link queue depth (in ms) 60 | std::string desc) // test case name/description 61 | : RmcatTestCase{capacity, pdelay, qdelay, desc} 62 | , m_nWifi{2} // default: a pair of bi-directional RMCAT flows 63 | , m_nDnRMCAT{1} 64 | , m_nUpRMCAT{1} 65 | , m_nDnTCP{0} 66 | , m_nUpTCP{0} 67 | , m_nDnCBR{0} 68 | , m_nUpCBR{0} 69 | , m_rCBR{0} 70 | , m_simTime{RMCAT_TC_SIMTIME} 71 | , m_codecType{SYNCODEC_TYPE_FIXFPS} 72 | , m_phyMode{WifiMode ("HtMcs11")} 73 | {} 74 | 75 | 76 | /** 77 | * Configure RMCAT flows in terms of: 78 | * -- direction (downlink/uplink) 79 | * -- arrival/departure times 80 | */ 81 | void RmcatWifiTestCase::SetRMCATFlows (size_t numFlows, 82 | const std::vector& startTimes, 83 | const std::vector& endTimes, 84 | bool fwd) 85 | { 86 | if (fwd) { 87 | // configure downlink flows 88 | m_nDnRMCAT = numFlows; 89 | m_startTDnRMCAT = startTimes; 90 | m_finisTDnRMCAT = endTimes; 91 | } else { 92 | // configure uplink flows 93 | m_nUpRMCAT = numFlows; 94 | m_startTUpRMCAT = startTimes; 95 | m_finisTUpRMCAT = endTimes; 96 | } 97 | } 98 | 99 | /** 100 | * Configure long lived TCP background flows 101 | * in terms of: 102 | * -- direction (downlink/uplink) 103 | * -- arrival/departure times 104 | */ 105 | void RmcatWifiTestCase::SetTCPFlows (size_t numFlows, 106 | const std::vector& startTimes, 107 | const std::vector& endTimes, 108 | bool fwd) 109 | { 110 | if (fwd) { 111 | // configure downlink flows 112 | m_nDnTCP = numFlows; 113 | m_startTDnTCP = startTimes; 114 | m_finisTDnTCP = endTimes; 115 | } else { 116 | // configure uplink flows 117 | m_nUpTCP = numFlows; 118 | m_startTUpTCP = startTimes; 119 | m_finisTUpTCP = endTimes; 120 | } 121 | } 122 | 123 | /* 124 | * Configure CBR-over-UDP background flows 125 | * in terms of: 126 | * -- direction (downlink/uplink) 127 | * -- arrival/departure times 128 | */ 129 | void RmcatWifiTestCase::SetUDPFlows (size_t numFlows, 130 | const std::vector& startTimes, 131 | const std::vector& endTimes, 132 | bool fwd) 133 | { 134 | if (fwd) { 135 | // configure downlink flows 136 | m_nDnCBR = numFlows; 137 | m_startTDnCBR = startTimes; 138 | m_finisTDnCBR = endTimes; 139 | } else { 140 | // configure uplink flows 141 | m_nUpCBR = numFlows; 142 | m_startTUpCBR = startTimes; 143 | m_finisTUpCBR = endTimes; 144 | } 145 | } 146 | 147 | 148 | /** 149 | * Instantiate RMCAT flows 150 | */ 151 | void RmcatWifiTestCase::SetUpRMCAT (std::vector >& send, 152 | bool fwd) 153 | { 154 | size_t numFlows = fwd ? m_nDnRMCAT : m_nUpRMCAT; 155 | const uint32_t basePort = RMCAT_TC_RMCAT_PORT + (fwd ? 0: 1000); 156 | const auto nRmcatBase = (fwd ? 0 : m_nDnRMCAT); 157 | std::stringstream ss0; 158 | if (fwd) { 159 | ss0 << "rmcatDn_"; 160 | } else { 161 | ss0 << "rmcatUp_"; 162 | } 163 | 164 | for (uint32_t i = 0; i < numFlows; i++) { 165 | std::stringstream ss; 166 | ss << ss0.str () << i; 167 | 168 | ApplicationContainer rmcatApps = m_topo.InstallRMCAT (ss.str (), // flowID 169 | nRmcatBase + i, // nodeID 170 | basePort + i * 2, // port # , 171 | fwd); // direction 172 | 173 | send[i] = DynamicCast (rmcatApps.Get (0)); 174 | send[i]->SetCodecType (m_codecType); 175 | send[i]->SetRinit (RMCAT_TC_RINIT); 176 | send[i]->SetRmin (RMCAT_TC_RMIN); 177 | send[i]->SetRmax (RMCAT_TC_RMAX); 178 | send[i]->SetStartTime (Seconds (0)); 179 | send[i]->SetStopTime (Seconds (m_simTime-1)); 180 | } 181 | 182 | // configure start/end times for downlink flows 183 | if (fwd && m_startTDnRMCAT.size () > 0) { 184 | NS_ASSERT (m_startTDnRMCAT.size () == numFlows); 185 | NS_ASSERT (m_finisTDnRMCAT.size () == numFlows); 186 | for (uint32_t i = 0; i < numFlows; i++) { 187 | send[i]->SetStartTime (Seconds (m_startTDnRMCAT[i])); 188 | send[i]->SetStopTime (Seconds (m_finisTDnRMCAT[i])); 189 | } 190 | } 191 | 192 | // configure start/end times for uplink flows 193 | if (!fwd && m_startTUpRMCAT.size () > 0) { 194 | NS_ASSERT (m_startTUpRMCAT.size () == numFlows); 195 | NS_ASSERT (m_finisTUpRMCAT.size () == numFlows); 196 | for (uint32_t i = 0; i < numFlows; i++) { 197 | send[i]->SetStartTime (Seconds (m_startTUpRMCAT[i])); 198 | send[i]->SetStopTime (Seconds (m_finisTUpRMCAT[i])); 199 | } 200 | } 201 | } 202 | 203 | /** Instantiate long lived TCP background flows */ 204 | void RmcatWifiTestCase::SetUpTCP (std::vector >& tcpSend, 205 | bool fwd) 206 | { 207 | size_t numFlows = fwd ? m_nDnTCP : m_nUpTCP; 208 | const uint32_t basePort = RMCAT_TC_LONG_TCP_PORT + (fwd ? 0: 1000); 209 | const auto nTcpBase = m_nDnRMCAT+m_nUpRMCAT+ (fwd? 0:m_nDnTCP); 210 | 211 | std::stringstream ss0; 212 | if (fwd) { 213 | ss0 << "tcpDn_"; 214 | } else { 215 | ss0 << "tcpUp_"; 216 | } 217 | 218 | std::vector > tcpRecv (numFlows); 219 | 220 | for (uint32_t i = 0; i < numFlows; i++) { 221 | std::stringstream ss; 222 | ss << ss0.str () << i; 223 | 224 | auto tcpApps = m_topo.InstallTCP (ss.str (), // flow description 225 | nTcpBase+i, // node ID for server/client 226 | basePort + 2 * i, // server port 227 | fwd); 228 | 229 | tcpSend[i] = DynamicCast (tcpApps.Get (0)); 230 | tcpSend[i]->SetStartTime (Seconds (RMCAT_TC_BG_TSTART)); 231 | tcpSend[i]->SetStopTime (Seconds (RMCAT_TC_BG_TFINIS)); 232 | tcpRecv[i] = DynamicCast (tcpApps.Get (1)); 233 | tcpRecv[i]->SetStartTime (Seconds (RMCAT_TC_BG_TSTART)); 234 | tcpRecv[i]->SetStopTime (Seconds (RMCAT_TC_BG_TFINIS)); 235 | } 236 | 237 | // configure start/end times for downlink flows 238 | if (fwd && m_startTDnTCP.size () > 0) { 239 | NS_ASSERT (m_startTDnTCP.size () == numFlows); 240 | NS_ASSERT (m_finisTDnTCP.size () == numFlows); 241 | for (uint32_t i = 0; i < numFlows; i++) { 242 | tcpSend[i]->SetStartTime (Seconds (m_startTDnTCP[i])); 243 | tcpSend[i]->SetStopTime (Seconds (m_finisTDnTCP[i])); 244 | tcpRecv[i]->SetStartTime (Seconds (m_startTDnTCP[i])); 245 | tcpRecv[i]->SetStopTime (Seconds (m_finisTDnTCP[i])); 246 | } 247 | } 248 | 249 | // configure start/end times for uplink flows 250 | if (!fwd && m_startTUpTCP.size () > 0) { 251 | NS_ASSERT (m_startTUpTCP.size () == numFlows); 252 | NS_ASSERT (m_finisTUpTCP.size () == numFlows); 253 | for (uint32_t i = 0; i < numFlows; i++) { 254 | tcpSend[i]->SetStartTime (Seconds (m_startTUpTCP[i])); 255 | tcpSend[i]->SetStopTime (Seconds (m_finisTUpTCP[i])); 256 | tcpRecv[i]->SetStartTime (Seconds (m_startTUpTCP[i])); 257 | tcpRecv[i]->SetStopTime (Seconds (m_finisTUpTCP[i])); 258 | } 259 | } 260 | } 261 | 262 | /** Instantiate CBR-over-UDP background flows */ 263 | void RmcatWifiTestCase::SetUpCBR (std::vector >& cbrSend, 264 | bool fwd) 265 | { 266 | 267 | size_t numFlows = fwd ? m_nDnCBR : m_nUpCBR; 268 | const uint32_t basePort = RMCAT_TC_CBR_UDP_PORT + (fwd ? 0: 1000); 269 | const uint32_t nCbrBase = m_nDnRMCAT+m_nUpRMCAT+m_nDnTCP+m_nUpTCP + (fwd? 0:m_nDnCBR); 270 | for (uint32_t i = 0; i < numFlows; i++) { 271 | ApplicationContainer cbrApps = m_topo.InstallCBR (nCbrBase+i, // node ID 272 | basePort+i, // port #, 273 | m_rCBR, // rate of CBR 274 | RMCAT_TC_UDP_PKTSIZE, 275 | // RMCAT_TC_BG_TSTART, 276 | // RMCAT_TC_BG_TFINIS, 277 | fwd); 278 | 279 | cbrSend[i] = cbrApps.Get (0); 280 | cbrSend[i]->SetStartTime (Seconds (RMCAT_TC_BG_TSTART)); 281 | cbrSend[i]->SetStopTime (Seconds (RMCAT_TC_BG_TFINIS)); 282 | } 283 | 284 | // configure start/end times for downlink flows 285 | if (fwd && m_startTDnCBR.size () > 0) { 286 | NS_ASSERT (m_startTDnCBR.size () == numFlows); 287 | NS_ASSERT (m_finisTDnCBR.size () == numFlows); 288 | for (uint32_t i = 0; i < numFlows; i++) { 289 | cbrSend[i]->SetStartTime (Seconds (m_startTDnCBR[i])); 290 | cbrSend[i]->SetStopTime (Seconds (m_finisTDnCBR[i])); 291 | } 292 | } 293 | 294 | // configure start/end times for uplink flows 295 | if (!fwd && m_startTUpCBR.size () > 0) { 296 | NS_ASSERT (m_startTUpCBR.size () == numFlows); 297 | NS_ASSERT (m_finisTUpCBR.size () == numFlows); 298 | for (uint32_t i = 0; i < numFlows; i++) { 299 | cbrSend[i]->SetStartTime (Seconds (m_startTUpCBR[i])); 300 | cbrSend[i]->SetStopTime (Seconds (m_finisTUpCBR[i])); 301 | } 302 | } 303 | } 304 | 305 | /** 306 | * Inherited DoSetup function: 307 | * -- Build network topology 308 | * -- Enable additional logging 309 | */ 310 | void RmcatWifiTestCase::DoSetup () 311 | { 312 | RmcatTestCase::DoSetup (); 313 | m_nWifi = m_nDnRMCAT + m_nUpRMCAT; 314 | m_nWifi += m_nDnTCP + m_nUpTCP; 315 | m_nWifi += m_nDnCBR + m_nUpCBR; 316 | 317 | m_topo.Build (m_capacity, 318 | m_delay, 319 | m_qdelay, 320 | m_nWifi, 321 | WIFI_PHY_STANDARD_80211n_5GHZ, 322 | m_phyMode); 323 | 324 | ns3::LogComponentEnable ("RmcatSimTestWifi", LOG_LEVEL_INFO); 325 | } 326 | 327 | /** 328 | * Inherited DoRun () function: 329 | * -- Instantiate RMCAT/TCP/UDP flows 330 | * -- Populate routing table 331 | * -- Kickoff simulation 332 | */ 333 | void RmcatWifiTestCase::DoRun () 334 | { 335 | /* Configure downlink/uplink flows */ 336 | std::vector< Ptr > sendDnRMCAT (m_nDnRMCAT); 337 | std::vector< Ptr > sendUpRMCAT (m_nUpRMCAT); 338 | std::vector< Ptr > sendDnTCP (m_nDnTCP); 339 | std::vector< Ptr > sendUpTCP (m_nUpTCP); 340 | std::vector< Ptr > sendDnCBR (m_nDnCBR); 341 | std::vector< Ptr > sendUpCBR (m_nUpCBR); 342 | 343 | SetUpRMCAT (sendDnRMCAT, true); 344 | SetUpRMCAT (sendUpRMCAT, false); 345 | 346 | SetUpTCP (sendDnTCP, true); 347 | SetUpTCP (sendUpTCP, false); 348 | 349 | SetUpCBR (sendDnCBR, true); 350 | SetUpCBR (sendUpCBR, false); 351 | 352 | /* Kick off simulation */ 353 | NS_LOG_INFO ("Run Simulation."); 354 | Simulator::Stop (Seconds (m_simTime)); 355 | Simulator::Run (); 356 | Simulator::Destroy (); 357 | NS_LOG_INFO ("Done."); 358 | } 359 | -------------------------------------------------------------------------------- /test/rmcat-wifi-test-case.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Template for rmcat wifi test cases. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | /* 29 | * This file contains definition of the rmcatWifiTestCase 30 | * class. It defines the template for individual 31 | * rmcat-wifi test cases as specified in 32 | * in Section 4 of the following IETF draft: 33 | * 34 | * Evaluation Test Cases for Interactive Real-Time 35 | * Media over Wireless Networks 36 | * https://tools.ietf.org/html/draft-ietf-rmcat-wireless-tests-04 37 | * 38 | */ 39 | 40 | 41 | #ifndef RMCAT_WIFI_TEST_CASE_H 42 | #define RMCAT_WIFI_TEST_CASE_H 43 | 44 | #include "ns3/wifi-topo.h" 45 | #include "ns3/rmcat-sender.h" 46 | #include "ns3/rmcat-receiver.h" 47 | #include "ns3/rmcat-constants.h" 48 | #include "rmcat-common-test.h" 49 | 50 | using namespace ns3; 51 | 52 | /* 53 | * Defines common configuration parameters of a 54 | * RMCAT wifi test case. 55 | * 56 | * Defines common procedures in setting up a 57 | * test case: 58 | * -- configuration of network topology, including 59 | * number of wired and wireless nodes; 60 | * -- configuration of capacity and propagation 61 | * delay of the wired connection 62 | * -- configuration of PHY- and MAC-layer parameters 63 | * for the wireless connections 64 | * -- configuration of traversing traffic flows 65 | * in terms of traffic type (i.e., RMCAT/TCP/UDP), 66 | * arrival and departure patterns 67 | */ 68 | 69 | class RmcatWifiTestCase : public RmcatTestCase 70 | { 71 | public: 72 | /* Constructor */ 73 | RmcatWifiTestCase (uint64_t capacity, // wired link capacity (in bps) 74 | uint32_t pdelay, // propagation delay (in ms) 75 | uint32_t qdelay, // wired bottleneck queue depth (in ms) 76 | std::string desc); // test case description/name 77 | 78 | virtual void DoSetup (); 79 | virtual void DoRun (); 80 | 81 | /* 82 | * Configure various parameters of 83 | * the test case by passing along function 84 | * input values to member variables 85 | */ 86 | void SetCapacity (uint64_t capacity) {m_capacity = capacity; }; 87 | void SetSimTime (uint32_t simTime) {m_simTime = simTime; }; 88 | void SetCodec (SyncodecType codecType) {m_codecType = codecType; }; 89 | void SetPHYMode (ns3::WifiMode phyMode) {m_phyMode = phyMode; }; 90 | void SetCBRRate (uint64_t rCBR) { m_rCBR = rCBR; }; 91 | 92 | /* configure RMCAT flows and 93 | * their arrival/departure patterns 94 | */ 95 | void SetRMCATFlows (size_t numFlows, 96 | const std::vector& startTimes, 97 | const std::vector& endTimes, 98 | bool fwd); 99 | 100 | /* configure long lived TCP background flows and 101 | * their arrival/departure patterns 102 | */ 103 | void SetTCPFlows (size_t numFlows, 104 | const std::vector& startTimes, 105 | const std::vector& endTimes, 106 | bool fwd); 107 | 108 | /* configure CBR over UDP background flows 109 | * and their arrival/departure patterns 110 | */ 111 | void SetUDPFlows (size_t numFlows, 112 | const std::vector& startTimes, 113 | const std::vector& endTimes, 114 | bool fwd); 115 | 116 | /* Instantiate flows in DoRun () */ 117 | void SetUpRMCAT (std::vector< Ptr >& send, 118 | bool fwd); 119 | 120 | void SetUpTCP (std::vector >& tcpSend, 121 | bool fwd); 122 | 123 | void SetUpCBR (std::vector >& cbrSend, 124 | bool fwd); 125 | 126 | protected: 127 | /* network toplogy configuration */ 128 | WifiTopo m_topo; 129 | 130 | private: 131 | /* Member variables specifying test case configuration */ 132 | uint32_t m_nWifi; // # of wireless nodes in test topology 133 | uint32_t m_nDnRMCAT; // # of downlink RMCAT flows 134 | uint32_t m_nUpRMCAT; // # of uplink RMCAT flows 135 | uint32_t m_nDnTCP; // # of downlink long lived TCP background flows 136 | uint32_t m_nUpTCP; // # of uplink long lived TCP background flows 137 | uint32_t m_nDnCBR; // # of downlink CBR-over-UDP background flows 138 | uint32_t m_nUpCBR; // # of uplink CBR-over-UDP background flows 139 | uint64_t m_rCBR; // rate of each CBR background flow (in bps) 140 | 141 | uint32_t m_simTime; // simulation duration (in seconds) 142 | 143 | // start/end times for each RMCAT flow 144 | std::vector m_startTDnRMCAT; 145 | std::vector m_finisTDnRMCAT; 146 | std::vector m_startTUpRMCAT; 147 | std::vector m_finisTUpRMCAT; 148 | 149 | // start/end times for each long lived TCP flow 150 | std::vector m_startTDnTCP; 151 | std::vector m_finisTDnTCP; 152 | std::vector m_startTUpTCP; 153 | std::vector m_finisTUpTCP; 154 | 155 | // start/end times for each CBR over UDP flow 156 | std::vector m_startTDnCBR; 157 | std::vector m_finisTDnCBR; 158 | std::vector m_startTUpCBR; 159 | std::vector m_finisTUpCBR; 160 | 161 | SyncodecType m_codecType; // traffic source type 162 | ns3::WifiMode m_phyMode; // PHY mode for wireless connections 163 | }; 164 | 165 | #endif /* RMCAT_WIFI_TEST_CASE_H */ 166 | -------------------------------------------------------------------------------- /test/rmcat-wifi-test-suite.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Test suite for rmcat wifi test cases. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | /* 29 | * This file contains implementation of the 30 | * RmcatWifiTestSuite class. It instantiates 31 | * the collection of wifi test cases as described 32 | * in Section 4 of the following IETF draft: 33 | * 34 | * Evaluation Test Cases for Interactive Real-Time 35 | * Media over Wireless Networks 36 | * https://tools.ietf.org/html/draft-ietf-rmcat-wireless-tests-04 37 | * 38 | */ 39 | 40 | #include "rmcat-wifi-test-case.h" 41 | 42 | /* 43 | * Defines common configuration parameters of a 44 | * RMCAT wifi test case. 45 | * 46 | * Implement common procedures in setting up a 47 | * test case: 48 | * -- configuration of network topology, including 49 | * number of wired and wireless nodes; 50 | * -- configuration of capacity and propagation 51 | * delay of the wired connection 52 | * -- configuration of PHY- and MAC-layer parameters 53 | * for the wireless connections 54 | * -- configuration of traversing traffic flows 55 | * in terms of traffic type (i.e., RMCAT/TCP/UDP), 56 | * arrival and departure patterns 57 | */ 58 | 59 | /* 60 | * Defines collection of test cases as specified in 61 | * Section 4 of the rmcat-wireless-tests draft 62 | */ 63 | class RmcatWifiTestSuite : public TestSuite 64 | { 65 | public: 66 | RmcatWifiTestSuite (); 67 | }; 68 | 69 | RmcatWifiTestSuite :: RmcatWifiTestSuite () 70 | : TestSuite{"rmcat-wifi", UNIT} 71 | { 72 | // ---------------- 73 | // Default test case parameters 74 | // ----------------- 75 | uint64_t bw = 1 * (1u << 20); // wired bottleneck capacity: 1Mbps 76 | uint32_t pdel = 50; // forward propagation delay: 50ms 77 | uint32_t qdel = 300; // wired bottleneck queue depth: 300ms 78 | uint64_t rCBR = 300* (1u << 10); // rate of each CBR background flow: 300Kbps 79 | uint32_t simT = 120; // default simulation duration: 120s 80 | uint32_t nRMCAT = 1; // place-holder param for # of RMCAT flows 81 | 82 | ns3::WifiMode phyMode = WifiMode ("HtMcs11"); // default PHY mode 83 | const std::vector t0s; // null time vector as filler 84 | 85 | // Default TCP configuration 86 | Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue ("ns3::TcpNewReno")); 87 | Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (RMCAT_TC_TCP_PKTSIZE)); 88 | Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (0)); 89 | // Uncomment these lines if you wish to modify TCP's send or receive buffer sizes 90 | // Config::SetDefault ("ns3::TcpSocket::RcvBufSize", UintegerValue (RMCAT_TC_TCP_RECVBUF_SIZE)); 91 | // Config::SetDefault ("ns3::TcpSocket::SndBufSize", UintegerValue (RMCAT_TC_TCP_RECVBUF_SIZE)); 92 | 93 | /* start/stop times of background CBR traffic, single flow */ 94 | uint32_t nCBR = 1; 95 | std::vector tstartCBRTC41; // Seconds 96 | std::vector tstopCBRTC41; // Seconds 97 | tstartCBRTC41.push_back (RMCAT_TC_BG_TSTART); // t_start = 40s 98 | tstopCBRTC41.push_back (RMCAT_TC_BG_TFINIS); // t_stop = 80s 99 | 100 | /* start/stop times of background TCP traffic; single flow */ 101 | uint32_t nTCP = 1; 102 | std::vector tstartTCPTC41; // Seconds 103 | std::vector tstopTCPTC41; // Seconds 104 | tstartTCPTC41.push_back (RMCAT_TC_BG_TSTART); // t_start = 40s 105 | tstopTCPTC41.push_back (RMCAT_TC_BG_TFINIS); // t_stop = 80s 106 | 107 | // ----------------------- 108 | // Test Case 4.1.a: Wired Bottleneck; Single downlink RMCAT flow [10|00|00] 109 | // ----------------------- 110 | RmcatWifiTestCase * tc41a = new RmcatWifiTestCase{bw, pdel, qdel, "rmcat-wifi-test-case-4.1.a"}; 111 | tc41a->SetSimTime (simT); 112 | tc41a->SetPHYMode (phyMode); 113 | tc41a->SetRMCATFlows (1, t0s, t0s, true); 114 | tc41a->SetRMCATFlows (0, t0s, t0s, false); 115 | 116 | // ----------------------- 117 | // Test Case 4.1.b: Wired Bottleneck; Single uplink RMCAT flow [01|00|00] 118 | // ----------------------- 119 | RmcatWifiTestCase * tc41b = new RmcatWifiTestCase{bw, pdel, qdel, "rmcat-wifi-test-case-4.1.b"}; 120 | tc41b->SetSimTime (simT); 121 | tc41b->SetPHYMode (phyMode); 122 | tc41b->SetRMCATFlows (0, t0s, t0s, true); 123 | tc41b->SetRMCATFlows (1, t0s, t0s, false); 124 | 125 | // ----------------------- 126 | // Test Case 4.1.c: Wired Bottleneck; Bi-directional RMCAT flows [11|00|00] 127 | // ----------------------- 128 | RmcatWifiTestCase * tc41c = new RmcatWifiTestCase{bw, pdel, qdel, "rmcat-wifi-test-case-4.1.c"}; 129 | tc41c->SetSimTime (simT); 130 | tc41c->SetPHYMode (phyMode); 131 | tc41c->SetRMCATFlows (1, t0s, t0s, true); 132 | tc41c->SetRMCATFlows (1, t0s, t0s, false); 133 | 134 | // ----------------------- 135 | // Test Case 4.1.d: Wired Bottleneck; 136 | // Bi-directional RMCAT flow + one downlink UDP background flow 137 | // [11|10|00] 138 | // ----------------------- 139 | RmcatWifiTestCase * tc41d = new RmcatWifiTestCase{bw, pdel, qdel, "rmcat-wifi-test-case-4.1.d"}; 140 | tc41d->SetSimTime (simT); 141 | tc41d->SetPHYMode (phyMode); 142 | tc41d->SetCBRRate (rCBR); 143 | tc41d->SetRMCATFlows (1, t0s, t0s, true); 144 | tc41d->SetRMCATFlows (1, t0s, t0s, false); 145 | tc41d->SetUDPFlows (nCBR, tstartCBRTC41, tstopCBRTC41, true); 146 | tc41d->SetUDPFlows (0, t0s, t0s, false); 147 | 148 | // ----------------------- 149 | // Test Case 4.1.e: Wired Bottleneck; 150 | // Bi-directional RMCAT flow + one uplink UDP background flow 151 | // [11|01|00] 152 | // ----------------------- 153 | RmcatWifiTestCase * tc41e = new RmcatWifiTestCase{bw, pdel, qdel, "rmcat-wifi-test-case-4.1.e"}; 154 | tc41e->SetSimTime (simT); 155 | tc41e->SetPHYMode (phyMode); 156 | tc41e->SetCBRRate (rCBR); 157 | tc41e->SetRMCATFlows (1, t0s, t0s, true); 158 | tc41e->SetRMCATFlows (1, t0s, t0s, false); 159 | tc41e->SetUDPFlows (0, t0s, t0s, true); 160 | tc41e->SetUDPFlows (nCBR, tstartCBRTC41, tstopCBRTC41, false); 161 | 162 | // ----------------------- 163 | // Test Case 4.1.f: Wired Bottleneck; 164 | // Bi-directional RMCAT flow + one downlink TCP background flow 165 | // [11|00|10] 166 | // ----------------------- 167 | RmcatWifiTestCase * tc41f = new RmcatWifiTestCase{bw, pdel, qdel, "rmcat-wifi-test-case-4.1.f"}; 168 | tc41f->SetSimTime (simT); 169 | tc41f->SetPHYMode (phyMode); 170 | tc41f->SetRMCATFlows (1, t0s, t0s, true); 171 | tc41f->SetRMCATFlows (1, t0s, t0s, false); 172 | 173 | tc41f->SetTCPFlows (nTCP, tstartTCPTC41, tstopTCPTC41, true); 174 | tc41f->SetTCPFlows (0, t0s, t0s, false); 175 | 176 | // ----------------------- 177 | // Test Case 4.1.g: Wired Bottleneck; 178 | // Bi-directional RMCAT flow + one uplink TCP background flow 179 | // [11|00|01] 180 | // ----------------------- 181 | RmcatWifiTestCase * tc41g = new RmcatWifiTestCase{bw, pdel, qdel, "rmcat-wifi-test-case-4.1.g"}; 182 | tc41g->SetSimTime (simT); 183 | tc41g->SetPHYMode (phyMode); 184 | tc41g->SetRMCATFlows (1, t0s, t0s, true); 185 | tc41g->SetRMCATFlows (1, t0s, t0s, false); 186 | 187 | tc41g->SetTCPFlows (0, t0s, t0s, true); 188 | tc41g->SetTCPFlows (nTCP, tstartTCPTC41, tstopTCPTC41, false); 189 | 190 | /* 191 | * Add collection of wired bottleneck test cases 192 | * (Section 4.1. in rmcat-wireless-tests draft) 193 | * to test suite 194 | */ 195 | AddTestCase (tc41a, TestCase::QUICK); 196 | AddTestCase (tc41b, TestCase::QUICK); 197 | AddTestCase (tc41c, TestCase::QUICK); 198 | AddTestCase (tc41d, TestCase::QUICK); 199 | AddTestCase (tc41e, TestCase::QUICK); 200 | AddTestCase (tc41f, TestCase::QUICK); 201 | AddTestCase (tc41g, TestCase::QUICK); 202 | 203 | // ----------------------- 204 | // Test Case 4.2.x: Wireless Bottleneck 205 | // ----------------------- 206 | bw = 100 * (1u << 20); // default wired capacity: 100Mbps 207 | rCBR = 600 * (1u << 10); // rate of each CBR-over-UDP flow: 600Kbps 208 | 209 | std::vector nFlows; 210 | nFlows.push_back (8); 211 | nFlows.push_back (12); 212 | nFlows.push_back (16); 213 | for (size_t i = 0; iSetSimTime (simT); 226 | tc42a->SetPHYMode (phyMode); 227 | tc42a->SetRMCATFlows (n * 2, t0s, t0s, true); 228 | tc42a->SetRMCATFlows (0, t0s, t0s, false); 229 | 230 | // ----------------------- 231 | // Test Case 4.2.b: Wireless Bottleneck; 232 | // Multiple uplink RMCAT flows 233 | // ----------------------- 234 | bss << "rmcat-wifi-test-case-4.2.b-n" << n * 2; 235 | RmcatWifiTestCase * tc42b = new RmcatWifiTestCase{bw, pdel, qdel, bss.str ()}; 236 | tc42b->SetSimTime (simT); 237 | tc42b->SetPHYMode (phyMode); 238 | tc42b->SetRMCATFlows (0, t0s, t0s, true); 239 | tc42b->SetRMCATFlows (n * 2, t0s, t0s, false); 240 | 241 | // ----------------------- 242 | // Test Case 4.2.c: Wireless Bottleneck; 243 | // Multiple bi-directional RMCAT flows 244 | // ----------------------- 245 | css << "rmcat-wifi-test-case-4.2.c-n" << n * 2; 246 | RmcatWifiTestCase * tc42c = new RmcatWifiTestCase{bw, pdel, qdel, css.str ()}; 247 | tc42c->SetSimTime (simT); 248 | tc42c->SetPHYMode (phyMode); 249 | tc42c->SetRMCATFlows (n, t0s, t0s, true); 250 | tc42c->SetRMCATFlows (n, t0s, t0s, false); 251 | 252 | /* Add test cases to test suite */ 253 | // You can comment out these lines if you wish to reduce the time 254 | // it takes to run the suite, as these test cases take a while 255 | AddTestCase (tc42a,TestCase::QUICK); 256 | AddTestCase (tc42b,TestCase::QUICK); 257 | AddTestCase (tc42c,TestCase::QUICK); 258 | } 259 | 260 | // ----------------------- 261 | // Test Case 4.2.d: Wireless Bottleneck; 262 | // Multiple bi-directional RMCAT flows 263 | // + multiple uplink CBR-over-UDP flows 264 | // ----------------------- 265 | nRMCAT = 12; 266 | nCBR = 4; 267 | /* start/stop times of background CBR traffic, multiple flows */ 268 | std::vector tstartCBRTC42; // Seconds 269 | std::vector tstopCBRTC42; // Seconds 270 | for (uint32_t i = 0; i < nCBR; ++i) { 271 | tstartCBRTC42.push_back (RMCAT_TC_BG_TSTART); // t_start = 40s 272 | tstopCBRTC42.push_back (RMCAT_TC_BG_TFINIS); // t_stop = 80s 273 | } 274 | 275 | std::stringstream dss; 276 | dss << "rmcat-wifi-test-case-4.2.d-n" << nRMCAT*2; 277 | RmcatWifiTestCase * tc42d = new RmcatWifiTestCase{bw, pdel, qdel, dss.str ()}; 278 | tc42d->SetSimTime (simT); 279 | tc42d->SetPHYMode (phyMode); 280 | tc42d->SetCBRRate (rCBR); 281 | tc42d->SetRMCATFlows (nRMCAT, t0s, t0s, true); 282 | tc42d->SetRMCATFlows (nRMCAT, t0s, t0s, false); 283 | tc42d->SetUDPFlows (0, t0s, t0s, true); 284 | tc42d->SetUDPFlows (nCBR, tstartCBRTC42, tstopCBRTC42, false); 285 | 286 | // ----------------------- 287 | // Test Case 4.2.f: Wireless Bottleneck; 288 | // Multiple bi-directional RMCAT flows 289 | // + multiple uplink TCP flows 290 | // ----------------------- 291 | nRMCAT = 12; 292 | nTCP = 4; 293 | 294 | /* start/stop times of background TCP traffic; single flow */ 295 | std::vector tstartTCPTC42; // Seconds 296 | std::vector tstopTCPTC42; // Seconds 297 | for (uint32_t i = 0; i < nTCP; ++i) { 298 | tstartTCPTC42.push_back (RMCAT_TC_BG_TSTART); // t_start = 40s 299 | tstopTCPTC42.push_back (RMCAT_TC_BG_TFINIS); // t_stop = 80s 300 | } 301 | std::stringstream ess; 302 | ess << "rmcat-wifi-test-case-4.2.e-n" << nRMCAT * 2; 303 | RmcatWifiTestCase * tc42e = new RmcatWifiTestCase{bw, pdel, qdel, ess.str ()}; 304 | tc42e->SetSimTime (simT); 305 | tc42e->SetPHYMode (phyMode); 306 | tc42e->SetRMCATFlows (nRMCAT, t0s, t0s, true); 307 | tc42e->SetRMCATFlows (nRMCAT, t0s, t0s, false); 308 | tc42e->SetTCPFlows (0, t0s, t0s, true); 309 | tc42e->SetTCPFlows (nTCP, tstartTCPTC42, tstopTCPTC42, false); 310 | 311 | /* 312 | * Add collection of wi-fi bottleneck test cases 313 | * (Section 4.2. in rmcat-wireless-tests draft) 314 | * to test suite 315 | */ 316 | AddTestCase (tc42d,TestCase::QUICK); 317 | AddTestCase (tc42e,TestCase::QUICK); 318 | } 319 | 320 | static RmcatWifiTestSuite rmcatWifiTestSuite; 321 | -------------------------------------------------------------------------------- /test/rmcat-wired-test-case.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Class declaration for rmcat wired test cases. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #ifndef RMCAT_WIRED_TEST_CASE_H 29 | #define RMCAT_WIRED_TEST_CASE_H 30 | 31 | 32 | #include "ns3/wired-topo.h" 33 | #include "ns3/rmcat-sender.h" 34 | #include "ns3/rmcat-receiver.h" 35 | #include "ns3/rmcat-constants.h" 36 | #include "ns3/bulk-send-application.h" 37 | #include "ns3/application-container.h" 38 | #include "ns3/log.h" 39 | #include "ns3/timer.h" 40 | #include "rmcat-common-test.h" 41 | #include 42 | 43 | using namespace ns3; 44 | 45 | /** 46 | * Defines common configuration parameters of a RMCAT 47 | * wired test case; 48 | * 49 | * Implements common procedures such as configurations 50 | * of network topology, traffic flow types (RMCAT/TCP), 51 | * and arrival/departure patterns. 52 | */ 53 | class RmcatWiredTestCase : public RmcatTestCase 54 | { 55 | 56 | public: 57 | /* Constructor */ 58 | RmcatWiredTestCase (uint64_t capacity, // bottleneck capacity (in bps) 59 | uint32_t delay, // one-way propagation delay (in ms) 60 | uint32_t qdelay, // bottleneck queue depth (in ms) 61 | std::string desc); // test case description/name 62 | 63 | virtual void DoSetup (); 64 | virtual void DoRun (); 65 | 66 | /* 67 | * Configure various parameters of the 68 | * test case by passing along function 69 | * input values to member variables 70 | */ 71 | void SetCapacity (uint64_t capacity) {m_capacity = capacity; }; 72 | void SetSimTime (uint32_t simTime) {m_simTime = simTime; }; 73 | void SetCodec (SyncodecType codecType) { m_codecType = codecType; }; 74 | void SetPropDelays (const std::vector& pDelays) { m_pDelays = pDelays; } ; 75 | 76 | /* configure time-varying BW */ 77 | void SetBW (const std::vector& times, 78 | const std::vector& capacities, 79 | bool fwd); 80 | 81 | /* configure pause time of a given flow */ 82 | void SetPauseResumeTimes (size_t fid, 83 | const std::vector & ptimes, 84 | const std::vector & rtimes, 85 | bool fwd); 86 | 87 | /* configure RMCAT flows and their arrival/departure pattern */ 88 | void SetRMCATFlows (size_t numFlows, 89 | const std::vector& startTimes, 90 | const std::vector& endTimes, 91 | bool fwd); 92 | 93 | /* configure long lived TCP background flows 94 | * and their arrival/departure patterns */ 95 | void SetTCPLongFlows (size_t numFlows, 96 | const std::vector& startTimes, 97 | const std::vector& endTimes, 98 | bool fwd); 99 | 100 | /* configure short-lived TCP background flows */ 101 | void SetTCPShortFlows (size_t numFlows, 102 | size_t numInitOnFlows, 103 | bool fwd); 104 | 105 | protected: 106 | /* Instantiate flows in DoRun () */ 107 | void SetUpPath (const std::vector& timesFw, 108 | const std::vector& capacities, 109 | bool fwd); 110 | 111 | void SetUpRMCAT (std::vector< Ptr >& send, 112 | std::vector >& ptimers, 113 | std::vector >& rtimers, 114 | bool fwd); 115 | 116 | void SetUpTCPLong (size_t numFlows, 117 | std::vector >& tcpSend); 118 | 119 | void SetUpTCPShort (size_t numFlows, 120 | size_t numInitOnFlows, 121 | std::vector >& tcpSend); 122 | 123 | /* network toplogy configuration */ 124 | WiredTopo m_topo; 125 | 126 | private: 127 | /* Member variables specifying test case configuration */ 128 | size_t m_numFlowsFw; // # of RMCAT flows on forward path 129 | size_t m_numFlowsBw; // # of RMCAT flows on backward path 130 | size_t m_numTcpFlows; // # of long lived TCP flows, only on forward path 131 | size_t m_numShortTcpFlows; // # of short lived TCP flows, only on forward path 132 | size_t m_numInitOnFlows; // # of short lived TCP flows initially in ON state 133 | uint32_t m_simTime; // simulation duration (in seconds) 134 | 135 | /* time-varying capacities */ 136 | std::vector m_capacitiesFw; 137 | std::vector m_capacitiesBw; 138 | std::vector m_timesFw; 139 | std::vector m_timesBw; 140 | 141 | /* per-flow one-way propagation delay (in ms) */ 142 | std::vector m_pDelays; 143 | 144 | /* start/end times for each RMCAT flow */ 145 | std::vector m_startTimesFw; 146 | std::vector m_endTimesFw; 147 | std::vector m_startTimesBw; 148 | std::vector m_endTimesBw; 149 | 150 | /* start/end times for long lived TCP flows 151 | * (currently only supporting forward direction) 152 | */ 153 | std::vector m_startTimesTcp; 154 | std::vector m_endTimesTcp; 155 | 156 | /* pause/resume times of a given RMCAT flow 157 | * (currently only supporting forward direction) 158 | */ 159 | size_t m_pauseFid; 160 | std::vector m_pauseTimes; 161 | std::vector m_resumeTimes; 162 | 163 | SyncodecType m_codecType; 164 | }; 165 | 166 | #endif /* RMCAT_WIRED_TEST_CASE_H */ 167 | -------------------------------------------------------------------------------- /test/rmcat-wired-test-suite.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Test suite for rmcat wired test cases. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #include "rmcat-wired-test-case.h" 29 | 30 | /* 31 | * Implementation of the RmcatTestSuite class, 32 | * which instantiates the collection of test 33 | * cases as specified in the following IETF draft 34 | * (rmcat-eval-test): 35 | * 36 | * Test Cases for Evaluating RMCAT Proposals 37 | * https://tools.ietf.org/html/draft-ietf-rmcat-eval-test-05 38 | */ 39 | 40 | /* 41 | * Defines collection of test cases as specified in 42 | * the rmcat-eval-test draft 43 | */ 44 | class RmcatTestSuite : public TestSuite 45 | { 46 | public: 47 | RmcatTestSuite (); 48 | }; 49 | 50 | RmcatTestSuite::RmcatTestSuite () 51 | : TestSuite{"rmcat-wired", UNIT} 52 | { 53 | // ---------------- 54 | // Default test case parameters 55 | // ----------------- 56 | uint64_t bw = 4 * (1u << 20); // capacity: 4Mbps 57 | uint32_t pdel = 50; // one-way propagation delay: 50ms 58 | uint32_t qdel = 300; // bottleneck queuing delay: 300ms 59 | uint32_t simT = 120; // default simulation duration: 120s 60 | 61 | // null time vector as filler 62 | const std::vector t0s; 63 | 64 | // TODO (deferred): decide where to specify default TCP behavior (currently duplicated 65 | // in rmcat-wired and rmcat-wifi test suites) 66 | // 67 | // Default TCP configuration 68 | Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue ("ns3::TcpNewReno")); 69 | Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (RMCAT_TC_TCP_PKTSIZE)); 70 | Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (0)); 71 | // Uncomment these lines if you wish to modify TCP's send or receive buffer sizes 72 | // Config::SetDefault ("ns3::TcpSocket::RcvBufSize", UintegerValue (RMCAT_TC_TCP_RECVBUF_SIZE)); 73 | // Config::SetDefault ("ns3::TcpSocket::SndBufSize", UintegerValue (RMCAT_TC_TCP_RECVBUF_SIZE)); 74 | 75 | // TODO (deferred): Set up a mechanism (e.g., json-based) to load TC setup. Goal: improve readability 76 | 77 | // ----------------------- 78 | // Test Case 5.1: Variable Available Capacity with a Single Flow 79 | // ----------------------- 80 | std::vector timeTC51; // in seconds 81 | std::vector bwTC51; // in bps 82 | timeTC51.push_back (0); bwTC51.push_back (1u << 20); // 1 Mbps 83 | timeTC51.push_back (40); bwTC51.push_back (2.5 * (1u << 20)); // 2.5 Mbps 84 | timeTC51.push_back (60); bwTC51.push_back ( .6 * (1u << 20)); // 0.6 Mbps 85 | timeTC51.push_back (80); bwTC51.push_back (1u << 20); // 1 Mbps 86 | 87 | RmcatWiredTestCase * tc51a = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.1-fixfps"}; 88 | tc51a->SetSimTime (100); // simulation time: 100s 89 | tc51a->SetBW (timeTC51, bwTC51, true); // FWD path 90 | 91 | RmcatWiredTestCase * tc51b = new RmcatWiredTestCase{bw, 100, qdel, "rmcat-test-case-5.1-fixfps-pdel_100ms"}; 92 | tc51b->SetSimTime (100); // simulation time: 100s 93 | tc51b->SetBW (timeTC51, bwTC51, true); // FWD path 94 | 95 | RmcatWiredTestCase * tc51c = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.1-cbrlike"}; 96 | tc51c->SetSimTime (100); // simulation time: 100s 97 | tc51c->SetBW (timeTC51, bwTC51, true); // FWD path 98 | tc51c->SetCodec (SYNCODEC_TYPE_PERFECT); // CBR-like traffic source 99 | 100 | RmcatWiredTestCase * tc51d = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.1-stats"}; 101 | tc51d->SetSimTime (100); // simulation time: 100s 102 | tc51d->SetBW (timeTC51, bwTC51, true); // FWD path 103 | tc51d->SetCodec (SYNCODEC_TYPE_STATS); // statistical video source 104 | 105 | RmcatWiredTestCase * tc51e = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.1-trace"}; 106 | tc51e->SetSimTime (100); // simulation time: 100s 107 | tc51e->SetBW (timeTC51, bwTC51, true); // FWD path 108 | tc51e->SetCodec (SYNCODEC_TYPE_TRACE); // trace-based video source 109 | 110 | RmcatWiredTestCase * tc51f = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.1-sharing"}; 111 | tc51f->SetSimTime (100); // simulation time: 100s 112 | tc51f->SetBW (timeTC51, bwTC51, true); // FWD path 113 | tc51f->SetCodec (SYNCODEC_TYPE_SHARING); // content-sharing video source 114 | 115 | RmcatWiredTestCase * tc51g = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.1-hybrid"}; 116 | tc51g->SetSimTime (100); // simulation time: 100s 117 | tc51g->SetBW (timeTC51, bwTC51, true); // FWD path 118 | tc51g->SetCodec (SYNCODEC_TYPE_HYBRID); // hybrid (trace/statistics) video source 119 | 120 | // ----------------------- 121 | // Test Case 5.2: Variable Available Capacity with Multiple Flows 122 | // ----------------------- 123 | std::vector timeTC52; 124 | std::vector bwTC52; 125 | timeTC52.push_back (0); bwTC52.push_back (2. * (1u << 21)); // 2 * 2 Mbps 126 | timeTC52.push_back (25); bwTC52.push_back (1u << 21); // 2 Mbps 127 | timeTC52.push_back (50); bwTC52.push_back (1.75 * (1u << 21)); // 1.75 * 2 Mbps 128 | timeTC52.push_back (75); bwTC52.push_back ( .5 * (1u << 21)); // 0.5 * 2 Mbps 129 | timeTC52.push_back (100); bwTC52.push_back (1u << 21); // 2 Mbps 130 | 131 | RmcatWiredTestCase * tc52 = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.2-fixfps"}; 132 | tc52->SetSimTime (125); // simulation time: 125s 133 | tc52->SetBW (timeTC52, bwTC52, true); 134 | tc52->SetRMCATFlows (2, t0s, t0s, true); 135 | 136 | // ----------------------- 137 | // Test Case 5.3: Congested Feedback Link with Bi-directional Media Flows 138 | // ----------------------- 139 | std::vector timeTC53fwd; 140 | std::vector timeTC53bwd; 141 | std::vector bwTC53fwd; 142 | std::vector bwTC53bwd; 143 | timeTC53fwd.push_back (0); bwTC53fwd.push_back (2. * (1u << 20)); // 2 Mbps 144 | timeTC53fwd.push_back (20); bwTC53fwd.push_back (1. * (1u << 20)); // 1 Mbps 145 | timeTC53fwd.push_back (40); bwTC53fwd.push_back ( .5 * (1u << 20)); // 0.5 Mbps 146 | timeTC53fwd.push_back (60); bwTC53fwd.push_back (2. * (1u << 20)); // 2 Mbps 147 | 148 | timeTC53bwd.push_back (0); bwTC53bwd.push_back (2. * (1u << 20)); // 2 Mbps 149 | timeTC53bwd.push_back (35); bwTC53bwd.push_back ( .8 * (1u << 20)); // 0.8 Mbps 150 | timeTC53bwd.push_back (70); bwTC53bwd.push_back (2. * (1u << 20)); // 2 Mbps 151 | 152 | RmcatWiredTestCase * tc53 = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.3-fixfps"}; 153 | tc53->SetSimTime (100); // simulation time: 100s 154 | tc53->SetBW (timeTC53fwd, bwTC53fwd, true); // Forward path 155 | tc53->SetBW (timeTC53bwd, bwTC53bwd, false); // Backward path 156 | tc53->SetRMCATFlows (1, t0s, t0s, true); // Forward path 157 | tc53->SetRMCATFlows (1, t0s, t0s, false); // Backward path 158 | 159 | // ----------------------- 160 | // Test Case 5.4: Competing Media Flows with same Congestion Control Algorithm 161 | // ----------------------- 162 | std::vector tstartTC54; // Seconds 163 | std::vector tstopTC54; // Seconds 164 | tstartTC54.push_back (0); tstopTC54.push_back (119); 165 | tstartTC54.push_back (20); tstopTC54.push_back (119); 166 | tstartTC54.push_back (40); tstopTC54.push_back (119); 167 | RmcatWiredTestCase * tc54 = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.4-fixfps"}; 168 | tc54->SetCapacity (3.5 * (1u << 20)); // bottleneck capacity: 3.5 Mbps 169 | tc54->SetSimTime (simT); // default simulation time: 120s 170 | tc54->SetRMCATFlows (3, tstartTC54, tstopTC54, true); // Forward path 171 | 172 | // ----------------------- 173 | // Test Case 5.5: Round Trip Time Fairness 174 | // ----------------------- 175 | // configure per-flow one-way propagation delay 176 | std::vector pDelaysTC55; // ms 177 | pDelaysTC55.push_back (10); // 1st flow: 10ms 178 | pDelaysTC55.push_back (25); // 2nd flow: 25ms 179 | pDelaysTC55.push_back (50); // 3rd flow: 50ms 180 | pDelaysTC55.push_back (100); // 4th flow: 100ms 181 | pDelaysTC55.push_back (150); // 5th flow: 150ms 182 | 183 | // configure per-flow start/stop time 184 | std::vector tstartTC55; // Seconds 185 | std::vector tstopTC55; // Seconds 186 | tstartTC55.push_back (0); tstopTC55.push_back (299); 187 | tstartTC55.push_back (10); tstopTC55.push_back (299); 188 | tstartTC55.push_back (20); tstopTC55.push_back (299); 189 | tstartTC55.push_back (30); tstopTC55.push_back (299); 190 | tstartTC55.push_back (40); tstopTC55.push_back (299); 191 | RmcatWiredTestCase * tc55 = new RmcatWiredTestCase{bw, 10, qdel, "rmcat-test-case-5.5-fixfps"}; 192 | tc55->SetSimTime (300); // simulation time: 300s 193 | tc55->SetRMCATFlows (5, tstartTC55, tstopTC55, true); // Forward path 194 | tc55->SetPropDelays (pDelaysTC55); 195 | 196 | // ----------------------- 197 | // Test Case 5.6: Media Flow Competing with a Long TCP Flow 198 | // ----------------------- 199 | // configure TCP flow start/end time 200 | std::vector tstartTC56; // Seconds 201 | std::vector tstopTC56; // Seconds 202 | tstartTC56.push_back (5); tstopTC56.push_back (119); 203 | 204 | RmcatWiredTestCase * tc56 = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.6-fixfps"}; 205 | tc56->SetCapacity (2 * (1u << 20)); // Bottleneck capacity: 2Mbps 206 | tc56->SetSimTime (simT); // Default simulation time: 120s 207 | tc56->SetRMCATFlows (1, tstartTC56, tstopTC56, true); // Forward path 208 | tc56->SetTCPLongFlows (1, t0s, t0s, true); // Forward path 209 | // TODO (deferred): Bottleneck queue sizes: [300ms, 1000ms] 210 | 211 | // ----------------------- 212 | // Test Case 5.7: Media Flow Competing with Short TCP Flows 213 | // ----------------------- 214 | std::vector tstartTC57; // Seconds 215 | std::vector tstopTC57; // Seconds 216 | tstartTC57.push_back (5); tstopTC57.push_back (299); 217 | tstartTC57.push_back (5); tstopTC57.push_back (299); 218 | 219 | RmcatWiredTestCase * tc57 = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.7-fixfps"}; 220 | tc57->SetCapacity (2 * (1u << 20)); // Bottleneck capacity: 2Mbps 221 | tc57->SetSimTime (300); // Simulation time: 300s 222 | tc57->SetRMCATFlows (2, tstartTC57, tstopTC57, true); // Forward path 223 | tc57->SetTCPShortFlows (10, 2, true); // Forward path 224 | 225 | // ----------------------- 226 | // Test Case 5.8: Media Pause and Resume (Modified from TC5.4) 227 | // ----------------------- 228 | 229 | // configure flow pause/resume timeline 230 | uint32_t fid8 = 1; // flowID to be paused & resumed 231 | std::vector tpauseTC58; // Seconds 232 | std::vector tresumeTC58; // Seconds 233 | tpauseTC58.push_back (40); 234 | tresumeTC58.push_back (60); 235 | 236 | RmcatWiredTestCase * tc58 = new RmcatWiredTestCase{bw, pdel, qdel, "rmcat-test-case-5.8-fixfps"}; 237 | tc58->SetCapacity (3.5 * (1u << 20)); // bottleneck capacity: 3.5 Mbps (same as TC5.4) 238 | tc58->SetSimTime (simT); // default simulation time: 120s (same as TC5.4) 239 | tc58->SetRMCATFlows (3, t0s, t0s, true); // Forward path 240 | tc58->SetPauseResumeTimes (fid8, tpauseTC58, tresumeTC58, true); 241 | 242 | // ------------------------------- 243 | // Add test cases to test suite 244 | // ------------------------------- 245 | 246 | AddTestCase (tc51a, TestCase::QUICK); 247 | AddTestCase (tc51b, TestCase::QUICK); 248 | AddTestCase (tc51c, TestCase::QUICK); 249 | AddTestCase (tc51d, TestCase::QUICK); 250 | AddTestCase (tc51e, TestCase::QUICK); 251 | AddTestCase (tc51f, TestCase::QUICK); 252 | AddTestCase (tc51g, TestCase::QUICK); 253 | 254 | AddTestCase (tc52, TestCase::QUICK); 255 | 256 | AddTestCase (tc53, TestCase::QUICK); 257 | AddTestCase (tc54, TestCase::QUICK); 258 | AddTestCase (tc55, TestCase::QUICK); 259 | AddTestCase (tc56, TestCase::QUICK); 260 | AddTestCase (tc57, TestCase::QUICK); 261 | AddTestCase (tc58, TestCase::QUICK); 262 | } 263 | 264 | static RmcatTestSuite rmcatTestSuite; 265 | -------------------------------------------------------------------------------- /test/rmcat-wired-varyparam-test-suite.cc: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * Copyright 2016-2017 Cisco Systems, Inc. * 3 | * * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); * 5 | * you may not use this file except in compliance with the License. * 6 | * * 7 | * You may obtain a copy of the License at * 8 | * * 9 | * http://www.apache.org/licenses/LICENSE-2.0 * 10 | * * 11 | * Unless required by applicable law or agreed to in writing, software * 12 | * distributed under the License is distributed on an "AS IS" BASIS, * 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 14 | * See the License for the specific language governing permissions and * 15 | * limitations under the License. * 16 | ******************************************************************************/ 17 | 18 | /** 19 | * @file 20 | * Test suite for rmcat wired test cases, obtained by varying various parameters. 21 | * 22 | * @version 0.1.1 23 | * @author Jiantao Fu 24 | * @author Sergio Mena 25 | * @author Xiaoqing Zhu 26 | */ 27 | 28 | #include "rmcat-wired-test-case.h" 29 | 30 | /* 31 | * Implementation of the RmcatVaryParamTestSuite class, 32 | * which instantiates the collection of test 33 | * cases as specified in the following IETF draft 34 | * (rmcat-eval-test): 35 | * 36 | * Test Cases for Evaluating RMCAT Proposals 37 | * https://tools.ietf.org/html/draft-ietf-rmcat-eval-test-05 38 | */ 39 | 40 | /* 41 | * Defines collection of test cases with varying 42 | * parameters (e.g., bottleneck BW, propagation 43 | * delay) for specific test cases in the rmcat-eval-test 44 | * draft 45 | */ 46 | class RmcatVaryParamTestSuite : public TestSuite 47 | { 48 | public: 49 | RmcatVaryParamTestSuite (); 50 | }; 51 | 52 | RmcatVaryParamTestSuite::RmcatVaryParamTestSuite () 53 | : TestSuite{"rmcat-vparam", UNIT} 54 | { 55 | // ---------------- 56 | // Default test case parameters 57 | // ----------------- 58 | uint32_t qdel = 300; // bottleneck queuing delay: 300ms 59 | uint32_t simT = 300; // default simulation duration: 120s 60 | 61 | // TODO (deferred): decide where to specify default TCP behavior (currently duplicated 62 | // in rmcat-wired and rmcat-wifi test suites) 63 | // 64 | // Default TCP configuration 65 | Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue ("ns3::TcpNewReno")); 66 | Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (RMCAT_TC_TCP_PKTSIZE)); 67 | Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (0)); 68 | Config::SetDefault ("ns3::TcpSocket::RcvBufSize", UintegerValue (RMCAT_TC_TCP_RECVBUF_SIZE)); 69 | Config::SetDefault ("ns3::TcpSocket::SndBufSize", UintegerValue (RMCAT_TC_TCP_RECVBUF_SIZE)); 70 | 71 | // ----------------------- 72 | // Test Case 5.6: Media Flow Competing with a Long TCP Flow 73 | // ----------------------- 74 | // configure TCP flow start/end time 75 | std::vector tstartTC56; // Seconds 76 | std::vector tstopTC56; // Seconds 77 | tstartTC56.push_back (60); 78 | tstopTC56.push_back (240); 79 | 80 | /* 81 | * Duplicating Julius's Tests 82 | */ 83 | std::vector pdellist; 84 | std::vector bwlist; 85 | pdellist.push_back (20); 86 | pdellist.push_back (40); 87 | pdellist.push_back (60); 88 | pdellist.push_back (80); 89 | pdellist.push_back (100); 90 | 91 | bwlist.push_back (400 * (1u << 10)); // 400Kbps 92 | bwlist.push_back (600 * (1u << 10)); // 600Kbps 93 | bwlist.push_back (800 * (1u << 10)); // 800Kbps 94 | bwlist.push_back (1000 * (1u << 10)); // 1 Mbps 95 | bwlist.push_back (1200 * (1u << 10)); // 1.2 Mbps 96 | bwlist.push_back (1600 * (1u << 10)); // 1.6 Mbps 97 | bwlist.push_back (2000 * (1u << 10)); // 2 Mbps 98 | bwlist.push_back (4000 * (1u << 10)); // 4 Mbps 99 | bwlist.push_back (6000 * (1u << 10)); // 6 Mbps 100 | bwlist.push_back (10000 * (1u << 10)); // 10 Mbps 101 | 102 | for (size_t i = 0; i < bwlist.size (); ++i) { 103 | uint64_t bw_i = bwlist[i]; 104 | for (size_t j = 0; j < pdellist.size (); ++j) { 105 | uint32_t pdel_j = pdellist[j]; 106 | 107 | std::stringstream ss; 108 | ss << "rmcat-test-case-5.6-C" << bw_i / (1u << 10) << "-pdel" << pdel_j; 109 | RmcatWiredTestCase * tc56tmp = new RmcatWiredTestCase{bw_i, pdel_j, qdel, ss.str ()}; 110 | tc56tmp->SetSimTime (simT); // Simulation time: 300s 111 | tc56tmp->SetTCPLongFlows (1, tstartTC56, tstopTC56, true); // Forward path 112 | 113 | AddTestCase (tc56tmp, TestCase::QUICK); 114 | } 115 | } 116 | } 117 | 118 | static RmcatVaryParamTestSuite rmcatVparamTestSuite; 119 | -------------------------------------------------------------------------------- /tools/plot_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | ############################################################################### 4 | # Copyright 2016-2017 Cisco Systems, Inc. # 5 | # # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); # 7 | # you may not use this file except in compliance with the License. # 8 | # # 9 | # You may obtain a copy of the License at # 10 | # # 11 | # http://www.apache.org/licenses/LICENSE-2.0 # 12 | # # 13 | # Unless required by applicable law or agreed to in writing, software # 14 | # distributed under the License is distributed on an "AS IS" BASIS, # 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 16 | # See the License for the specific language governing permissions and # 17 | # limitations under the License. # 18 | ############################################################################### 19 | 20 | import os 21 | import sys 22 | import json 23 | import matplotlib.pyplot as plt 24 | 25 | colorlist = ['blue', 26 | 'orange', 27 | 'green', 28 | 'pink', 29 | 'red', 30 | 'purple', 31 | 'gray', 32 | 'black', 33 | 'brown', 34 | 'aqua', 35 | 'navy', 36 | 'teal', 37 | 'olive', 38 | 'coral', 39 | 'lime', 40 | 'royalblue', 41 | 'maroon', 42 | 'yellowgreen', 43 | 'tan', 44 | 'khaki', 45 | 'darkslategrey', 46 | 'darkgreen', 47 | 'sienna', 48 | 'peachpuff', 49 | 'sandybrown', 50 | 'steelblue'] 51 | 52 | tableau20 = [(31, 119, 180), (174, 199, 232), (255, 127, 14), (255, 187, 120), 53 | (44, 160, 44), (152, 223, 138), (214, 39, 40), (255, 152, 150), 54 | (148, 103, 189), (197, 176, 213), (140, 86, 75), (196, 156, 148), 55 | (227, 119, 194), (247, 182, 210), (127, 127, 127), (199, 199, 199), 56 | (188, 189, 34), (219, 219, 141), (23, 190, 207), (158, 218, 229)] 57 | 58 | # Scale the RGB values to the [0, 1] range, which is the format matplotlib accepts. 59 | for i in range(len(tableau20)): 60 | r, g, b = tableau20[i] 61 | colorlist.append((r / 255., g / 255., b / 255.)) 62 | 63 | 64 | def adjust_tmax(tmax, new_max_ts): 65 | tmax_tmp = int(new_max_ts + 2.5) / 5 * 5 66 | return tmax_tmp if tmax_tmp > tmax else tmax 67 | 68 | def plot_test_case(tc_name, contents, dirname): 69 | rmcat_log = contents['nada'] 70 | tcp_log = contents['tcp'] 71 | rmcat_keys = sorted(rmcat_log.keys()) 72 | tcp_keys = sorted(tcp_log.keys()) 73 | 74 | print('plotting data for tc {}...'.format(tc_name)) 75 | nflow = len(rmcat_keys) + len(tcp_keys) 76 | 77 | l = len(colorlist) 78 | pngfile = '{}.png'.format(tc_name); 79 | tmax = 100 80 | fig = plt.figure() 81 | plt.subplot(311) 82 | for (i, obj) in enumerate(rmcat_keys): 83 | rcolor = colorlist[i % l] 84 | rcolor2 = colorlist[i+1 % l] 85 | ts = [x[0] for x in rmcat_log[obj]] 86 | tmax = adjust_tmax(tmax, max(ts)) 87 | rrate = [x[6]/1.e+6 for x in rmcat_log[obj]] 88 | srate = [x[7]/1.e+6 for x in rmcat_log[obj]] 89 | if nflow == 1: 90 | plt.plot(ts, rrate, 'd', linewidth=1.0, color=rcolor2, mfc=rcolor2, mec='none', 91 | ms=2, label=obj+'(recv)') 92 | plt.plot(ts, srate, 'o', linewidth=1.0, color=rcolor, mfc=rcolor, mec='none', 93 | ms=2, label=obj+'(sent)') 94 | else: 95 | plt.plot(ts, srate, 'o', linewidth=1.0, color=rcolor, mfc=rcolor, mec='none', 96 | ms=2, label=obj) 97 | 98 | for (i, obj) in enumerate(tcp_keys): 99 | rcolor = colorlist[(i + 5) % l] 100 | ts = [x[0] for x in tcp_log[obj]] 101 | tmax = adjust_tmax(tmax, max(ts)) 102 | rrate = [x[2]/1.e+6 for x in tcp_log[obj]] 103 | plt.plot(ts, rrate, '-o', linewidth=.7, color=rcolor, mfc=rcolor, mec='none', 104 | ms=2, label=obj) 105 | 106 | plt.xlim(0, tmax) 107 | plt.ylim(0, 2.5) 108 | plt.ylabel('Rate (Mbps)') 109 | # plt.legend(loc='upper left', prop={'size':6}, bbox_to_anchor=(1,1), ncol=1) 110 | all_curves = len(rmcat_keys) + len(tcp_keys) 111 | if all_curves < 12: 112 | plt.legend(ncol = (all_curves // 4) + 1, loc='upper right', fontsize = 'small') 113 | 114 | plt.subplot(312) 115 | for (i, obj) in enumerate(rmcat_keys): 116 | rcolor = colorlist[i % l] 117 | ts = [x[0] for x in rmcat_log[obj]] 118 | qdelay = [x[1] for x in rmcat_log[obj]] 119 | rtt = [x[2] for x in rmcat_log[obj]] 120 | xcurr = [x[5] for x in rmcat_log[obj]] 121 | delta = [x[11] for x in rmcat_log[obj]] 122 | plt.plot(ts, qdelay, 'o', color=rcolor, mfc=rcolor, mec='none', ms=2, label=obj) 123 | # plt.plot(ts, xcurr, 'o', color='purple', mfc='purple', mec='none', ms=2, label=obj) 124 | # plt.plot(ts, delta, 'o', color=rcolor, mfc=rcolor, mec='none', ms=1, label=obj) 125 | plt.xlim(0, tmax) 126 | plt.ylim(0, 400) 127 | # plt.ylim(0, plt.gca().get_ylim()[1] * 1.5) #Margin for legend 128 | plt.ylabel('QDelay (ms)') 129 | # plt.legend(loc='upper left', prop={'size':6}, bbox_to_anchor=(1,1), ncol=1) 130 | all_curves = len(rmcat_keys) 131 | # plt.legend(ncol = (all_curves / 4) + 1, loc='upper right', fontsize = 'small') 132 | 133 | plt.subplot(313) 134 | for (i, obj) in enumerate(rmcat_keys): 135 | rcolor = colorlist[i % l] 136 | ts = [x[0] for x in rmcat_log[obj]] 137 | ploss = [x[3] for x in rmcat_log[obj]] 138 | plr = [x[4]*100. for x in rmcat_log[obj]] # ratio => % 139 | loglen = [x[8] for x in rmcat_log[obj]] 140 | plt.plot(ts, plr, 'o', color=rcolor, mfc=rcolor, mec='none', ms=2, label=obj) 141 | # plt.plot(ts, ploss, 'd', color=rcolor, mfc=rcolor, mec='none', ms=4, label=obj) 142 | 143 | plt.xlim(0, tmax) 144 | # plt.ylim(0, 5) 145 | plt.ylabel('PLR (%)') 146 | plt.xlabel('Time (s)') 147 | # plt.legend(loc='upper left', prop={'size':6}, bbox_to_anchor=(1,1), ncol=1) 148 | # plt.legend(ncol = (all_curves / 4) + 1, loc='upper right', fontsize = 'small') 149 | fig.savefig(os.path.join(dirname, pngfile)) 150 | plt.close(fig) 151 | 152 | 153 | # --------- # 154 | if len(sys.argv) != 2: 155 | sys.stderr.write('Usage: python {} \n'.format(sys.argv[0])) 156 | sys.exit(1) 157 | 158 | dirname = sys.argv[1] 159 | assert os.path.isdir(dirname) 160 | 161 | f_json_name = os.path.join(dirname, 'all_tests.json') 162 | assert os.path.isfile(f_json_name) 163 | f_json = open(f_json_name, 'r') 164 | all_logs = json.load(f_json) 165 | for test_case in all_logs.keys(): 166 | plot_test_case(test_case, all_logs[test_case], dirname) 167 | -------------------------------------------------------------------------------- /tools/process_test_logs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | ############################################################################### 4 | # Copyright 2016-2017 Cisco Systems, Inc. # 5 | # # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); # 7 | # you may not use this file except in compliance with the License. # 8 | # # 9 | # You may obtain a copy of the License at # 10 | # # 11 | # http://www.apache.org/licenses/LICENSE-2.0 # 12 | # # 13 | # Unless required by applicable law or agreed to in writing, software # 14 | # distributed under the License is distributed on an "AS IS" BASIS, # 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 16 | # See the License for the specific language governing permissions and # 17 | # limitations under the License. # 18 | ############################################################################### 19 | 20 | import os 21 | import sys 22 | import re 23 | import json 24 | 25 | SEP = '\t' 26 | 27 | def process_row(row, width): 28 | if row is not None: 29 | vals = [str(v) for v in row] 30 | assert len(vals) == width 31 | line = SEP.join(vals) 32 | else: 33 | line = (SEP + 'NaN') * width 34 | return line 35 | 36 | def process_controller_log(line, test_logs): 37 | 'place-holder, parsing debug stats' 38 | match = re.search(r'controller_log: DEBUG:', line) 39 | if match: 40 | #Controller's debug log, ignore 41 | return 42 | 43 | 'parsing nada-specific stats' 44 | # ts: 158114 loglen: 60 qdel: 286 rtt: 386 ploss: 0 plr: 0.00 xcurr: 4.72 rrate: 863655.56 srate: 916165.81 avgint: 437.10 curint: 997 delta: 100 45 | match = re.search(r'algo:nada (\S+) ts: (\d+) loglen: (\d+)', line) 46 | match_d = re.search(r'qdel: (\d+(?:\.\d*)?|\.\d+) rtt: (\d+(?:\.\d*)?|\.\d+)', line) 47 | match_p = re.search(r'ploss: (\d+) plr: (\d+(?:\.\d*)?|\.\d+)', line) 48 | match_x = re.search(r'xcurr: (\d+(?:\.\d*)?|\.\d+)', line) 49 | match_r = re.search(r'rrate: (\d+(?:\.\d*)?|\.\d+) srate: (\d+(?:\.\d*)?|\.\d+)', line) 50 | match_l = re.search(r'avgint: (\d+(?:\.\d*)?|\.\d+) curint: (\d+(?:\.\d*)?|\.\d+)', line) 51 | match_D = re.search(r'delta: (\d+(?:\.\d*)?|\.\d+)', line) 52 | 53 | if match: 54 | assert (match_d and match_p and match_x and match_r and match_l) 55 | obj = match.group(1); 56 | ts = int(match.group(2)) / 1000. # to seconds 57 | loglen = int(match.group(3)); 58 | 59 | qdel = float(match_d.group(1)) 60 | rtt = float(match_d.group(2)) 61 | ploss = int(match_p.group(1)) 62 | plr = float(match_p.group(2)) 63 | x_curr = float(match_x.group(1)) 64 | rrate = float(match_r.group(1)) 65 | srate = float(match_r.group(2)) 66 | avgint = float(match_l.group(1)) 67 | curint = int(match_l.group(2)) 68 | delta = float(match_D.group(1)) 69 | 70 | if obj not in test_logs['nada']: 71 | test_logs['nada'][obj] = [] 72 | test_logs['nada'][obj].append([ts, qdel, rtt, ploss, plr, x_curr, 73 | rrate, srate, loglen, avgint, curint, delta]) 74 | return 75 | 76 | 77 | def process_tcp_log(line, test_logs): 78 | #tcp_0 ts: 165000 recv: 16143000 rrate: 1160000.0000 79 | match = re.search(r'(\S+) ts: (\d+) recv: (\d+) rrate: (\d+(?:\.\d*)?|\.\d+)', line) 80 | if match: 81 | obj = match.group(1) 82 | ts = int(match.group(2)) / 1000. # to seconds 83 | bytes_recvd = int(match.group(3)) 84 | rrate = float(match.group(4)) 85 | if obj not in test_logs['tcp']: 86 | test_logs['tcp'][obj] = [] 87 | test_logs['tcp'][obj].append([ts, bytes_recvd, rrate]) 88 | return 89 | assert False, "Error: Unrecognized tcp log line: <{}>".format(line) 90 | 91 | def process_log(dirname, filename, all_logs): 92 | abs_fn = os.path.join(dirname, filename) 93 | if not os.path.isfile(abs_fn): 94 | print("Skipping file {} (not a regular file)".format(filename)) 95 | return 96 | match = re.match(r'([a-zA-Z0-9_\.-]+).log', filename) 97 | if match is None: 98 | print("Skipping file {} (not a log file)".format(filename)) 99 | return 100 | 101 | print("Processing file {}...".format(filename)) 102 | test_name = match.group(1).replace(".", "_").replace("-", "_") 103 | 104 | test_logs = {'nada': {}, 'tcp': {} } 105 | all_logs[test_name] = test_logs 106 | 107 | with open(abs_fn) as f_log: 108 | for line in f_log: 109 | match = re.search(r'controller_log:', line) 110 | if match: 111 | process_controller_log(line, test_logs) 112 | continue 113 | match = re.search(r'tcp_log:', line) 114 | if match: 115 | process_tcp_log(line, test_logs) 116 | continue 117 | #Unrecognized ns3 log line , ignore 118 | 119 | saveto_matfile(dirname, filename, test_logs) 120 | 121 | def saveto_matfile(dirname, test_name, test_logs): 122 | 'save to *.mat file' 123 | f_out_name = os.path.join(dirname, '{}.mat'.format(test_name)) 124 | print('Creating matlab file: {}'.format(f_out_name)) 125 | f_out = open(f_out_name, 'w') 126 | f_out.write('% id | ts | qdel | rtt | ploss | plr | xcurr ') 127 | f_out.write('| rrate | srate | loglen | avgint | curint\n') 128 | for (i, obj) in enumerate(test_logs['nada'].keys()): 129 | nrec = len(test_logs['nada'][obj]) 130 | print('parsing flow ', obj, ' number of records: ', nrec) 131 | for j in range(nrec): 132 | row = process_row(test_logs['nada'][obj][j], width=12) 133 | f_out.write(SEP.join([str(i), row])) 134 | f_out.write('\n') 135 | 136 | # -------------------- # 137 | if len(sys.argv) != 2: 138 | sys.stderr.write('Usage: python {} \n'.format(sys.argv[0])) 139 | sys.exit(1) 140 | 141 | dirname = sys.argv[1] 142 | assert os.path.isdir(dirname) 143 | all_logs = {} 144 | for filename in os.listdir(dirname): 145 | process_log(dirname, filename, all_logs) 146 | 147 | print("Creating json file with all data: all_tests.json") 148 | f_json_name = os.path.join(dirname, 'all_tests.json') 149 | f_json = open(f_json_name, 'w') 150 | json.dump(all_logs, f_json, indent=4, sort_keys=True) 151 | -------------------------------------------------------------------------------- /tools/test.csh: -------------------------------------------------------------------------------- 1 | #!/bin/csh 2 | 3 | ############################################################################### 4 | # Copyright 2016-2017 Cisco Systems, Inc. # 5 | # # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); # 7 | # you may not use this file except in compliance with the License. # 8 | # # 9 | # You may obtain a copy of the License at # 10 | # # 11 | # http://www.apache.org/licenses/LICENSE-2.0 # 12 | # # 13 | # Unless required by applicable law or agreed to in writing, software # 14 | # distributed under the License is distributed on an "AS IS" BASIS, # 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 16 | # See the License for the specific language governing permissions and # 17 | # limitations under the License. # 18 | ############################################################################### 19 | 20 | # run from ns3 root directory: ns-3.xx/ 21 | # 22 | # Example: 23 | # ./src/ns3-rmcat/tools/test.csh wired 2017-07-21-rmcat-wired 24 | # ./src/ns3-rmcat/tools/test.csh vparam 2017-07-21-rmcat-wired-vparam 25 | # ./src/ns3-rmcat/tools/test.csh wifi 2017-07-21-rmcat-wifi 26 | # 27 | # The second parameter, output directory, is optional. If not specified, 28 | # the script will use a folder with a name based on current GMT time 29 | 30 | set scen = $1 31 | set odir = $2 32 | if ( "$odir" == "" ) then 33 | set odir = `date -u +"%Y-%m-%d-%H-%M-%S-CUT"` 34 | set odir = "testpy-output/$odir" 35 | endif 36 | 37 | set patched_script = test_patched.py 38 | 39 | # uncomment the following for building from scratch 40 | # 41 | # clean up and rebuild 42 | # echo "cleaning up and rebuiling ..." 43 | # ./waf clean 44 | # ./waf 45 | 46 | # patch test.py 47 | if ( ! -f "$patched_script") then 48 | rm -f "$patched_script" 49 | endif 50 | patch -p1 -i src/ns3-rmcat/tools/test.py.diff -o "$patched_script" test.py 51 | 52 | # run tests 53 | echo "running tests ..." 54 | python "$patched_script" -o $odir -s rmcat-$scen -w rmcat-$scen.html -r 55 | 56 | # process and plot 57 | echo "processing and plotting ..." 58 | python src/ns3-rmcat/tools/process_test_logs.py $odir 59 | python src/ns3-rmcat/tools/plot_tests.py $odir 60 | 61 | # for reviewing results 62 | #echo "reviewing results ..." 63 | #open $odir/*.png 64 | -------------------------------------------------------------------------------- /tools/test.py.diff: -------------------------------------------------------------------------------- 1 | diff --git a/test.py b/test.py 2 | --- a/test.py 3 | +++ b/test.py 4 | @@ -1216,22 +1216,26 @@ def run_tests(): 5 | # with a unique name (time) to avoid collisions. In case an error happens, we 6 | # provide a runtime option to retain the temporary files. 7 | # 8 | # When we run examples as smoke tests, they are going to want to create 9 | # lots and lots of trace files. We aren't really interested in the contents 10 | # of the trace files, so we also just stash them off in the temporary dir. 11 | # The retain option also causes these unchecked trace files to be kept. 12 | # 13 | - date_and_time = time.strftime("%Y-%m-%d-%H-%M-%S-CUT", time.gmtime()) 14 | 15 | - if not os.path.exists(TMP_OUTPUT_DIR): 16 | - os.makedirs(TMP_OUTPUT_DIR) 17 | + if options.outpath: 18 | + testpy_output_dir = options.outpath 19 | + else: 20 | + date_and_time = time.strftime("%Y-%m-%d-%H-%M-%S-CUT", time.gmtime()) 21 | + if not os.path.exists(TMP_OUTPUT_DIR): 22 | + os.makedirs(TMP_OUTPUT_DIR) 23 | + testpy_output_dir = os.path.join(TMP_OUTPUT_DIR, date_and_time); 24 | 25 | - testpy_output_dir = os.path.join(TMP_OUTPUT_DIR, date_and_time); 26 | + testpy_output_dir = os.path.abspath(testpy_output_dir) 27 | 28 | if not os.path.exists(testpy_output_dir): 29 | os.makedirs(testpy_output_dir) 30 | 31 | # 32 | # Create the main output file and start filling it with XML. We need to 33 | # do this since the tests will just append individual results to this file. 34 | # 35 | @@ -1376,17 +1380,18 @@ def run_tests(): 36 | for test in suite_list: 37 | test = test.strip() 38 | if len(test): 39 | job = Job() 40 | job.set_is_example(False) 41 | job.set_is_pyexample(False) 42 | job.set_display_name(test) 43 | job.set_tmp_file_name(os.path.join(testpy_output_dir, "%s.xml" % test)) 44 | - job.set_cwd(os.getcwd()) 45 | + # change cwd to testpy_output_dir 46 | + job.set_cwd(testpy_output_dir) 47 | job.set_basedir(os.getcwd()) 48 | job.set_tempdir(testpy_output_dir) 49 | if (options.multiple): 50 | multiple = "" 51 | else: 52 | multiple = " --stop-on-failure" 53 | if (len(options.fullness)): 54 | fullness = options.fullness.upper() 55 | @@ -1926,16 +1931,19 @@ def main(argv): 56 | parser.add_option("-w", "--web", "--html", action="store", type="string", dest="html", default="", 57 | metavar="HTML-FILE", 58 | help="write detailed test results into HTML-FILE.html") 59 | 60 | parser.add_option("-x", "--xml", action="store", type="string", dest="xml", default="", 61 | metavar="XML-FILE", 62 | help="write detailed test results into XML-FILE.xml") 63 | 64 | + parser.add_option("-o", "--outpath", action="store", type="string", dest="outpath", default="", 65 | + metavar="OUTPUT-PATH", help="output path for test results") 66 | + 67 | global options 68 | options = parser.parse_args()[0] 69 | signal.signal(signal.SIGINT, sigint_hook) 70 | 71 | return run_tests() 72 | 73 | if __name__ == '__main__': 74 | sys.exit(main(sys.argv)) 75 | -------------------------------------------------------------------------------- /tools/test_v2.csh: -------------------------------------------------------------------------------- 1 | #!/bin/csh 2 | 3 | ############################################################################### 4 | # Copyright 2016-2020 Cisco Systems, Inc. # 5 | # # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); # 7 | # you may not use this file except in compliance with the License. # 8 | # # 9 | # You may obtain a copy of the License at # 10 | # # 11 | # http://www.apache.org/licenses/LICENSE-2.0 # 12 | # # 13 | # Unless required by applicable law or agreed to in writing, software # 14 | # distributed under the License is distributed on an "AS IS" BASIS, # 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 16 | # See the License for the specific language governing permissions and # 17 | # limitations under the License. # 18 | ############################################################################### 19 | 20 | # run from ns3 root directory: ns-3.xx/ 21 | # 22 | # Example: 23 | # ./src/ns3-rmcat/tools/test_v2.csh wired 2020-08-25-rmcat-wired 24 | # ./src/ns3-rmcat/tools/test_v2.csh vparam 2020-08-25-rmcat-wired-vparam 25 | # ./src/ns3-rmcat/tools/test_v2.csh wifi 2020-08-25-rmcat-wifi 26 | # 27 | # The second parameter, output directory, is optional. If not specified, 28 | # the script will use a folder with a name based on current GMT time 29 | 30 | set scen = $1 31 | set odir = $2 32 | if ( "$odir" == "" ) then 33 | set odir = `date -u +"%Y-%m-%d-%H-%M-%S-CUT"` 34 | set odir = "testpy-output/$odir" 35 | endif 36 | 37 | set patched_script = test_patched.py 38 | 39 | # uncomment the following for building from scratch 40 | # 41 | # clean up and rebuild 42 | # echo "cleaning up and rebuiling ..." 43 | # ./waf clean 44 | # ./waf 45 | 46 | # patch test.py 47 | if ( ! -f "$patched_script") then 48 | rm -f "$patched_script" 49 | endif 50 | patch -p1 -i src/ns3-rmcat/tools/test.py.diff -o "$patched_script" test.py 51 | 52 | # run tests 53 | echo "running tests ..." 54 | python2 "$patched_script" -o $odir -s rmcat-$scen -w rmcat-$scen.html -r 55 | 56 | # process and plot 57 | echo "processing and plotting ..." 58 | python3 src/ns3-rmcat/tools/process_test_logs.py $odir 59 | python3 src/ns3-rmcat/tools/plot_tests.py $odir 60 | 61 | # for reviewing results 62 | #echo "reviewing results ..." 63 | #open $odir/*.png 64 | -------------------------------------------------------------------------------- /wscript: -------------------------------------------------------------------------------- 1 | # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- 2 | 3 | ############################################################################### 4 | # Copyright 2016-2017 Cisco Systems, Inc. # 5 | # # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); # 7 | # you may not use this file except in compliance with the License. # 8 | # # 9 | # You may obtain a copy of the License at # 10 | # # 11 | # http://www.apache.org/licenses/LICENSE-2.0 # 12 | # # 13 | # Unless required by applicable law or agreed to in writing, software # 14 | # distributed under the License is distributed on an "AS IS" BASIS, # 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 16 | # See the License for the specific language governing permissions and # 17 | # limitations under the License. # 18 | ############################################################################### 19 | 20 | def build(bld): 21 | module = bld.create_ns3_module('ns3-rmcat', ['wifi', 'point-to-point', 'applications', 'internet-apps']) 22 | module.source = [ 23 | 'model/apps/rmcat-sender.cc', 24 | 'model/apps/rmcat-receiver.cc', 25 | 'model/apps/rtp-header.cc', 26 | 'model/syncodecs/syncodecs.cc', 27 | 'model/syncodecs/traces-reader.cc', 28 | 'model/congestion-control/sender-based-controller.cc', 29 | 'model/congestion-control/dummy-controller.cc', 30 | 'model/congestion-control/nada-controller.cc', 31 | 'model/topo/topo.cc', 32 | 'model/topo/wired-topo.cc', 33 | 'model/topo/wifi-topo.cc', 34 | ] 35 | 36 | module.defines = ['NS3_ASSERT_ENABLE', 'NS3_LOG_ENABLE'] 37 | module.cxxflags = ['-std=c++11', '-g'] 38 | 39 | 40 | module_test = bld.create_ns3_module_test_library('ns3-rmcat') 41 | module_test.source = [ 42 | 'test/rmcat-common-test.cc', 43 | 'test/rmcat-wired-test-case.cc', 44 | 'test/rmcat-wired-test-suite.cc', 45 | 'test/rmcat-wired-varyparam-test-suite.cc', 46 | 'test/rmcat-wifi-test-case.cc', 47 | 'test/rmcat-wifi-test-suite.cc', 48 | ] 49 | 50 | headers = bld(features='ns3header') 51 | headers.module = 'ns3-rmcat' 52 | headers.source = [ 53 | 'model/apps/rmcat-constants.h', 54 | 'model/apps/rmcat-sender.h', 55 | 'model/apps/rmcat-receiver.h', 56 | 'model/apps/rtp-header.h', 57 | 'model/syncodecs/syncodecs.h', 58 | 'model/syncodecs/traces-reader.h', 59 | 'model/congestion-control/sender-based-controller.h', 60 | 'model/congestion-control/dummy-controller.h', 61 | 'model/congestion-control/nada-controller.h', 62 | 'model/topo/topo.h', 63 | 'model/topo/wired-topo.h', 64 | 'model/topo/wifi-topo.h', 65 | ] 66 | 67 | if bld.env.ENABLE_EXAMPLES: 68 | bld.recurse('examples') 69 | 70 | --------------------------------------------------------------------------------