Bug 555 - DCF immediate access fix
authorDaniel Lertpratchya <nikkipui@gmail.com>
Fri, 07 Dec 2012 14:36:01 -0500
changeset 9176 41ab1e874804
parent 9174 bb6bbda68e97
child 9177 44439aa36880
Bug 555 - DCF immediate access fix
RELEASE_NOTES
src/aodv/test/tcp-chain-test-0-0.pcap
src/aodv/test/tcp-chain-test-9-0.pcap
src/wifi/bindings/modulegen__gcc_ILP32.py
src/wifi/bindings/modulegen__gcc_LP64.py
src/wifi/model/dca-txop.cc
src/wifi/model/dca-txop.h
src/wifi/model/edca-txop-n.cc
src/wifi/model/edca-txop-n.h
src/wifi/model/mac-low.cc
src/wifi/model/mac-low.h
src/wifi/test/wifi-test.cc
--- a/RELEASE_NOTES	Fri Dec 07 10:12:40 2012 -0800
+++ b/RELEASE_NOTES	Fri Dec 07 14:36:01 2012 -0500
@@ -42,6 +42,7 @@
  - bug 1532 - unimplemented LTE Scheduler methods
  - bug 1524 - Fragmentation Threshold equals to Packet Size at MAC Layer (Data + IP + UDP) crash the reception
  - bug 1525 - Linker error with mpi on Mac 10.8
+ - bug  555 - DCF immediate access
 
 Known issues
 ------------
Binary file src/aodv/test/tcp-chain-test-0-0.pcap has changed
Binary file src/aodv/test/tcp-chain-test-9-0.pcap has changed
--- a/src/wifi/bindings/modulegen__gcc_ILP32.py	Fri Dec 07 10:12:40 2012 -0800
+++ b/src/wifi/bindings/modulegen__gcc_ILP32.py	Fri Dec 07 14:36:01 2012 -0500
@@ -2553,6 +2553,11 @@
                    'void', 
                    [], 
                    is_pure_virtual=True, is_virtual=True)
