OLD | NEW |
(Empty) | |
| 1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
| 2 /* |
| 3 * This program is free software; you can redistribute it and/or modify |
| 4 * it under the terms of the GNU General Public License version 2 as |
| 5 * published by the Free Software Foundation; |
| 6 * |
| 7 * This program is distributed in the hope that it will be useful, |
| 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 10 * GNU General Public License for more details. |
| 11 * |
| 12 * You should have received a copy of the GNU General Public License |
| 13 * along with this program; if not, write to the Free Software |
| 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 15 * |
| 16 */ |
| 17 |
| 18 // |
| 19 // Network topology |
| 20 // |
| 21 // 10Mb/s, 0.1ms 10Mb/s, 0.1ms |
| 22 // n0-----------------n1-----------------n2 |
| 23 // |
| 24 // Testcases for the correctness of TCP operations. |
| 25 // |
| 26 // Usage (e.g.): ./waf --run="tcp-testcases --case=1" |
| 27 // |
| 28 |
| 29 |
| 30 #include <ctype.h> |
| 31 #include <iostream> |
| 32 #include <iomanip> |
| 33 #include <fstream> |
| 34 #include <string> |
| 35 #include <cassert> |
| 36 |
| 37 #include "ns3/core-module.h" |
| 38 #include "ns3/common-module.h" |
| 39 #include "ns3/helper-module.h" |
| 40 #include "ns3/node-module.h" |
| 41 #include "ns3/simulator-module.h" |
| 42 |
| 43 using namespace ns3; |
| 44 |
| 45 NS_LOG_COMPONENT_DEFINE ("TcpTestCases"); |
| 46 |
| 47 // The number of bytes to send in this simulation. |
| 48 static uint32_t totalTxBytes = 200000; |
| 49 static uint32_t currentTxBytes = 0; |
| 50 // Perform series of 26*40=1040 byte writes (this is a multiple of 26 since |
| 51 // we want to detect data splicing in the output stream) |
| 52 static const uint32_t writeSize = 1040; |
| 53 uint8_t data[writeSize]; |
| 54 // Need to close the socket on node 0 upon finishing sending data |
| 55 static bool needToClose = true; |
| 56 |
| 57 //////////////////////////////////////////////////////////////////// |
| 58 // Implementing an "application" to send bytes over a TCP connection |
| 59 void WriteUntilBufferFull (Ptr<Socket> localSocket, uint32_t txSpace) |
| 60 { |
| 61 while (currentTxBytes < totalTxBytes) |
| 62 { |
| 63 uint32_t left = totalTxBytes - currentTxBytes; |
| 64 uint32_t dataOffset = currentTxBytes % writeSize; |
| 65 uint32_t toWrite = writeSize - dataOffset; |
| 66 uint32_t txAvail = localSocket->GetTxAvailable (); |
| 67 toWrite = std::min (toWrite, left); |
| 68 toWrite = std::min (toWrite, txAvail); |
| 69 if (txAvail == 0) |
| 70 { |
| 71 return; |
| 72 }; |
| 73 NS_LOG_LOGIC ("Submitting " << toWrite << " bytes to TCP socket"); |
| 74 int amountSent = localSocket->Send (&data[dataOffset], toWrite, 0); |
| 75 NS_ASSERT (amountSent > 0); // Given GetTxAvailable() non-zero, amountSen
t should not be zero |
| 76 currentTxBytes += amountSent; |
| 77 } |
| 78 if (needToClose) |
| 79 { |
| 80 NS_LOG_LOGIC ("Close socket at " << Simulator::Now ().GetSeconds ()); |
| 81 localSocket->Close (); |
| 82 needToClose = false; |
| 83 } |
| 84 } |
| 85 |
| 86 void StartFlow (Ptr<Socket> localSocket, |
| 87 Ipv4Address servAddress, |
| 88 uint16_t servPort) |
| 89 { |
| 90 NS_LOG_LOGIC ("Starting flow at time " << Simulator::Now ().GetSeconds ()); |
| 91 localSocket->Connect (InetSocketAddress (servAddress, servPort)); // connect |
| 92 |
| 93 // tell the tcp implementation to call WriteUntilBufferFull again |
| 94 // if we blocked and new tx buffer space becomes available |
| 95 localSocket->SetSendCallback (MakeCallback (&WriteUntilBufferFull)); |
| 96 WriteUntilBufferFull (localSocket, localSocket->GetTxAvailable ()); |
| 97 } |
| 98 |
| 99 // cwnd tracer |
| 100 static void |
| 101 CwndTracer (uint32_t oldval, uint32_t newval) |
| 102 { |
| 103 NS_LOG_INFO ("Moving cwnd from " << oldval << " to " << newval << " at time "
<< Simulator::Now ().GetSeconds () << " seconds"); |
| 104 } |
| 105 |
| 106 int main (int argc, char *argv[]) |
| 107 { |
| 108 std::string tcpModel ("ns3::TcpNewReno"); |
| 109 uint32_t testcase = 1; |
| 110 uint32_t verbose = 0; |
| 111 bool tracing = true; |
| 112 |
| 113 // Configuration and command line parameter parsing |
| 114 CommandLine cmd; |
| 115 cmd.AddValue ("tcpModel", "TCP congestion control model", tcpModel); |
| 116 cmd.AddValue ("testcase", "test case", testcase); |
| 117 cmd.AddValue ("verbose", "turn on selected log components", verbose); |
| 118 cmd.Parse (argc, argv); |
| 119 |
| 120 Config::SetDefault ("ns3::TcpL4Protocol::SocketType", StringValue (tcpModel)); |
| 121 Config::SetDefault ("ns3::TcpSocket::SegmentSize", UintegerValue (1000)); // 1
000-byte packet for easier reading |
| 122 Config::SetDefault ("ns3::TcpSocket::DelAckCount", UintegerValue (1)); |
| 123 Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (20)); |
| 124 |
| 125 LogComponentEnableAll (LOG_PREFIX_FUNC); |
| 126 LogComponentEnable ("TcpTestCases", LOG_LEVEL_ALL); |
| 127 if (verbose) |
| 128 { |
| 129 //LogComponentEnableAll (LOG_PREFIX_TIME); |
| 130 LogComponentEnable ("ErrorModel", LOG_LEVEL_DEBUG); |
| 131 LogComponentEnable ("TcpTestCases", LOG_LEVEL_ALL); |
| 132 LogComponentEnable ("TcpNewReno", LOG_LEVEL_INFO); |
| 133 LogComponentEnable ("TcpReno", LOG_LEVEL_INFO); |
| 134 LogComponentEnable ("TcpTahoe", LOG_LEVEL_INFO); |
| 135 LogComponentEnable ("TcpSocketBase", (verbose>1)?LOG_LEVEL_ALL:LOG_LEVEL_I
NFO); |
| 136 //LogComponentEnable ("TcpTxBuffer", LOG_LEVEL_ALL); |
| 137 //LogComponentEnable ("TcpRxBuffer", LOG_LEVEL_ALL); |
| 138 } |
| 139 |
| 140 // initialize the tx buffer (fill with lowercase a to z) |
| 141 for (uint32_t i = 0; i < writeSize; ++i) |
| 142 { |
| 143 char m = toascii (97 + i % 26); |
| 144 data[i] = m; |
| 145 } |
| 146 |
| 147 //////////////////////////////////////////////////////// |
| 148 // Topology construction |
| 149 // |
| 150 ·· |
| 151 // Create three nodes |
| 152 NodeContainer n0n1; |
| 153 n0n1.Create (2); |
| 154 Names::Add ("n0", n0n1.Get (0)); |
| 155 Names::Add ("n1", n0n1.Get (1)); |
| 156 |
| 157 NodeContainer n1n2; |
| 158 n1n2.Add (n0n1.Get (1)); |
| 159 n1n2.Create (1); |
| 160 Names::Add ("n2", n1n2.Get (1)); |
| 161 |
| 162 // Set up TCP/IP stack to all nodes (and create loopback device at device 0) |
| 163 InternetStackHelper internet; |
| 164 internet.InstallAll (); |
| 165 |
| 166 // Connect the nodes |
| 167 PointToPointHelper p2p; |
| 168 p2p.SetDeviceAttribute ("DataRate", DataRateValue (DataRate (1e6))); |
| 169 p2p.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (0.1))); |
| 170 NetDeviceContainer dev0 = p2p.Install (n0n1); |
| 171 NetDeviceContainer dev1 = p2p.Install (n1n2); |
| 172 |
| 173 // Add IP addresses to each network interfaces |
| 174 Ipv4AddressHelper ipv4; |
| 175 ipv4.SetBase ("10.1.3.0", "255.255.255.0"); |
| 176 ipv4.Assign (dev0); |
| 177 ipv4.SetBase ("10.1.2.0", "255.255.255.0"); |
| 178 Ipv4InterfaceContainer ipInterfs = ipv4.Assign (dev1); |
| 179 |
| 180 // Set up routes to all nodes |
| 181 Ipv4GlobalRoutingHelper::PopulateRoutingTables (); |
| 182 |
| 183 //////////////////////////////////////////////////////// |
| 184 // A flow from node n0 to node n2 |
| 185 // |
| 186 |
| 187 // Create a packet sink to receive packets on node n2 |
| 188 uint16_t servPort = 50000; // Destination port number |
| 189 PacketSinkHelper sink ("ns3::TcpSocketFactory", InetSocketAddress (Ipv4Address
::GetAny (), servPort)); |
| 190 ApplicationContainer apps = sink.Install (n1n2.Get (1)); |
| 191 apps.Start (Seconds (0.0)); |
| 192 apps.Stop (Seconds (100.0)); |
| 193 |
| 194 // Create a data source to send packets on node n0 |
| 195 // Instead of full application, here use the socket directly by |
| 196 // registering callbacks in function StarFlow(). |
| 197 Ptr<Socket> localSocket = Socket::CreateSocket (n0n1.Get (0), TcpSocketFactory
::GetTypeId ()); |
| 198 localSocket->Bind (); |
| 199 Simulator::ScheduleNow (&StartFlow, localSocket, ipInterfs.GetAddress (1), ser
vPort); |
| 200 |
| 201 // Trace changes to the congestion window (available in Tahoe and descendents) |
| 202 Config::ConnectWithoutContext ("/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/C
ongestionWindow", MakeCallback (&CwndTracer)); |
| 203 |
| 204 //////////////////////////////////////////////////////// |
| 205 // Set up different test cases: Lost model at node n1, different file size |
| 206 // |
| 207 |
| 208 std::list<uint32_t> dropListN0; |
| 209 std::list<uint32_t> dropListN1; |
| 210 switch (testcase) |
| 211 { |
| 212 case 0: // Verify connection establishment |
| 213 totalTxBytes = 1000; |
| 214 break; |
| 215 case 1: // Verify a bigger (100 pkts) transfer: Sliding window operation, et
c. |
| 216 totalTxBytes = 1e5; |
| 217 break; |
| 218 case 2: // Survive a SYN lost |
| 219 totalTxBytes = 1000; |
| 220 dropListN0.push_back (0); |
| 221 break; |
| 222 case 3: // Survive a SYN+ACK lost |
| 223 totalTxBytes = 2000; |
| 224 dropListN1.push_back (0); |
| 225 break; |
| 226 case 4: // Survive a ACK (last packet in 3-way handshake) lost |
| 227 totalTxBytes = 2000; |
| 228 dropListN0.push_back (1); |
| 229 break; |
| 230 case 5: // Immediate FIN upon SYN_RCVD |
| 231 totalTxBytes = 0; |
| 232 needToClose = false; |
| 233 dropListN0.push_back (1); // Hide the ACK in 3WHS |
| 234 Simulator::Schedule (Seconds(0.002), &Socket::Close, localSocket); |
| 235 break; |
| 236 case 6: // Simulated simultaneous close |
| 237 totalTxBytes = 5000; |
| 238 dropListN1.push_back (5); // Hide the ACK-to-FIN from n2 |
| 239 break; |
| 240 case 7: // FIN check 1: Lost of initiator's FIN. Shall wait until applicatio
n close. |
| 241 needToClose = false; |
| 242 totalTxBytes = 5000; |
| 243 dropListN0.push_back (7); // Hide the FIN from n0 |
| 244 Simulator::Schedule (Seconds(0.04), &Socket::Close, localSocket); |
| 245 break; |
| 246 case 8: // FIN check 2: Lost of responder's FIN. The FIN will resent after l
ast ack timeout |
| 247 totalTxBytes = 5000; |
| 248 dropListN1.push_back (6); // Hide the FIN from n2 |
| 249 break; |
| 250 default: |
| 251 NS_FATAL_ERROR ("Program fatal error: specified test case not supported: "
<< testcase); |
| 252 break; |
| 253 } |
| 254 |
| 255 Ptr<ReceiveListErrorModel> errN0 = CreateObject<ReceiveListErrorModel> (); |
| 256 errN0->SetList (dropListN0); |
| 257 dev0.Get (1)->SetAttribute ("ReceiveErrorModel", PointerValue (errN0)); |
| 258 |
| 259 Ptr<ReceiveListErrorModel> errN1 = CreateObject<ReceiveListErrorModel> (); |
| 260 errN1->SetList (dropListN1); |
| 261 dev1.Get (0)->SetAttribute ("ReceiveErrorModel", PointerValue (errN1)); |
| 262 |
| 263 ///////////////////////////////////////////////////////// |
| 264 // Set up trace and run the simulation |
| 265 // |
| 266 |
| 267 if (tracing) |
| 268 { |
| 269 // Ask for ASCII and pcap traces of network traffic |
| 270 AsciiTraceHelper ascii; |
| 271 //Ptr<OutputStreamWrapper> osw = ascii.CreateFileStream ("tcp-loss-respons
e.tr"); |
| 272 Ptr<OutputStreamWrapper> osw = Create<OutputStreamWrapper> (&std::clog); |
| 273 *(osw->GetStream ()) << std::setprecision(9) << std::fixed; |
| 274 p2p.EnableAsciiAll (osw); |
| 275 } |
| 276 |
| 277 // Finally, set up the simulator to run. The 1000 second hard limit is a |
| 278 // failsafe in case some change above causes the simulation to never end |
| 279 Simulator::Stop (Seconds (1000)); |
| 280 Simulator::Run (); |
| 281 Simulator::Destroy (); |
| 282 } |
OLD | NEW |