/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2018 Piotr Gawlowicz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Author: Piotr Gawlowicz * Based on script: ./examples/tcp/tcp-variants-comparison.cc * * Topology: * * Right Leafs (Clients) Left Leafs (Sinks) * | \ / | * | \ bottleneck / | * | R0--------------R1 | * | / \ | * | access / \ access | * N ----------- --------N */ #include #include #include #include "ns3/core-module.h" #include "ns3/network-module.h" #include "ns3/internet-module.h" #include "ns3/point-to-point-module.h" #include "ns3/point-to-point-layout-module.h" #include "ns3/applications-module.h" #include "ns3/error-model.h" #include "ns3/tcp-header.h" #include "ns3/enum.h" #include "ns3/event-id.h" #include "ns3/flow-monitor-helper.h" #include "ns3/ipv4-global-routing-helper.h" #include "ns3/traffic-control-module.h" #include "ns3/opengym-module.h" #include "tcp-rl.h" using namespace ns3; NS_LOG_COMPONENT_DEFINE ("TcpVariantsComparison"); static std::vector rxPkts; static void CountRxPkts(uint32_t sinkId, Ptr packet, const Address & srcAddr) { rxPkts[sinkId]++; } static void PrintRxCount() { uint32_t size = rxPkts.size(); NS_LOG_UNCOND("RxPkts:"); for (uint32_t i=0; i openGymInterface; if (transport_prot.compare ("ns3::TcpRl") == 0) { openGymInterface = OpenGymInterface::Get(openGymPort); Config::SetDefault ("ns3::TcpRl::Reward", DoubleValue (2.0)); // Reward when increasing congestion window Config::SetDefault ("ns3::TcpRl::Penalty", DoubleValue (-30.0)); // Penalty when decreasing congestion window } if (transport_prot.compare ("ns3::TcpRlTimeBased") == 0) { openGymInterface = OpenGymInterface::Get(openGymPort); Config::SetDefault ("ns3::TcpRlTimeBased::StepTime", TimeValue (Seconds(tcpEnvTimeStep))); // Time step of env Config::SetDefault ("ns3::TcpRlTimeBased::Duration", TimeValue (Seconds(duration))); // Duration of env sim Config::SetDefault ("ns3::TcpRlTimeBased::Reward", DoubleValue (1.0)); // Reward Config::SetDefault ("ns3::TcpRlTimeBased::Penalty", DoubleValue (-1.0)); // Penalty } // Calculate the ADU size Header* temp_header = new Ipv4Header (); uint32_t ip_header = temp_header->GetSerializedSize (); NS_LOG_LOGIC ("IP Header size is: " << ip_header); delete temp_header; temp_header = new TcpHeader (); uint32_t tcp_header = temp_header->GetSerializedSize (); NS_LOG_LOGIC ("TCP Header size is: " << tcp_header); delete temp_header; uint32_t tcp_adu_size = mtu_bytes - 20 - (ip_header + tcp_header); NS_LOG_LOGIC ("TCP ADU size is: " << tcp_adu_size); // Set the simulation start and stop time double start_time = 0.1; // it takes some time to initialise some variables, idk why double stop_time = start_time + duration; // 4 MB of TCP buffer Config::SetDefault ("ns3::TcpSocket::RcvBufSize", UintegerValue (1 << 21)); Config::SetDefault ("ns3::TcpSocket::SndBufSize", UintegerValue (1 << 21)); Config::SetDefault ("ns3::TcpSocketBase::Sack", BooleanValue (sack)); // no. of packets received before an ACK is sent (why is the default 2?) Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (2)); Config::SetDefault ("ns3::TcpL4Protocol::RecoveryType", TypeIdValue (TypeId::LookupByName (recovery))); // Select TCP variant if (transport_prot.compare ("ns3::TcpWestwoodPlus") == 0) { // TcpWestwoodPlus is not an actual TypeId name; we need TcpWestwood here Config::SetDefault ("ns3::TcpL4Protocol::SocketType", TypeIdValue (TcpWestwood::GetTypeId ())); // the default protocol type in ns3::TcpWestwood is WESTWOOD Config::SetDefault ("ns3::TcpWestwood::ProtocolType", EnumValue (TcpWestwood::WESTWOODPLUS)); } else { TypeId tcpTid; NS_ABORT_MSG_UNLESS (TypeId::LookupByNameFailSafe (transport_prot, &tcpTid), "TypeId " << transport_prot << " not found"); Config::SetDefault ("ns3::TcpL4Protocol::SocketType", TypeIdValue (TypeId::LookupByName (transport_prot))); } // Configure the error model // Here we use RateErrorModel with packet error rate Ptr uv = CreateObject (); uv->SetStream (50); RateErrorModel error_model; error_model.SetRandomVariable (uv); error_model.SetUnit (RateErrorModel::ERROR_UNIT_PACKET); error_model.SetRate (error_p); // Create the point-to-point link helpers PointToPointHelper bottleNeckLink; bottleNeckLink.SetDeviceAttribute ("DataRate", StringValue (bottleneck_bandwidth)); bottleNeckLink.SetChannelAttribute ("Delay", StringValue (bottleneck_delay)); //bottleNeckLink.SetDeviceAttribute ("ReceiveErrorModel", PointerValue (&error_model)); PointToPointHelper pointToPointLeaf; pointToPointLeaf.SetDeviceAttribute ("DataRate", StringValue (access_bandwidth)); pointToPointLeaf.SetChannelAttribute ("Delay", StringValue (access_delay)); PointToPointDumbbellHelper d (nLeaf, pointToPointLeaf, nLeaf, pointToPointLeaf, bottleNeckLink); // Install IP stack InternetStackHelper stack; stack.InstallAll (); // Traffic Control TrafficControlHelper tchPfifo; tchPfifo.SetRootQueueDisc ("ns3::PfifoFastQueueDisc"); TrafficControlHelper tchCoDel; tchCoDel.SetRootQueueDisc ("ns3::CoDelQueueDisc"); DataRate access_b (access_bandwidth); DataRate bottle_b (bottleneck_bandwidth); Time access_d (access_delay); Time bottle_d (bottleneck_delay); uint32_t size = static_cast((std::min (access_b, bottle_b).GetBitRate () / 8) * ((access_d + bottle_d + access_d) * 2).GetSeconds ()); Config::SetDefault ("ns3::PfifoFastQueueDisc::MaxSize", QueueSizeValue (QueueSize (QueueSizeUnit::PACKETS, size / mtu_bytes))); Config::SetDefault ("ns3::CoDelQueueDisc::MaxSize", QueueSizeValue (QueueSize (QueueSizeUnit::BYTES, size))); if (queue_disc_type.compare ("ns3::PfifoFastQueueDisc") == 0) { tchPfifo.Install (d.GetLeft()->GetDevice(1)); tchPfifo.Install (d.GetRight()->GetDevice(1)); } else if (queue_disc_type.compare ("ns3::CoDelQueueDisc") == 0) { tchCoDel.Install (d.GetLeft()->GetDevice(1)); tchCoDel.Install (d.GetRight()->GetDevice(1)); } else { NS_FATAL_ERROR ("Queue not recognized. Allowed values are ns3::CoDelQueueDisc or ns3::PfifoFastQueueDisc"); } // Assign IP Addresses d.AssignIpv4Addresses (Ipv4AddressHelper ("10.1.1.0", "255.255.255.0"), Ipv4AddressHelper ("10.2.1.0", "255.255.255.0"), Ipv4AddressHelper ("10.3.1.0", "255.255.255.0")); NS_LOG_INFO ("Initialize Global Routing."); Ipv4GlobalRoutingHelper::PopulateRoutingTables (); // Install apps in left and right nodes uint16_t port = 50000; Address sinkLocalAddress (InetSocketAddress (Ipv4Address::GetAny (), port)); PacketSinkHelper sinkHelper ("ns3::TcpSocketFactory", sinkLocalAddress); ApplicationContainer sinkApps; for (uint32_t i = 0; i < d.RightCount (); ++i) { sinkHelper.SetAttribute ("Protocol", TypeIdValue (TcpSocketFactory::GetTypeId ())); sinkApps.Add (sinkHelper.Install (d.GetRight (i))); } sinkApps.Start (Seconds (0.0)); sinkApps.Stop (Seconds (stop_time)); for (uint32_t i = 0; i < d.LeftCount (); ++i) { // Create an on/off app sending packets to the left side AddressValue remoteAddress (InetSocketAddress (d.GetRightIpv4Address (i), port)); Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (tcp_adu_size)); BulkSendHelper ftp ("ns3::TcpSocketFactory", Address ()); ftp.SetAttribute ("Remote", remoteAddress); ftp.SetAttribute ("SendSize", UintegerValue (tcp_adu_size)); ftp.SetAttribute ("MaxBytes", UintegerValue (data_mbytes * 1000000)); ApplicationContainer clientApp = ftp.Install (d.GetLeft (i)); clientApp.Start (Seconds (start_time * i)); // Start after sink clientApp.Stop (Seconds (stop_time - 3)); // Stop before the sink } // Flow monitor FlowMonitorHelper flowHelper; if (flow_monitor) { flowHelper.InstallAll (); } // Count RX packets for (uint32_t i = 0; i < d.RightCount (); ++i) { rxPkts.push_back(0); Ptr pktSink = DynamicCast(sinkApps.Get(i)); pktSink->TraceConnectWithoutContext ("Rx", MakeBoundCallback (&CountRxPkts, i)); } Simulator::Stop (Seconds (stop_time)); Simulator::Run (); if (flow_monitor) { flowHelper.SerializeToXmlFile (prefix_file_name + ".flowmonitor", true, true); } if (transport_prot.compare ("ns3::TcpRl") == 0 or transport_prot.compare ("ns3::TcpRlTimeBased") == 0) { openGymInterface->NotifySimulationEnd(); } PrintRxCount(); Simulator::Destroy (); return 0; }