+    ## mac-low.h (module 'wifi'): void ns3::MacLowTransmissionListener::EndTxNoAck() [member function]
+    cls.add_method('EndTxNoAck', 
+                   'void', 
+                   [], 
+                   is_pure_virtual=True, is_virtual=True)
     ## mac-low.h (module 'wifi'): void ns3::MacLowTransmissionListener::GotAck(double snr, ns3::WifiMode txMode) [member function]
     cls.add_method('GotAck', 
                    'void', 
@@ -4095,6 +4100,7 @@
 
 def register_Ns3Int64x64_t_methods(root_module, cls):
     cls.add_inplace_numeric_operator('+=', param('ns3::int64x64_t const &', 'right'))
+    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('!=')
     cls.add_binary_numeric_operator('*', root_module['ns3::int64x64_t'], root_module['ns3::int64x64_t'], param('long long unsigned int const', 'right'))
     cls.add_binary_numeric_operator('*', root_module['ns3::int64x64_t'], root_module['ns3::int64x64_t'], param('long unsigned int const', 'right'))
@@ -4151,7 +4157,6 @@
     cls.add_inplace_numeric_operator('-=', param('ns3::int64x64_t const &', 'right'))
     cls.add_inplace_numeric_operator('/=', param('ns3::int64x64_t const &', 'right'))
     cls.add_output_stream_operator()
-    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('==')
     cls.add_binary_comparison_operator('>=')
     ## int64x64-double.h (module 'core'): ns3::int64x64_t::int64x64_t() [constructor]
@@ -5354,6 +5359,7 @@
 
 def register_Ns3Time_methods(root_module, cls):
     cls.add_inplace_numeric_operator('+=', param('ns3::Time const &', 'right'))
+    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('!=')
     cls.add_binary_numeric_operator('+', root_module['ns3::Time'], root_module['ns3::Time'], param('ns3::Time const &', 'right'))
     cls.add_binary_numeric_operator('-', root_module['ns3::Time'], root_module['ns3::Time'], param('ns3::Time const &', 'right'))
@@ -5361,7 +5367,6 @@
     cls.add_binary_comparison_operator('>')
     cls.add_inplace_numeric_operator('-=', param('ns3::Time const &', 'right'))
     cls.add_output_stream_operator()
-    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('==')
     cls.add_binary_comparison_operator('>=')
     ## nstime.h (module 'core'): ns3::Time::Time() [constructor]
@@ -8918,6 +8923,10 @@
     cls.add_method('Cancel', 
                    'void', 
                    [])
+    ## edca-txop-n.h (module 'wifi'): void ns3::EdcaTxopN::EndTxNoAck() [member function]
+    cls.add_method('EndTxNoAck', 
+                   'void', 
+                   [])
     ## edca-txop-n.h (module 'wifi'): void ns3::EdcaTxopN::RestartAccessIfNeeded() [member function]
     cls.add_method('RestartAccessIfNeeded', 
                    'void', 
--- a/src/wifi/bindings/modulegen__gcc_LP64.py	Fri Dec 07 10:12:40 2012 -0800
+++ b/src/wifi/bindings/modulegen__gcc_LP64.py	Fri Dec 07 14:36:01 2012 -0500
@@ -2553,6 +2553,11 @@
                    'void', 
                    [], 
                    is_pure_virtual=True, is_virtual=True)
+    ## mac-low.h (module 'wifi'): void ns3::MacLowTransmissionListener::EndTxNoAck() [member function]
+    cls.add_method('EndTxNoAck', 
+                   'void', 
+                   [], 
+                   is_pure_virtual=True, is_virtual=True)
     ## mac-low.h (module 'wifi'): void ns3::MacLowTransmissionListener::GotAck(double snr, ns3::WifiMode txMode) [member function]
     cls.add_method('GotAck', 
                    'void', 
@@ -4095,6 +4100,7 @@
 
 def register_Ns3Int64x64_t_methods(root_module, cls):
     cls.add_inplace_numeric_operator('+=', param('ns3::int64x64_t const &', 'right'))
+    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('!=')
     cls.add_binary_numeric_operator('*', root_module['ns3::int64x64_t'], root_module['ns3::int64x64_t'], param('long long unsigned int const', 'right'))
     cls.add_binary_numeric_operator('*', root_module['ns3::int64x64_t'], root_module['ns3::int64x64_t'], param('long unsigned int const', 'right'))
@@ -4151,7 +4157,6 @@
     cls.add_inplace_numeric_operator('-=', param('ns3::int64x64_t const &', 'right'))
     cls.add_inplace_numeric_operator('/=', param('ns3::int64x64_t const &', 'right'))
     cls.add_output_stream_operator()
-    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('==')
     cls.add_binary_comparison_operator('>=')
     ## int64x64-double.h (module 'core'): ns3::int64x64_t::int64x64_t() [constructor]
@@ -5354,6 +5359,7 @@
 
 def register_Ns3Time_methods(root_module, cls):
     cls.add_inplace_numeric_operator('+=', param('ns3::Time const &', 'right'))
+    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('!=')
     cls.add_binary_numeric_operator('+', root_module['ns3::Time'], root_module['ns3::Time'], param('ns3::Time const &', 'right'))
     cls.add_binary_numeric_operator('-', root_module['ns3::Time'], root_module['ns3::Time'], param('ns3::Time const &', 'right'))
@@ -5361,7 +5367,6 @@
     cls.add_binary_comparison_operator('>')
     cls.add_inplace_numeric_operator('-=', param('ns3::Time const &', 'right'))
     cls.add_output_stream_operator()
-    cls.add_binary_comparison_operator('<=')
     cls.add_binary_comparison_operator('==')
     cls.add_binary_comparison_operator('>=')
     ## nstime.h (module 'core'): ns3::Time::Time() [constructor]
@@ -8918,6 +8923,10 @@
     cls.add_method('Cancel', 
                    'void', 
                    [])
+    ## edca-txop-n.h (module 'wifi'): void ns3::EdcaTxopN::EndTxNoAck() [member function]
+    cls.add_method('EndTxNoAck', 
+                   'void', 
+                   [])
     ## edca-txop-n.h (module 'wifi'): void ns3::EdcaTxopN::RestartAccessIfNeeded() [member function]
     cls.add_method('RestartAccessIfNeeded', 
                    'void', 
--- a/src/wifi/model/dca-txop.cc	Fri Dec 07 10:12:40 2012 -0800
+++ b/src/wifi/model/dca-txop.cc	Fri Dec 07 14:36:01 2012 -0500
@@ -103,6 +103,10 @@
   {
     m_txop->Cancel ();
   }
+  virtual void EndTxNoAck (void)
+  {
+    m_txop->EndTxNoAck ();
+  }
 
 private:
   DcaTxop *m_txop;
@@ -407,10 +411,6 @@
                                  &m_currentHdr,
                                  params,
                                  m_transmissionListener);
-      m_currentPacket = 0;
-      m_dcf->ResetCw ();
-      m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
-      StartAccessIfNeeded ();
       NS_LOG_DEBUG ("tx broadcast");
     }
   else
@@ -621,4 +621,15 @@
    */
 }
 
