Index: src/internet/test/tcp-ecn-test.cc |
=================================================================== |
new file mode 100644 |
--- /dev/null |
+++ b/src/internet/test/tcp-ecn-test.cc |
@@ -0,0 +1,567 @@ |
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ |
+/* |
+ * Copyright (c) 2016 NITK Surathkal |
+ * |
+ * 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 |
+ * |
+ * Authors: Shravya Ks <shravya.ks0@gmail.com> |
+ * |
+ */ |
+#include "ns3/ipv4.h" |
+#include "ns3/ipv6.h" |
+#include "ns3/ipv4-interface-address.h" |
+#include "ns3/ipv4-route.h" |
+#include "ns3/ipv6-route.h" |
+#include "ns3/ipv4-routing-protocol.h" |
+#include "ns3/ipv6-routing-protocol.h" |
+#include "../model/ipv4-end-point.h" |
+#include "../model/ipv6-end-point.h" |
+#include "tcp-general-test.h" |
+#include "ns3/node.h" |
+#include "ns3/log.h" |
+#include "tcp-error-model.h" |
+#include "ns3/tcp-l4-protocol.h" |
+ |
+namespace ns3 { |
+ |
+NS_LOG_COMPONENT_DEFINE ("TcpECNTestSuite"); |
+/** |
+ * \ingroup internet-test |
+ * \ingroup tests |
+ * |
+ * \brief checks if ECT, CWR and ECE bits are set correctly in different scenarios |
+ * |
+ * This test suite will run four combinations of enabling ECN (sender off and receiver off; sender on and sender off; |
+ * sender off and receiver on; sender on and receiver on;) and checks that the TOS byte of eventual packets transmitted |
+ * or received have ECT, CWR, and ECE set correctly (or not). It also checks if congestion window is being reduced by half |
+ * only once per every window on receipt of ECE flags |
+ * |
+ */ |
+class TcpECNTest : public TcpGeneralTest |
+{ |
+public: |
+ /** |
+ * \brief Constructor |
+ * |
+ * \param testcase test case number |
+ * \param desc Description about the ECN capabilities of sender and reciever |
+ */ |
+ TcpECNTest (uint32_t testcase, const std::string &desc); |
+ |
+protected: |
+ virtual void CWndTrace (uint32_t oldValue, uint32_t newValue); |
+ virtual void Rx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who); |
+ virtual void Tx (const Ptr<const Packet> p, const TcpHeader&h, SocketWho who); |
+ virtual Ptr<TcpSocketMsgBase> CreateSenderSocket (Ptr<Node> node); |
+ void ConfigureProperties (); |
+ |
+private: |
+ uint32_t m_cwndChangeCount; |
+ uint32_t m_senderSent; |
+ uint32_t m_receiverSent; |
+ uint32_t m_senderReceived; |
+ uint32_t m_receiverReceived; |
+ uint32_t m_testcase; |
+}; |
+ |
+ |
+/** |
+ * \ingroup internet-test |
+ * \ingroup tests |
+ * |
+ * \brief A TCP socket which sends certain data packets with CE flags set for tests 5 and 6. |
+ * |
+ * The SendDataPacket function of this class sends data packets numbered 1 and 2 with CE flags set |
+ * for test 5 to verify if ECE and CWR bits are correctly set by receiver and sender respectively. It |
+ * also sets CE flags on data packets 10 and 11 in test case 6 to check if sender reduces congestion window |
+ * by half and also only once per every window. |
+ * |
+ */ |
+class TcpSocketCongestedRouter : public TcpSocketMsgBase |
+{ |
+public: |
+ /** |
+ * \brief Get the type ID. |
+ * \return the object TypeId |
+ */ |
+ static TypeId GetTypeId (void); |
+ |
+ uint32_t m_dataPacketSent; |
+ uint8_t m_testcase; |
+ |
+ TcpSocketCongestedRouter () |
+ : TcpSocketMsgBase () |
+ { |
+ m_dataPacketSent = 0; |
+ } |
+ |
+ /** |
+ * \brief Constructor. |
+ * \param other The object to copy from. |
+ */ |
+ TcpSocketCongestedRouter (const TcpSocketCongestedRouter &other) |
+ : TcpSocketMsgBase (other) |
+ { |
+ } |
+ |
+ void SetTestCase (uint8_t testCase); |
+ |
+protected: |
+ virtual uint32_t SendDataPacket (SequenceNumber32 seq, uint32_t maxSize, bool withAck); |
+ virtual void ReTxTimeout (); |
+ Ptr<TcpSocketBase> Fork (void); |
+}; |
+ |
+NS_OBJECT_ENSURE_REGISTERED (TcpSocketCongestedRouter); |
+ |
+TypeId |
+TcpSocketCongestedRouter::GetTypeId (void) |
+{ |
+ static TypeId tid = TypeId ("ns3::TcpSocketCongestedRouter") |
+ .SetParent<TcpSocketMsgBase> () |
+ .SetGroupName ("Internet") |
+ .AddConstructor<TcpSocketCongestedRouter> () |
+ ; |
+ return tid; |
+} |
+ |
+void |
+TcpSocketCongestedRouter::ReTxTimeout () |
+{ |
+ TcpSocketBase::ReTxTimeout (); |
+} |
+ |
+void |
+TcpSocketCongestedRouter::SetTestCase (uint8_t testCase) |
+{ |
+ m_testcase = testCase; |
+} |
+ |
+uint32_t |
+TcpSocketCongestedRouter::SendDataPacket (SequenceNumber32 seq, uint32_t maxSize, bool withAck) |
+{ |
+ NS_LOG_FUNCTION (this << seq << maxSize << withAck); |
+ m_dataPacketSent++; |
+ |
+ bool isRetransmission = false; |
+ if (seq != m_tcb->m_highTxMark) |
+ { |
+ isRetransmission = true; |
+ } |
+ |
+ Ptr<Packet> p = m_txBuffer->CopyFromSequence (maxSize, seq); |
+ uint32_t sz = p->GetSize (); // Size of packet |
+ uint8_t flags = withAck ? TcpHeader::ACK : 0; |
+ uint32_t remainingData = m_txBuffer->SizeFromSequence (seq + SequenceNumber32 (sz)); |
+ |
+ if (withAck) |
+ { |
+ m_delAckEvent.Cancel (); |
+ m_delAckCount = 0; |
+ } |
+ |
+ // Sender should reduce the Congestion Window as a response to receiver's ECN Echo notification only once per window |
+ if (m_tcb->m_ecnState == TcpSocketState::ECN_ECE_RCVD && m_ecnEchoSeq.Get () > m_ecnCWRSeq.Get () && !isRetransmission ) |
+ { |
+ NS_LOG_INFO ("Backoff mechanism by reducing CWND by half because we've received ECN Echo"); |
+ m_tcb->m_ssThresh = m_congestionControl->GetSsThresh (m_tcb, BytesInFlight ()); |
+ //m_tcb->m_cWnd = std::max ((uint32_t)m_tcb->m_cWnd / 2, m_tcb->m_segmentSize); |
+ m_congestionControl->ReduceCwnd (m_tcb); |
+ flags |= TcpHeader::CWR; |
+ m_ecnCWRSeq = seq; |
+ m_tcb->m_ecnState = TcpSocketState::ECN_CWR_SENT; |
+ NS_LOG_DEBUG (TcpSocketState::EcnStateName[m_tcb->m_ecnState] << " -> ECN_CWR_SENT"); |
+ NS_LOG_INFO ("CWR flags set"); |
+ NS_LOG_DEBUG (TcpSocketState::TcpCongStateName[m_tcb->m_congState] << " -> CA_CWR"); |
+ if (m_tcb->m_congState == TcpSocketState::CA_OPEN) |
+ { |
+ m_congestionControl->CongestionStateSet (m_tcb, TcpSocketState::CA_CWR); |
+ m_tcb->m_congState = TcpSocketState::CA_CWR; |
+ } |
+ } |
+ /* |
+ * Add tags for each socket option. |
+ * Note that currently the socket adds both IPv4 tag and IPv6 tag |
+ * if both options are set. Once the packet got to layer three, only |
+ * the corresponding tags will be read. |
+ */ |
+ if (GetIpTos ()) |
+ { |
+ SocketIpTosTag ipTosTag; |
+ |
+ NS_LOG_LOGIC (" ECT bits should not be set on retransmitted packets "); |
+ if ( m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 2) && !isRetransmission ) |
+ { |
+ ipTosTag.SetTos (GetIpTos () | 0x3); |
+ } |
+ else if ( m_testcase == 6 && ( m_dataPacketSent == 10 || m_dataPacketSent == 11 ) && !isRetransmission ) |
+ { |
+ ipTosTag.SetTos (GetIpTos () | 0x3); |
+ } |
+ else |
+ { |
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && (GetIpTos () & 0x3) == 0 && !isRetransmission) |
+ { |
+ ipTosTag.SetTos (GetIpTos () | 0x2); |
+ } |
+ else |
+ { |
+ ipTosTag.SetTos (GetIpTos ()); |
+ } |
+ } |
+ p->AddPacketTag (ipTosTag); |
+ } |
+ else |
+ { |
+ SocketIpTosTag ipTosTag; |
+ if ( m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 2) && !isRetransmission) |
+ { |
+ ipTosTag.SetTos (0x3); |
+ } |
+ else if ( m_testcase == 6 && ( m_dataPacketSent == 10 || m_dataPacketSent == 11 ) && !isRetransmission ) |
+ { |
+ ipTosTag.SetTos (0x3); |
+ } |
+ else |
+ { |
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !isRetransmission) |
+ { |
+ ipTosTag.SetTos (0x2); |
+ } |
+ } |
+ p->AddPacketTag (ipTosTag); |
+ } |
+ |
+ if (IsManualIpv6Tclass ()) |
+ { |
+ SocketIpv6TclassTag ipTclassTag; |
+ if ( m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 2) && !isRetransmission ) |
+ { |
+ ipTclassTag.SetTclass (GetIpv6Tclass () | 0x3); |
+ } |
+ else if ( m_testcase == 6 && ( m_dataPacketSent == 10 || m_dataPacketSent == 11 ) && !isRetransmission) |
+ { |
+ ipTclassTag.SetTclass (GetIpv6Tclass () | 0x3); |
+ } |
+ else |
+ { |
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && (GetIpv6Tclass () & 0x3) == 0 && !isRetransmission) |
+ { |
+ ipTclassTag.SetTclass (GetIpv6Tclass () | 0x2); |
+ } |
+ else |
+ { |
+ ipTclassTag.SetTclass (GetIpv6Tclass ()); |
+ } |
+ } |
+ p->AddPacketTag (ipTclassTag); |
+ } |
+ else |
+ { |
+ SocketIpv6TclassTag ipTclassTag; |
+ if ( m_testcase == 5 && (m_dataPacketSent == 1 || m_dataPacketSent == 2) && !isRetransmission) |
+ { |
+ ipTclassTag.SetTclass (0x3); |
+ } |
+ else if ( m_testcase == 6 &&( m_dataPacketSent == 10 || m_dataPacketSent == 11 ) && !isRetransmission) |
+ { |
+ ipTclassTag.SetTclass (0x3); |
+ } |
+ else |
+ { |
+ if (m_tcb->m_ecnState != TcpSocketState::ECN_DISABLED && !isRetransmission) |
+ { |
+ ipTclassTag.SetTclass (0x2); |
+ } |
+ } |
+ p->AddPacketTag (ipTclassTag); |
+ } |
+ |
+ if (IsManualIpTtl ()) |
+ { |
+ SocketIpTtlTag ipTtlTag; |
+ ipTtlTag.SetTtl (GetIpTtl ()); |
+ p->AddPacketTag (ipTtlTag); |
+ } |
+ |
+ if (IsManualIpv6HopLimit ()) |
+ { |
+ SocketIpv6HopLimitTag ipHopLimitTag; |
+ ipHopLimitTag.SetHopLimit (GetIpv6HopLimit ()); |
+ p->AddPacketTag (ipHopLimitTag); |
+ } |
+ |
+ uint8_t priority = GetPriority (); |
+ if (priority) |
+ { |
+ SocketPriorityTag priorityTag; |
+ priorityTag.SetPriority (priority); |
+ p->ReplacePacketTag (priorityTag); |
+ } |
+ |
+ if (m_closeOnEmpty && (remainingData == 0)) |
+ { |
+ flags |= TcpHeader::FIN; |
+ if (m_state == ESTABLISHED) |
+ { // On active close: I am the first one to send FIN |
+ NS_LOG_DEBUG ("ESTABLISHED -> FIN_WAIT_1"); |
+ m_state = FIN_WAIT_1; |
+ } |
+ else if (m_state == CLOSE_WAIT) |
+ { // On passive close: Peer sent me FIN already |
+ NS_LOG_DEBUG ("CLOSE_WAIT -> LAST_ACK"); |
+ m_state = LAST_ACK; |
+ } |
+ } |
+ TcpHeader header; |
+ header.SetFlags (flags); |
+ header.SetSequenceNumber (seq); |
+ header.SetAckNumber (m_rxBuffer->NextRxSequence ()); |
+ if (m_endPoint) |
+ { |
+ header.SetSourcePort (m_endPoint->GetLocalPort ()); |
+ header.SetDestinationPort (m_endPoint->GetPeerPort ()); |
+ } |
+ else |
+ { |
+ header.SetSourcePort (m_endPoint6->GetLocalPort ()); |
+ header.SetDestinationPort (m_endPoint6->GetPeerPort ()); |
+ } |
+ header.SetWindowSize (AdvertisedWindowSize ()); |
+ AddOptions (header); |
+ |
+ if (m_retxEvent.IsExpired ()) |
+ { |
+ // Schedules retransmit timeout. m_rto should be already doubled. |
+ |
+ NS_LOG_LOGIC (this << " SendDataPacket Schedule ReTxTimeout at time " << |
+ Simulator::Now ().GetSeconds () << " to expire at time " << |
+ (Simulator::Now () + m_rto.Get ()).GetSeconds () ); |
+ m_retxEvent = Simulator::Schedule (m_rto, &TcpSocketCongestedRouter::ReTxTimeout, this); |
+ } |
+ |
+ m_txTrace (p, header, this); |
+ |
+ if (m_endPoint) |
+ { |
+ m_tcp->SendPacket (p, header, m_endPoint->GetLocalAddress (), |
+ m_endPoint->GetPeerAddress (), m_boundnetdevice); |
+ NS_LOG_DEBUG ("Send segment of size " << sz << " with remaining data " << |
+ remainingData << " via TcpL4Protocol to " << m_endPoint->GetPeerAddress () << |
+ ". Header " << header); |
+ } |
+ else |
+ { |
+ m_tcp->SendPacket (p, header, m_endPoint6->GetLocalAddress (), |
+ m_endPoint6->GetPeerAddress (), m_boundnetdevice); |
+ NS_LOG_DEBUG ("Send segment of size " << sz << " with remaining data " << |
+ remainingData << " via TcpL4Protocol to " << m_endPoint6->GetPeerAddress () << |
+ ". Header " << header); |
+ } |
+ |
+ UpdateRttHistory (seq, sz, isRetransmission); |
+ |
+ // Notify the application of the data being sent unless this is a retransmit |
+ if (seq + sz > m_tcb->m_highTxMark) |
+ { |
+ Simulator::ScheduleNow (&TcpSocketCongestedRouter::NotifyDataSent, this, |
+ (seq + sz - m_tcb->m_highTxMark.Get ())); |
+ } |
+ // Update highTxMark |
+ m_tcb->m_highTxMark = std::max (seq + sz, m_tcb->m_highTxMark.Get ()); |
+ return sz; |
+} |
+ |
+Ptr<TcpSocketBase> |
+TcpSocketCongestedRouter::Fork (void) |
+{ |
+ return CopyObject<TcpSocketCongestedRouter> (this); |
+} |
+ |
+ |
+TcpECNTest::TcpECNTest (uint32_t testcase, const std::string &desc) |
+ : TcpGeneralTest (desc), |
+ m_cwndChangeCount (0), |
+ m_senderSent (0), |
+ m_receiverSent (0), |
+ m_senderReceived (0), |
+ m_receiverReceived (0), |
+ m_testcase (testcase) |
+{ |
+} |
+ |
+void |
+TcpECNTest::ConfigureProperties () |
+{ |
+ TcpGeneralTest::ConfigureProperties (); |
+ if (m_testcase == 2 || m_testcase == 4 || m_testcase == 5 || m_testcase == 6) |
+ { |
+ SetEcn (SENDER); |
+ } |
+ if (m_testcase == 3 || m_testcase == 4 ||m_testcase == 5 || m_testcase == 6) |
+ { |
+ SetEcn (RECEIVER); |
+ } |
+} |
+ |
+void |
+TcpECNTest::CWndTrace (uint32_t oldValue, uint32_t newValue) |
+{ |
+ if (m_testcase == 6) |
+ { |
+ uint32_t increase = newValue - oldValue; |
+ if ( increase < 0) |
+ { |
+ m_cwndChangeCount++; |
+ NS_TEST_ASSERT_MSG_EQ (m_cwndChangeCount, 1, "Congestion window should be reduced once per every window"); |
+ NS_TEST_ASSERT_MSG_EQ (newValue, oldValue / 2, "Congestion window should be reduced by half"); |
+ } |
+ } |
+} |
+ |
+void |
+TcpECNTest::Rx (const Ptr<const Packet> p, const TcpHeader &h, SocketWho who) |
+{ |
+ if (who == RECEIVER) |
+ { |
+ if (m_receiverReceived == 0) |
+ { |
+ NS_TEST_ASSERT_MSG_NE (((h.GetFlags ()) & TcpHeader::SYN), 0, "SYN should be received as first message at the receiver"); |
+ if (m_testcase == 2 || m_testcase == 4 || m_testcase == 5 ||m_testcase == 6) |
+ { |
+ NS_TEST_ASSERT_MSG_NE (((h.GetFlags ()) & TcpHeader::ECE) && ((h.GetFlags ()) & TcpHeader::CWR), 0, "The flags ECE + CWR should be set in the TCP header of first message receieved at receiver when sender is ECN Capable"); |
+ } |
+ else |
+ { |
+ NS_TEST_ASSERT_MSG_EQ (((h.GetFlags ()) & TcpHeader::ECE) && ((h.GetFlags ()) & TcpHeader::CWR), 0, "The flags ECE + CWR should not be set in the TCP header of first message receieved at receiver when sender is not ECN Capable"); |
+ } |
+ } |
+ else if (m_receiverReceived == 1) |
+ { |
+ NS_TEST_ASSERT_MSG_NE (((h.GetFlags ()) & TcpHeader::ACK), 0, "ACK should be received as second message at receiver"); |
+ } |
+ else if (m_receiverReceived == 3 && m_testcase == 5) |
+ { |
+ NS_TEST_ASSERT_MSG_NE (((h.GetFlags ()) & TcpHeader::CWR), 0, "Sender should send CWR on receipt of ECE"); |
+ } |
+ m_receiverReceived++; |
+ } |
+ else if (who == SENDER) |
+ { |
+ if (m_senderReceived == 0) |
+ { |
+ NS_TEST_ASSERT_MSG_NE (((h.GetFlags ()) & TcpHeader::SYN) && ((h.GetFlags ()) & TcpHeader::ACK), 0, "SYN+ACK received as first message at sender"); |
+ if (m_testcase == 4 || m_testcase == 5 || m_testcase == 6) |
+ { |
+ NS_TEST_ASSERT_MSG_NE (((h.GetFlags ()) & TcpHeader::ECE), 0, "The flag ECE should be set in the TCP header of first message receieved at sender when both receiver and sender are ECN Capable"); |
+ } |
+ else |
+ { |
+ NS_TEST_ASSERT_MSG_EQ (((h.GetFlags ()) & TcpHeader::ECE), 0, "The flag ECE should not be set in the TCP header of first message receieved at sender when either receiver or sender are not ECN Capable"); |
+ } |
+ } |
+ if (m_senderReceived == 3 && m_testcase == 5) |
+ { |
+ NS_TEST_ASSERT_MSG_NE (((h.GetFlags ()) & TcpHeader::ECE), 0, "The flag ECE should be set in TCP header of the packet sent by the receiver when it receives a packet with CE bit set in IP header"); |
+ } |
+ if (m_senderReceived == 4 && m_testcase == 5) |
+ { |
+ NS_TEST_ASSERT_MSG_NE (((h.GetFlags ()) & TcpHeader::ECE), 0, "The flag ECE should be set in TCP header of the packet sent by the receiver even after sender sends CWR flags to receiver if it receives a packet with CE bit set in IP header"); |
+ } |
+ if ( m_testcase == 5 && m_receiverReceived > 12) |
+ { |
+ NS_TEST_ASSERT_MSG_EQ (((h.GetFlags ()) & TcpHeader::ECE), 0, "The flag ECE should not be set in TCP header of the packet sent by the receiver after sender sends CWR flags to receiver and receiver receives a packet without CE bit set in IP header"); |
+ } |
+ m_senderReceived++; |
+ } |
+} |
+ |
+void |
+TcpECNTest::Tx (const Ptr<const Packet> p, const TcpHeader &h, SocketWho who) |
+{ |
+ if (who == SENDER) |
+ { |
+ m_senderSent++; |
+ if (m_senderSent == 3) |
+ { |
+ SocketIpTosTag ipTosTag; |
+ p->PeekPacketTag (ipTosTag); |
+ if (m_testcase == 4 || m_testcase == 6) |
+ { |
+ NS_TEST_ASSERT_MSG_EQ ((ipTosTag.GetTos ()), 0x2, "IP TOS should have ECT set if ECN negotiation between endpoints is successful"); |
+ } |
+ else if (m_testcase == 5) |
+ { |
+ if (m_senderSent == 3 || m_senderSent == 4) |
+ { |
+ NS_TEST_ASSERT_MSG_EQ ((ipTosTag.GetTos ()), 0x3, "IP TOS should have CE bit set for 3rd and 4th packet sent in test case 5"); |
+ } |
+ else |
+ { |
+ NS_TEST_ASSERT_MSG_EQ ((ipTosTag.GetTos ()), 0x2, "IP TOS should have ECT set if ECN negotiation between endpoints is successful"); |
+ } |
+ } |
+ else |
+ { |
+ NS_TEST_ASSERT_MSG_NE ((ipTosTag.GetTos ()), 0x2, "IP TOS should not have ECT set if ECN negotiation between endpoints is unsuccessful"); |
+ } |
+ } |
+ } |
+} |
+ |
+Ptr<TcpSocketMsgBase> |
+TcpECNTest::CreateSenderSocket (Ptr<Node> node) |
+{ |
+ if (m_testcase == 5 || m_testcase == 6) |
+ { |
+ Ptr<TcpSocketCongestedRouter> socket = DynamicCast<TcpSocketCongestedRouter> ( |
+ CreateSocket (node, |
+ TcpSocketCongestedRouter::GetTypeId (), |
+ m_congControlTypeId)); |
+ socket->SetTestCase (m_testcase); |
+ return socket; |
+ } |
+ else |
+ { |
+ return TcpGeneralTest::CreateSenderSocket (node); |
+ } |
+} |
+ |
+/** |
+ * \ingroup internet-test |
+ * \ingroup tests |
+ * |
+ * \brief TCP ECN TestSuite |
+ */ |
+static class TcpECNTestSuite : public TestSuite |
+{ |
+public: |
+ TcpECNTestSuite () : TestSuite ("tcp-ecn-test", UNIT) |
+ { |
+ AddTestCase (new TcpECNTest (1, "ECN Negotiation Test : ECN incapable sender and ECN incapable receiver"), |
+ TestCase::QUICK); |
+ AddTestCase (new TcpECNTest (2, "ECN Negotiation Test : ECN capable sender and ECN incapable receiver"), |
+ TestCase::QUICK); |
+ AddTestCase (new TcpECNTest (3, "ECN Negotiation Test : ECN incapable sender and ECN capable receiver"), |
+ TestCase::QUICK); |
+ AddTestCase (new TcpECNTest (4, "ECN Negotiation Test : ECN capable sender and ECN capable receiver"), |
+ TestCase::QUICK); |
+ AddTestCase (new TcpECNTest (5, "ECE and CWR Functionality Test: ECN capable sender and ECN capable receiver"), |
+ TestCase::QUICK); |
+ AddTestCase (new TcpECNTest (6, "Congestion Window Reduction Test :ECN capable sender and ECN capable receiver"), |
+ TestCase::QUICK); |
+ } |
+} g_tcpECNTestSuite; |
+ |
+} // namespace ns3 |