A Discrete-Event Network Simulator
API
tcp-rate-ops-test.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018 NITK Surathkal
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 *
17 * Authors: Vivek Jain <jain.vivek.anand@gmail.com>
18 * Viyom Mittal <viyommittal@gmail.com>
19 * Mohit P. Tahiliani <tahiliani@nitk.edu.in>
20 */
21
22#include "tcp-error-model.h"
23#include "tcp-general-test.h"
24
25#include "ns3/config.h"
26#include "ns3/log.h"
27#include "ns3/tcp-rate-ops.h"
28#include "ns3/tcp-tx-buffer.h"
29#include "ns3/tcp-tx-item.h"
30#include "ns3/test.h"
31
32using namespace ns3;
33
34NS_LOG_COMPONENT_DEFINE("TcpRateOpsTestSuite");
35
37
45{
46 public:
56 SequenceNumber32 tailSeq,
57 SequenceNumber32 nextTx,
58 uint32_t testCase,
59 std::string testName);
60
61 private:
62 void DoRun() override;
63
68 void SendSkb(TcpTxItem* skb);
73 void SkbDelivered(TcpTxItem* skb);
74
84 std::vector<TcpTxItem*> m_skbs;
85};
86
88 SequenceNumber32 tailSeq,
89 SequenceNumber32 nextTx,
90 uint32_t testCase,
91 std::string testName)
92 : TestCase(testName),
93 m_cWnd(cWnd),
94 m_inFlight(0),
95 m_segmentSize(1),
96 m_delivered(0),
97 m_deliveredTime(Seconds(0)),
98 m_tailSeq(tailSeq),
99 m_nextTx(nextTx),
100 m_testCase(testCase)
101{
102}
103
104void
106{
107 for (uint8_t i = 0; i < 100; ++i)
108 {
109 m_skbs.push_back(new TcpTxItem());
110 Simulator::Schedule(Time(Seconds(i * 0.01)),
112 this,
113 m_skbs[i]);
114 }
115
116 for (uint8_t i = 0; i < 100; ++i)
117 {
118 Simulator::Schedule(Time(Seconds((i + 1) * 0.1)),
120 this,
121 m_skbs[i]);
122 }
123
124 Simulator::Run();
125 Simulator::Destroy();
126
127 for (uint8_t i = 0; i < 100; ++i)
128 {
129 delete m_skbs[i];
130 }
131}
132
133void
135{
136 bool isStartOfTransmission = m_inFlight == 0;
138 m_rateOps.SkbSent(skb, isStartOfTransmission);
139 m_inFlight += skb->GetSeqSize();
140
143 "SKB should have delivered equal to current value of total delivered");
144
145 if (isStartOfTransmission)
146 {
149 "SKB should have updated the delivered time to current value");
150 }
151 else
152 {
155 "SKB should have updated the delivered time to current value");
156 }
157}
158
159void
161{
163 m_inFlight -= skb->GetSeqSize();
164 m_delivered += skb->GetSeqSize();
166
168 Time::Max(),
169 "SKB should have delivered time as Time::Max ()");
170
171 if (m_testCase == 1)
172 {
174 false,
175 "Socket should not be applimited");
176 }
177 else if (m_testCase == 2)
178 {
180 true,
181 "Socket should be applimited");
182 }
183}
184
192{
193 public:
198 static TypeId GetTypeId();
199
201 {
202 }
203
204 bool HasCongControl() const override
205 {
206 return true;
207 }
208};
209
210TypeId
212{
213 static TypeId tid = TypeId("ns3::MimicCongControl")
215 .AddConstructor<MimicCongControl>()
216 .SetGroupName("Internet");
217 return tid;
218}
219
232{
233 public:
240 TcpRateLinuxWithSocketsTest(const std::string& desc,
241 bool sackEnabled,
242 std::vector<uint32_t>& toDrop);
243
244 protected:
251
257
264 void Rx(const Ptr<const Packet> p, const TcpHeader& h, SocketWho who) override;
265
271 void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override;
272
279 void PktDropped(const Ipv4Header& ipH, const TcpHeader& tcpH, Ptr<const Packet> p);
280
284 void ConfigureEnvironment() override;
285
289 void FinalChecks() override;
290
295 void RateUpdatedTrace(const TcpRateLinux::TcpRateConnection& rate) override;
296
301 void RateSampleUpdatedTrace(const TcpRateLinux::TcpRateSample& sample) override;
302
303 private:
306 std::vector<uint32_t> m_toDrop;
310 TcpRateLinux::TcpRateConnection m_prevRate;
311 TcpRateLinux::TcpRateSample m_prevRateSample;
312};
313
315 bool sackEnabled,
316 std::vector<uint32_t>& toDrop)
317 : TcpGeneralTest(desc),
318 m_sackEnabled(sackEnabled),
319 m_toDrop(toDrop)
320{
321}
322
325{
326 Ptr<TcpSocketMsgBase> s = TcpGeneralTest::CreateSenderSocket(node);
327 m_congCtl = CreateObject<MimicCongControl>();
328 s->SetCongestionControlAlgorithm(m_congCtl);
329 return s;
330}
331
332void
334{
335 TcpGeneralTest::ConfigureEnvironment();
336 SetAppPktCount(300);
339
340 Config::SetDefault("ns3::TcpSocketBase::Sack", BooleanValue(m_sackEnabled));
341}
342
345{
346 Ptr<TcpSeqErrorModel> m_errorModel = CreateObject<TcpSeqErrorModel>();
347 for (std::vector<uint32_t>::iterator it = m_toDrop.begin(); it != m_toDrop.end(); ++it)
348 {
349 m_errorModel->AddSeqToKill(SequenceNumber32(*it));
350 }
351
353
354 return m_errorModel;
355}
356
357void
359 const TcpHeader& tcpH,
361{
362 NS_LOG_DEBUG("Drop seq= " << tcpH.GetSequenceNumber() << " size " << p->GetSize());
363}
364
365void
367{
368 if (who == SENDER)
369 {
371 (h.GetFlags() & TcpHeader::FIN) == 0)
372 {
373 m_isDupAck = true;
374 }
375 else
376 {
377 m_isDupAck = false;
379 }
380 }
381}
382
383void
385{
386 m_bytesInFlight = newValue;
387}
388
389void
390TcpRateLinuxWithSocketsTest::RateUpdatedTrace(const TcpRateLinux::TcpRateConnection& rate)
391{
392 NS_LOG_DEBUG("Rate updated " << rate);
393 if (m_bytesInFlight == 0)
394 {
395 NS_TEST_ASSERT_MSG_EQ(rate.m_firstSentTime,
397 "FirstSentTime should be current time when bytes inflight is zero");
398 NS_TEST_ASSERT_MSG_EQ(rate.m_deliveredTime,
400 "Delivered time should be current time when bytes inflight is zero");
401 }
402 NS_TEST_ASSERT_MSG_GT_OR_EQ(rate.m_delivered,
403 m_prevRate.m_delivered,
404 "Total delivered should not be lesser than previous values");
405 m_prevRate = rate;
406}
407
408void
409TcpRateLinuxWithSocketsTest::RateSampleUpdatedTrace(const TcpRateLinux::TcpRateSample& sample)
410{
411 NS_LOG_DEBUG("Rate sample updated " << sample);
412 if (m_isDupAck)
413 {
414 if (!m_sackEnabled)
415 {
417 sample,
418 "RateSample should not update due to DupAcks");
419 }
420 else
421 {
422 if (sample.m_ackedSacked == 0)
423 {
425 sample,
426 "RateSample should not update as nothing is acked or sacked");
427 }
428 }
429 }
430 m_prevRateSample = sample;
431}
432
433void
435{
436}
437
446{
447 public:
454
455 private:
456 void DoRun() override;
457 void DoTeardown() override;
458
463 virtual void RateUpdatedTrace(const TcpRateLinux::TcpRateConnection& rate);
464
469 virtual void RateSampleUpdatedTrace(const TcpRateLinux::TcpRateSample& sample);
470
473
475 void TestWithSackBlocks();
476
482};
483
485 : TestCase(testString),
486 m_segmentSize(segmentSize)
487{
488 m_rateOps = CreateObject<TcpRateLinux>();
490 "TcpRateUpdated",
493 "TcpRateSampleUpdated",
495}
496
497void
499{
500 Simulator::Schedule(Seconds(0.0), &TcpRateLinuxWithBufferTest::TestWithSackBlocks, this);
501 Simulator::Run();
502 Simulator::Destroy();
503}
504
505void
506TcpRateLinuxWithBufferTest::RateUpdatedTrace(const TcpRateLinux::TcpRateConnection& rate)
507{
508 NS_LOG_DEBUG("Rate updated " << rate);
509 NS_TEST_ASSERT_MSG_EQ(rate.m_delivered,
511 "Delivered data is not equal to expected delivered");
512}
513
514void
515TcpRateLinuxWithBufferTest::RateSampleUpdatedTrace(const TcpRateLinux::TcpRateSample& sample)
516{
517 NS_LOG_DEBUG("Rate sample updated " << sample);
518 NS_TEST_ASSERT_MSG_EQ(sample.m_ackedSacked,
520 "AckedSacked bytes is not equal to expected AckedSacked bytes");
521}
522
523void
525{
526 SequenceNumber32 head(1);
529 Ptr<TcpOptionSack> sack = CreateObject<TcpOptionSack>();
532
533 m_txBuf.Add(Create<Packet>(10 * m_segmentSize));
534
535 // Send 10 Segments
536 for (uint8_t i = 0; i < 10; ++i)
537 {
538 bool isStartOfTransmission = m_txBuf.BytesInFlight() == 0;
539 TcpTxItem* outItem =
541 m_rateOps->SkbSent(outItem, isStartOfTransmission);
542 }
543
544 uint32_t priorInFlight = m_txBuf.BytesInFlight();
545 // ACK 2 Segments
546 for (uint8_t i = 1; i <= 2; ++i)
547 {
548 priorInFlight = m_txBuf.BytesInFlight();
551 MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
553 m_rateOps->GenerateSample(m_segmentSize, 0, false, priorInFlight, Seconds(0));
554 }
555
556 priorInFlight = m_txBuf.BytesInFlight();
557 sack->AddSackBlock(TcpOptionSack::SackBlock(SequenceNumber32(m_segmentSize * 4 + 1),
560 m_txBuf.Update(sack->GetSackList(), MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
562 m_rateOps->GenerateSample(m_segmentSize, 0, false, priorInFlight, Seconds(0));
563
564 priorInFlight = m_txBuf.BytesInFlight();
565 sack->AddSackBlock(TcpOptionSack::SackBlock(SequenceNumber32(m_segmentSize * 3 + 1),
568 m_txBuf.Update(sack->GetSackList(), MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
569 m_rateOps->GenerateSample(m_segmentSize, 0, false, priorInFlight, Seconds(0));
570
571 priorInFlight = m_txBuf.BytesInFlight();
572 // Actual delivered should be increased by one segment even multiple blocks are acked.
575 MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
576 m_rateOps->GenerateSample(m_segmentSize, 0, false, priorInFlight, Seconds(0));
577
578 priorInFlight = m_txBuf.BytesInFlight();
579 // ACK rest of the segments
580 for (uint8_t i = 6; i <= 10; ++i)
581 {
584 MakeCallback(&TcpRateOps::SkbDelivered, m_rateOps));
585 }
587 TcpRateOps::TcpRateSample rateSample =
588 m_rateOps->GenerateSample(5 * m_segmentSize, 0, false, priorInFlight, Seconds(0));
589}
590
591void
593{
594}
595
603{
604 public:
606 : TestSuite("tcp-rate-ops", UNIT)
607 {
611 1,
612 "Testing SkbDelivered and SkbSent"),
613 TestCase::QUICK);
615 new TcpRateLinuxBasicTest(1000,
618 2,
619 "Testing SkbDelivered and SkbSent with app limited data"),
620 TestCase::QUICK);
621
622 std::vector<uint32_t> toDrop;
623 toDrop.push_back(4001);
625 new TcpRateLinuxWithSocketsTest("Checking Rate sample value without SACK, one drop",
626 false,
627 toDrop),
628 TestCase::QUICK);
629
631 new TcpRateLinuxWithSocketsTest("Checking Rate sample value with SACK, one drop",
632 true,
633 toDrop),
634 TestCase::QUICK);
635 toDrop.push_back(4001);
637 new TcpRateLinuxWithSocketsTest("Checking Rate sample value without SACK, two drop",
638 false,
639 toDrop),
640 TestCase::QUICK);
641
643 new TcpRateLinuxWithSocketsTest("Checking Rate sample value with SACK, two drop",
644 true,
645 toDrop),
646 TestCase::QUICK);
647
650 "Checking rate sample values with arbitary SACK Block"),
651 TestCase::QUICK);
652
655 "Checking rate sample values with arbitary SACK Block"),
656 TestCase::QUICK);
657 }
658};
659
#define Max(a, b)
Behaves as NewReno except HasCongControl returns true.
static TypeId GetTypeId()
Get the type ID.
bool HasCongControl() const override
Returns true when Congestion Control Algorithm implements CongControl.
The TcpRateLinux Basic Test.
void SkbDelivered(TcpTxItem *skb)
Deliver an application packet.
uint32_t m_delivered
Number of segments delivered.
void SendSkb(TcpTxItem *skb)
Send an application packet.
uint32_t m_segmentSize
Segment size.
TcpRateLinux m_rateOps
Rate information for TCP.
Time m_deliveredTime
Last time of a delivery.
uint32_t m_testCase
Test case type.
uint32_t m_inFlight
Number of packets in-flight.
uint32_t m_cWnd
Congestion window size.
TcpRateLinuxBasicTest(uint32_t cWnd, SequenceNumber32 tailSeq, SequenceNumber32 nextTx, uint32_t testCase, std::string testName)
Constructor.
SequenceNumber32 m_tailSeq
Tail sequence number.
void DoRun() override
Implementation to actually run this TestCase.
std::vector< TcpTxItem * > m_skbs
Application packets.
SequenceNumber32 m_nextTx
Tx next sequence number.
The TcpRateLinuxWithBufferTest tests rate sample functionality with arbitary SACK scenario.
uint32_t m_expectedAckedSacked
Amount of expected acked sacked data.
void DoRun() override
Implementation to actually run this TestCase.
void TestWithStraightAcks()
Test with acks without drop.
TcpTxBuffer m_txBuf
Tcp Tx buffer.
virtual void RateUpdatedTrace(const TcpRateLinux::TcpRateConnection &rate)
Track the rate value of TcpRateLinux.
TcpRateLinuxWithBufferTest(uint32_t segmentSize, std::string desc)
Constructor.
virtual void RateSampleUpdatedTrace(const TcpRateLinux::TcpRateSample &sample)
Track the rate sample value of TcpRateLinux.
void TestWithSackBlocks()
Test with arbitary SACK scenario.
Ptr< TcpRateOps > m_rateOps
Rate operations.
uint32_t m_expectedDelivered
Amount of expected delivered data.
void DoTeardown() override
Implementation to do any local setup required for this TestCase.
uint32_t m_segmentSize
Segment size.
The TcpRateLinux Test uses sender-receiver model to test its functionality.
void PktDropped(const Ipv4Header &ipH, const TcpHeader &tcpH, Ptr< const Packet > p)
Called when a packet is dropped.
TcpRateLinuxWithSocketsTest(const std::string &desc, bool sackEnabled, std::vector< uint32_t > &toDrop)
Constructor.
void Rx(const Ptr< const Packet > p, const TcpHeader &h, SocketWho who) override
Receive a packet.
Ptr< TcpSocketMsgBase > CreateSenderSocket(Ptr< Node > node) override
Create and install the socket to install on the sender.
bool m_isDupAck
Whether ACK is DupAck.
void BytesInFlightTrace(uint32_t oldValue, uint32_t newValue) override
Track the bytes in flight.
void ConfigureEnvironment() override
Configure the test.
void FinalChecks() override
Do the final checks.
void RateSampleUpdatedTrace(const TcpRateLinux::TcpRateSample &sample) override
Track the rate sample value of TcpRateLinux.
SequenceNumber32 m_lastAckRecv
Last ACK received.
TcpRateLinux::TcpRateSample m_prevRateSample
Previous rate sample.
std::vector< uint32_t > m_toDrop
List of SequenceNumber to drop.
Ptr< ErrorModel > CreateReceiverErrorModel() override
Create a receiver error model.
uint32_t m_bytesInFlight
Bytes inflight.
bool m_sackEnabled
Sack Variable.
void RateUpdatedTrace(const TcpRateLinux::TcpRateConnection &rate) override
Track the rate value of TcpRateLinux.
TcpRateLinux::TcpRateConnection m_prevRate
Previous rate.
Ptr< MimicCongControl > m_congCtl
Dummy congestion control.
the TestSuite for the TcpRateLinux test case
AttributeValue implementation for Boolean.
Definition: boolean.h:37
Packet header for IPv4.
Definition: ipv4-header.h:34
bool TraceConnectWithoutContext(std::string name, const CallbackBase &cb)
Connect a TraceSource to a Callback without a context.
Definition: object-base.cc:369
uint32_t GetSize() const
Returns the the size in bytes of the packet (including the zero-filled initial payload).
Definition: packet.h:863
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:78
void SetDropCallback(Callback< void, const Ipv4Header &, const TcpHeader &, Ptr< const Packet > > cb)
Set the drop callback.
General infrastructure for TCP testing.
void SetPropagationDelay(Time propDelay)
Propagation delay of the bottleneck link.
void SetAppPktCount(uint32_t pktCount)
Set app packet count.
SocketWho
Used as parameter of methods, specifies on what node the caller is interested (e.g.
void SetTransmitStart(Time startTime)
Set the initial time at which the application sends the first data packet.
Header for the Transmission Control Protocol.
Definition: tcp-header.h:46
SequenceNumber32 GetSequenceNumber() const
Get the sequence number.
Definition: tcp-header.cc:137
uint8_t GetFlags() const
Get the flags.
Definition: tcp-header.cc:167
SequenceNumber32 GetAckNumber() const
Get the ACK number.
Definition: tcp-header.cc:143
The NewReno implementation.
std::pair< SequenceNumber32, SequenceNumber32 > SackBlock
SACK block definition.
Linux management and generation of Rate information for TCP.
Definition: tcp-rate-ops.h:195
void SkbDelivered(TcpTxItem *skb) override
Update the Rate information after an item is received.
void SkbSent(TcpTxItem *skb, bool isStartOfTransmission) override
Put the rate information inside the sent skb.
void CalculateAppLimited(uint32_t cWnd, uint32_t in_flight, uint32_t segmentSize, const SequenceNumber32 &tailSeq, const SequenceNumber32 &nextTx, const uint32_t lostOut, const uint32_t retransOut) override
If a gap is detected between sends, it means we are app-limited.
virtual const TcpRateSample & GenerateSample(uint32_t delivered, uint32_t lost, bool is_sack_reneg, uint32_t priorInFlight, const Time &minRtt)=0
Generate a TcpRateSample to feed a congestion avoidance algorithm.
virtual void SkbSent(TcpTxItem *skb, bool isStartOfTransmission)=0
Put the rate information inside the sent skb.
void AddSeqToKill(const SequenceNumber32 &seq)
Add the sequence number to the list of segments to be killed.
Tcp sender buffer.
bool Add(Ptr< Packet > p)
Append a data packet to the end of the buffer.
void SetSegmentSize(uint32_t segmentSize)
Set the segment size.
void SetDupAckThresh(uint32_t dupAckThresh)
Set the DupAckThresh.
TcpTxItem * CopyFromSequence(uint32_t numBytes, const SequenceNumber32 &seq)
Copy data from the range [seq, seq+numBytes) into a packet.
uint32_t Update(const TcpOptionSack::SackList &list, const Callback< void, TcpTxItem * > &sackedCb=m_nullCb)
Update the scoreboard.
uint32_t BytesInFlight() const
Return total bytes in flight.
void DiscardUpTo(const SequenceNumber32 &seq, const Callback< void, TcpTxItem * > &beforeDelCb=m_nullCb)
Discard data up to but not including this sequence number.
void SetHeadSequence(const SequenceNumber32 &seq)
Set the head sequence of the buffer.
Item that encloses the application packet and some flags for it.
Definition: tcp-tx-item.h:33
uint32_t GetSeqSize() const
Get the size in the sequence number space.
Definition: tcp-tx-item.cc:61
RateInformation & GetRateInformation()
Get (to modify) the Rate Information of this item.
Definition: tcp-tx-item.cc:97
encapsulates test code
Definition: test.h:1060
void AddTestCase(TestCase *testCase, TestDuration duration=QUICK)
Add an individual child TestCase to this test suite.
Definition: test.cc:305
A suite of tests to run.
Definition: test.h:1256
@ UNIT
This test suite implements a Unit Test.
Definition: test.h:1265
Simulation virtual time values and global simulation resolution.
Definition: nstime.h:105
a unique identifier for an interface.
Definition: type-id.h:60
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
uint32_t segmentSize
void SetDefault(std::string name, const AttributeValue &value)
Definition: config.cc:891
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_DEBUG(msg)
Use NS_LOG to output a message of level LOG_DEBUG.
Definition: log.h:268
SequenceNumber< uint32_t, int32_t > SequenceNumber32
32 bit Sequence number.
Time Now()
create an ns3::Time instance which contains the current simulation time.
Definition: simulator.cc:296
#define NS_TEST_ASSERT_MSG_EQ(actual, limit, msg)
Test that an actual and expected (limit) value are equal and report and abort if not.
Definition: test.h:144
#define NS_TEST_ASSERT_MSG_GT_OR_EQ(actual, limit, msg)
Test that an actual value is greater than or equal to a limit and report and abort if not.
Definition: test.h:915
Time Seconds(double value)
Construct a Time in the indicated unit.
Definition: nstime.h:1338
Time MilliSeconds(uint64_t value)
Construct a Time in the indicated unit.
Definition: nstime.h:1350
void(* Time)(Time oldValue, Time newValue)
TracedValue callback signature for Time.
Definition: nstime.h:850
Every class exported by the ns3 library is enclosed in the ns3 namespace.
Callback< R, Args... > MakeCallback(R(T::*memPtr)(Args...), OBJ objPtr)
Build Callbacks for class method members which take varying numbers of arguments and potentially retu...
Definition: callback.h:691
Rate Sample structure.
Definition: tcp-rate-ops.h:139
bool m_isAppLimited
Connection's app limited at the time the packet was sent.
Definition: tcp-tx-item.h:94
uint64_t m_delivered
Connection's delivered data at the time the packet was sent.
Definition: tcp-tx-item.h:89
Time m_deliveredTime
Connection's delivered time at the time the packet was sent.
Definition: tcp-tx-item.h:90
static TcpRateOpsTestSuite g_TcpRateOpsTestSuite
Static variable for test initialization.