+void
+DcaTxop::EndTxNoAck (void)
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_DEBUG ("a transmission that did not require an ACK just finished");
+  m_currentPacket = 0;
+  m_dcf->ResetCw ();
+  m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+  StartAccessIfNeeded ();
+}
+
 } // namespace ns3
--- a/src/wifi/model/dca-txop.h	Fri Dec 07 10:12:40 2012 -0800
+++ b/src/wifi/model/dca-txop.h	Fri Dec 07 14:36:01 2012 -0500
@@ -147,6 +147,7 @@
   void MissedAck (void);
   void StartNext (void);
   void Cancel (void);
+  void EndTxNoAck (void);
 
   void RestartAccessIfNeeded (void);
   void StartAccessIfNeeded (void);
--- a/src/wifi/model/edca-txop-n.cc	Fri Dec 07 10:12:40 2012 -0800
+++ b/src/wifi/model/edca-txop-n.cc	Fri Dec 07 14:36:01 2012 -0500
@@ -111,6 +111,10 @@
   {
     m_txop->Cancel ();
   }
+  virtual void EndTxNoAck (void)
+  {
+    m_txop->EndTxNoAck ();
+  }
 
 private:
   EdcaTxopN *m_txop;
@@ -384,10 +388,6 @@
                                 params,
                                 m_transmissionListener);
 
-      m_currentPacket = 0;
-      m_dcf->ResetCw ();
-      m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
-      StartAccessIfNeeded ();
       NS_LOG_DEBUG ("tx broadcast");
     }
   else if (m_currentHdr.GetType () == WIFI_MAC_CTL_BACKREQ)
@@ -730,6 +730,17 @@
   NS_LOG_DEBUG ("transmission cancelled");
 }
 
+void
+EdcaTxopN::EndTxNoAck (void)
+{
+  NS_LOG_FUNCTION (this);
+  NS_LOG_DEBUG ("a transmission that did not require an ACK just finished");
+  m_currentPacket = 0;
+  m_dcf->ResetCw ();
+  m_dcf->StartBackoffNow (m_rng->GetNext (0, m_dcf->GetCw ()));
+  StartAccessIfNeeded ();
+}
+
 bool
 EdcaTxopN::NeedFragmentation (void) const
 {
--- a/src/wifi/model/edca-txop-n.h	Fri Dec 07 10:12:40 2012 -0800
+++ b/src/wifi/model/edca-txop-n.h	Fri Dec 07 14:36:01 2012 -0500
@@ -126,6 +126,7 @@
   void MissedAck (void);
   void StartNext (void);
   void Cancel (void);
+  void EndTxNoAck (void);
 
   void RestartAccessIfNeeded (void);
   void StartAccessIfNeeded (void);
--- a/src/wifi/model/mac-low.cc	Fri Dec 07 10:12:40 2012 -0800
+++ b/src/wifi/model/mac-low.cc	Fri Dec 07 14:36:01 2012 -0500
@@ -360,6 +360,7 @@
     m_sendAckEvent (),
     m_sendDataEvent (),
     m_waitSifsEvent (),
+    m_endTxNoAckEvent (),
     m_currentPacket (0),
     m_listener (0)
 {
@@ -396,6 +397,7 @@
   m_sendAckEvent.Cancel ();
   m_sendDataEvent.Cancel ();
   m_waitSifsEvent.Cancel ();
+  m_endTxNoAckEvent.Cancel ();
   m_phy = 0;
   m_stationManager = 0;
   delete m_phyMacLowListener;
@@ -457,6 +459,11 @@
       m_waitSifsEvent.Cancel ();
       oneRunning = true;
     }
+  if (m_endTxNoAckEvent.IsRunning ()) 
+    {
+      m_endTxNoAckEvent.Cancel ();
+      oneRunning = true;
+    }
   if (oneRunning && m_listener != 0)
     {
       m_listener->Cancel ();
@@ -1352,7 +1359,7 @@
   else
     {
       // since we do not expect any timer to be triggered.
-      m_listener = 0;
+      Simulator::Schedule(txDuration, &MacLow::EndTxNoAck, this);
     }
 }
 
@@ -1490,6 +1497,14 @@
   m_listener->StartNext ();
 }
 
+void 
+MacLow::EndTxNoAck (void)
+{
+  MacLowTransmissionListener *listener = m_listener;
+  m_listener = 0;
+  listener->EndTxNoAck ();
+}
+
 void
 MacLow::FastAckFailedTimeout (void)
 {
--- a/src/wifi/model/mac-low.h	Fri Dec 07 10:12:40 2012 -0800
+++ b/src/wifi/model/mac-low.h	Fri Dec 07 14:36:01 2012 -0500
@@ -123,7 +123,15 @@
    * you can assume that the packet has not been passed
    * down the stack to the PHY.
    */
-  virtual void Cancel (void) = 0;
+  virtual void Cancel (void) = 0;	
+
+  /** 
+   * Invoked upon the end of the transmission of a frame that does not
+   * require an ACK (e.g., broadcast and multicast frames).
+   * 
+   */
+  virtual void EndTxNoAck (void) = 0;
+
 };
 
 
@@ -541,6 +549,7 @@
   void SendAckAfterData (Mac48Address source, Time duration, WifiMode txMode, double rtsSnr);
   void SendDataAfterCts (Mac48Address source, Time duration, WifiMode txMode);
   void WaitSifsAfterEndTx (void);
+  void EndTxNoAck (void);
 
   void SendRtsForPacket (void);
   void SendDataPacket (void);
@@ -614,6 +623,7 @@
   EventId m_sendAckEvent;
   EventId m_sendDataEvent;
   EventId m_waitSifsEvent;
+  EventId m_endTxNoAckEvent;
   EventId m_navCounterResetCtsMissed;
 
   Ptr<Packet> m_currentPacket;
--- a/src/wifi/test/wifi-test.cc	Fri Dec 07 10:12:40 2012 -0800
+++ b/src/wifi/test/wifi-test.cc	Fri Dec 07 14:36:01 2012 -0500
@@ -37,6 +37,7 @@
 #include "ns3/dca-txop.h"
 #include "ns3/mac-rx-middle.h"
 #include "ns3/pointer.h"
+#include "ns3/rng-seed-manager.h"
 
 namespace ns3 {
 
@@ -285,6 +286,148 @@
 }
 
 //-----------------------------------------------------------------------------
+/**
+ * Make sure that when multiple broadcast packets are queued on the same
+ * device in a short succession no virtual collision occurs 
+ *
+ * The observed behavior is that the first frame will be sent immediately,
+ * and the frames are spaced by (backoff + SIFS + AIFS) time intervals
+ * (where backoff is a random number of slot sizes up to maximum CW)
+ * 
+ * The following test case should _not_ generate virtual collision for the second frame.
+ * The seed and run numbers were pick such that the second frame gets backoff = 0.
+ *
+ *                      frame 1, frame 2
+ *                      arrive                SIFS + AIFS
+ *                      V                    <-----------> 
+ * time  |--------------|-------------------|-------------|----------->
+ *       0              1s                  1.001408s     1.001442s
+ *                      ^                   ^             ^
+ *                      start TX            finish TX     start TX
+ *                      frame 1             frame 1       frame 2
+ *                      ^
+ *                      frame 2
+ *                      backoff = 0
+ *
+ * The buggy behavior was that frame 2 experiences a virtual collision and re-selects the
+ * backoff again. As a result, the _actual_ backoff experience by frame 2 is less likely to be 0
+ * since that would require two successions of 0 backoff (one that generates the virtual collision and
+ * one after the virtual collision).
+ */
+
+class Bug555TestCase : public TestCase
+{
+public:
+
+  Bug555TestCase ();
+
+  virtual void DoRun (void);
+
+private:
+
+  void SendOnePacket (Ptr<WifiNetDevice> dev);
+
+  ObjectFactory m_manager;
+  ObjectFactory m_mac; 
+  ObjectFactory m_propDelay;
+
+  Time m_firstTransmissionTime;
+  Time m_secondTransmissionTime;
+  unsigned int m_numSentPackets;
+
+  void NotifyPhyTxBegin (Ptr<const Packet> p);
+};
+
+Bug555TestCase::Bug555TestCase ()
+  : TestCase ("Test case for Bug 555")
+{
+}
+
+void 
+Bug555TestCase::NotifyPhyTxBegin (Ptr<const Packet> p)
+{
+  if (m_numSentPackets == 0)
+    {
+      NS_ASSERT_MSG (Simulator::Now() == Time (Seconds (1)), "Packet 0 not transmitted at 1 second");
+      m_numSentPackets++;
+      m_firstTransmissionTime = Simulator::Now ();
+    }
+  else if (m_numSentPackets == 1)
+    {
+      m_secondTransmissionTime = Simulator::Now ();
+    }
+}
+
+void
+Bug555TestCase::SendOnePacket (Ptr<WifiNetDevice> dev)
+{
+  Ptr<Packet> p = Create<Packet> (1000);
+  dev->Send (p, dev->GetBroadcast (), 1);
+}
+
+void
+Bug555TestCase::DoRun (void)
+{
+  m_mac.SetTypeId ("ns3::AdhocWifiMac");
+  m_propDelay.SetTypeId ("ns3::ConstantSpeedPropagationDelayModel");
+  m_manager.SetTypeId ("ns3::ConstantRateWifiManager");
+
+  //The simulation with the following seed and run numbers expe
+  RngSeedManager::SetSeed (1);
+  RngSeedManager::SetRun (17);
+
+  Ptr<YansWifiChannel> channel = CreateObject<YansWifiChannel> ();
+  Ptr<PropagationDelayModel> propDelay = m_propDelay.Create<PropagationDelayModel> ();
+  Ptr<PropagationLossModel> propLoss = CreateObject<RandomPropagationLossModel> ();
+  channel->SetPropagationDelayModel (propDelay);
+  channel->SetPropagationLossModel (propLoss);
+
+  Ptr<Node> txNode = CreateObject<Node> ();
+  Ptr<WifiNetDevice> txDev = CreateObject<WifiNetDevice> ();
+  Ptr<WifiMac> txMac = m_mac.Create<WifiMac> ();
+  txMac->ConfigureStandard (WIFI_PHY_STANDARD_80211a);
+
+  Ptr<ConstantPositionMobilityModel> txMobility = CreateObject<ConstantPositionMobilityModel> ();
+  Ptr<YansWifiPhy> txPhy = CreateObject<YansWifiPhy> ();
+  Ptr<ErrorRateModel> txError = CreateObject<YansErrorRateModel> ();
+  txPhy->SetErrorRateModel (txError);
+  txPhy->SetChannel (channel);
+  txPhy->SetDevice (txDev);
+  txPhy->SetMobility (txNode);
+  txPhy->ConfigureStandard (WIFI_PHY_STANDARD_80211a);
+
+  txPhy->TraceConnectWithoutContext ("PhyTxBegin", MakeCallback (&Bug555TestCase::NotifyPhyTxBegin, this));
+
+  txMobility->SetPosition (Vector (0.0, 0.0, 0.0));
+  txNode->AggregateObject (txMobility);
+  txMac->SetAddress (Mac48Address::Allocate ());
+  txDev->SetMac (txMac);
+  txDev->SetPhy (txPhy);
+  txDev->SetRemoteStationManager (m_manager.Create<WifiRemoteStationManager> ());
+  txNode->AddDevice (txDev);
+
+  m_firstTransmissionTime = Seconds (0.0);
+  m_secondTransmissionTime = Seconds (0.0);
+  m_numSentPackets = 0;
+  
+  Simulator::Schedule (Seconds (1.0), &Bug555TestCase::SendOnePacket, this, txDev);
+  Simulator::Schedule (Seconds (1.0), &Bug555TestCase::SendOnePacket, this, txDev);
+
+  Simulator::Stop (Seconds (2.0));
+  Simulator::Run ();
+  Simulator::Destroy ();
+
+  // First packet has 1408 us of transmit time.   Slot time is 9 us.  
+  // Backoff is 0 slots.  SIFS is 16 us.  AIFS is 2 slots = 18 us.
+  // Should send next packet at 1408 us + (0 * 9 us) + 16 us + 18 us
+  // 1442 us after the first one.
+  uint32_t expectedWait1 = 1408 + (0 * 9) + 16 + 18;
+  Time expectedSecondTransmissionTime = MicroSeconds (expectedWait1) + Seconds (1.0);
+
+  NS_TEST_ASSERT_MSG_EQ (m_secondTransmissionTime, expectedSecondTransmissionTime, "The second transmission time not correct!");
+}
+
+//-----------------------------------------------------------------------------
 
 class WifiTestSuite : public TestSuite
 {
@@ -298,6 +441,7 @@
   AddTestCase (new WifiTest);
   AddTestCase (new QosUtilsIsOldPacketTest);
   AddTestCase (new InterferenceHelperSequenceTest); // Bug 991
+  AddTestCase (new Bug555TestCase); // Bug 555
 }
 
 static WifiTestSuite g_wifiTestSuite;