diff --git a/src/test/ns3wifi/wifi-ac-mapping-test-suite.cc b/src/test/ns3wifi/wifi-ac-mapping-test-suite.cc new file mode 100644 index 000000000..124d8a52d --- /dev/null +++ b/src/test/ns3wifi/wifi-ac-mapping-test-suite.cc @@ -0,0 +1,210 @@ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2016 Universita' degli Studi di Napoli Federico II + * + * 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: Stefano Avallone + */ + +#include "ns3/test.h" +#include "ns3/simulator.h" +#include "ns3/log.h" +#include "ns3/uinteger.h" +#include "ns3/boolean.h" +#include "ns3/string.h" +#include "ns3/double.h" +#include "ns3/pointer.h" +#include "ns3/ssid.h" +#include "ns3/data-rate.h" +#include "ns3/inet-socket-address.h" +#include "ns3/packet-sink.h" +#include "ns3/wifi-helper.h" +#include "ns3/wifi-net-device.h" +#include "ns3/wifi-mac.h" +#include "ns3/wifi-mac-queue.h" +#include "ns3/edca-txop-n.h" +#include "ns3/yans-wifi-helper.h" +#include "ns3/mobility-helper.h" +#include "ns3/internet-stack-helper.h" +#include "ns3/ipv4-address-helper.h" +#include "ns3/packet-sink-helper.h" +#include "ns3/on-off-helper.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("WifiAcMappingTest"); + +class WifiAcMappingTest : public TestCase +{ +public: + WifiAcMappingTest (uint8_t tos, uint8_t expectedQueue); + virtual void DoRun (void); + +private: + uint8_t m_tos; + uint8_t m_expectedQueue; +}; + +WifiAcMappingTest::WifiAcMappingTest (uint8_t tos, uint8_t expectedQueue) + : TestCase ("User priority to Access Category mapping test"), + m_tos (tos), + m_expectedQueue (expectedQueue) +{ +} + +void +WifiAcMappingTest::DoRun (void) +{ + WifiHelper wifi; + WifiMacHelper wifiMac; + YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default (); + YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default (); + wifiPhy.SetChannel (wifiChannel.Create ()); + + Ssid ssid = Ssid ("wifi-ac-mapping"); + wifi.SetRemoteStationManager ("ns3::ArfWifiManager"); + + // Setup the AP, which will be the source of traffic for this test + NodeContainer ap; + ap.Create (1); + wifiMac.SetType ("ns3::ApWifiMac", + "QosSupported", BooleanValue (true), + "Ssid", SsidValue (ssid)); + + NetDeviceContainer apDev = wifi.Install (wifiPhy, wifiMac, ap); + + // Setup one STA, which will be the sink for traffic in this test. + NodeContainer sta; + sta.Create (1); + wifiMac.SetType ("ns3::StaWifiMac", + "QosSupported", BooleanValue (true), + "Ssid", SsidValue (ssid)); + NetDeviceContainer staDev = wifi.Install (wifiPhy, wifiMac, sta); + + // Our devices will have fixed positions + MobilityHelper mobility; + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.SetPositionAllocator ("ns3::GridPositionAllocator", + "MinX", DoubleValue (0.0), + "MinY", DoubleValue (0.0), + "DeltaX", DoubleValue (5.0), + "DeltaY", DoubleValue (10.0), + "GridWidth", UintegerValue (2), + "LayoutType", StringValue ("RowFirst")); + mobility.Install (sta); + mobility.Install (ap); + + // Now we install internet stacks on our devices + InternetStackHelper stack; + stack.Install (ap); + stack.Install (sta); + + Ipv4AddressHelper address; + address.SetBase ("192.168.0.0", "255.255.255.0"); + Ipv4InterfaceContainer staNodeInterface, apNodeInterface; + staNodeInterface = address.Assign (staDev); + apNodeInterface = address.Assign (apDev); + + uint16_t udpPort = 50000; + + PacketSinkHelper packetSink ("ns3::UdpSocketFactory", + InetSocketAddress (Ipv4Address::GetAny (), udpPort)); + ApplicationContainer sinkApp = packetSink.Install (sta.Get (0)); + sinkApp.Start (Seconds (0)); + sinkApp.Stop (Seconds (3.0)); + + // The packet source is an on-off application on the AP device + InetSocketAddress dest (staNodeInterface.GetAddress (0), udpPort); + dest.SetTos (m_tos); + OnOffHelper onoff ("ns3::UdpSocketFactory", dest); + onoff.SetConstantRate (DataRate ("5kbps"), 500); + ApplicationContainer sourceApp = onoff.Install (ap.Get (0)); + sourceApp.Start (Seconds (1.0)); + sourceApp.Stop (Seconds (3.0)); + + // The first packet will be transmitted at time 1+(500*8)/5000 = 1.8s. + // Let this packet be transmitted successfully, so that the AP can resolve + // the IP address of the station and get its MAC address. + // The second packet will be transmitted at time 1.8+(500*8)/5000 = 2.6s. + // Put the AP in sleep mode at time 2.0s, so that the second packet remains + // in a wifi mac queue and we can discover the queue it has been sent to. + Ptr apPhy = DynamicCast (apDev.Get (0))->GetPhy (); + Simulator::ScheduleWithContext (ap.Get (0)->GetId (), Seconds (2.0), + &WifiPhy::SetSleepMode, apPhy); + + Simulator::Stop (Seconds (4.0)); + + Ptr apMac = DynamicCast (apDev.Get (0))->GetMac (); + PointerValue ptr; + Ptr queues[4]; + // Get the four wifi mac queues and set their MaxDelay attribute to a large + // value, so that packets are not removed by the Cleanup method + apMac->GetAttribute ("BE_EdcaTxopN", ptr); + queues[0] = ptr.Get ()->GetEdcaQueue (); + queues[0]->SetAttribute ("MaxDelay", TimeValue (Seconds (10.0))); + + apMac->GetAttribute ("BK_EdcaTxopN", ptr); + queues[1] = ptr.Get ()->GetEdcaQueue (); + queues[1]->SetAttribute ("MaxDelay", TimeValue (Seconds (10.0))); + + apMac->GetAttribute ("VI_EdcaTxopN", ptr); + queues[2] = ptr.Get ()->GetEdcaQueue (); + queues[2]->SetAttribute ("MaxDelay", TimeValue (Seconds (10.0))); + + apMac->GetAttribute ("VO_EdcaTxopN", ptr); + queues[3] = ptr.Get ()->GetEdcaQueue (); + queues[3]->SetAttribute ("MaxDelay", TimeValue (Seconds (10.0))); + + + Simulator::Run (); + + for (uint32_t i = 0; i < 4; i++) + { + if (i == m_expectedQueue) + { + NS_TEST_ASSERT_MSG_EQ (queues[i]->GetSize (), 1, "There is no packet in the expected queue " << i); + } + else + { + NS_TEST_ASSERT_MSG_EQ (queues[i]->GetSize (), 0, "Unexpectedly, there is a packet in queue " << i); + } + } + + uint32_t totalOctetsThrough = + DynamicCast(sinkApp.Get (0))->GetTotalRx (); + + // Check that the first packet has been received + NS_TEST_ASSERT_MSG_EQ (totalOctetsThrough, 500, "A single packet should have been received"); + + Simulator::Destroy (); +} + + +class WifiAcMappingTestSuite : public TestSuite +{ +public: + WifiAcMappingTestSuite (); +}; + +WifiAcMappingTestSuite::WifiAcMappingTestSuite () + : TestSuite ("ns3-wifi-ac-mapping", SYSTEM) +{ + AddTestCase (new WifiAcMappingTest (0xb8, 2), TestCase::QUICK); // EF in AC_VI + AddTestCase (new WifiAcMappingTest (0x28, 1), TestCase::QUICK); // AF11 in AC_BK + AddTestCase (new WifiAcMappingTest (0x70, 0), TestCase::QUICK); // AF32 in AC_BE + AddTestCase (new WifiAcMappingTest (0xc0, 3), TestCase::QUICK); // CS7 in AC_VO +} + +static WifiAcMappingTestSuite wifiAcMappingTestSuite; diff --git a/src/test/wscript b/src/test/wscript index da897d5b3..41d328a31 100644 --- a/src/test/wscript +++ b/src/test/wscript @@ -41,6 +41,7 @@ def build(bld): 'ns3tcp/ns3tcp-socket-writer.cc', 'ns3wifi/wifi-interference-test-suite.cc', 'ns3wifi/wifi-msdu-aggregator-test-suite.cc', + 'ns3wifi/wifi-ac-mapping-test-suite.cc', 'traced/traced-callback-typedef-test-suite.cc', 'traced/traced-value-callback-typedef-test-suite.cc', ] diff --git a/src/wifi/model/adhoc-wifi-mac.cc b/src/wifi/model/adhoc-wifi-mac.cc index 4b596d49c..b70f46a5f 100644 --- a/src/wifi/model/adhoc-wifi-mac.cc +++ b/src/wifi/model/adhoc-wifi-mac.cc @@ -26,7 +26,6 @@ #include "ns3/string.h" #include "ns3/boolean.h" #include "ns3/trace-source-accessor.h" -#include "qos-tag.h" #include "mac-low.h" #include "dcf-manager.h" #include "mac-rx-middle.h" diff --git a/src/wifi/model/ap-wifi-mac.cc b/src/wifi/model/ap-wifi-mac.cc index 3243cbbaa..133a46dc9 100644 --- a/src/wifi/model/ap-wifi-mac.cc +++ b/src/wifi/model/ap-wifi-mac.cc @@ -27,7 +27,6 @@ #include "ns3/string.h" #include "ns3/pointer.h" #include "ns3/boolean.h" -#include "qos-tag.h" #include "wifi-phy.h" #include "dcf-manager.h" #include "mac-rx-middle.h" diff --git a/src/wifi/model/mac-low.cc b/src/wifi/model/mac-low.cc index a3832c776..e510a3639 100644 --- a/src/wifi/model/mac-low.cc +++ b/src/wifi/model/mac-low.cc @@ -26,6 +26,7 @@ #include "ns3/tag.h" #include "ns3/log.h" #include "ns3/node.h" +#include "ns3/socket.h" #include "ns3/double.h" #include "mac-low.h" #include "wifi-phy.h" @@ -741,6 +742,9 @@ MacLow::StartTransmission (Ptr packet, * one of the Edca of the QAP. */ m_currentPacket = packet->Copy (); + // remove the priority tag attached, if any + SocketPriorityTag priorityTag; + m_currentPacket->RemovePacketTag (priorityTag); m_currentHdr = *hdr; CancelAllEvents (); m_listener = listener; diff --git a/src/wifi/model/qos-utils.cc b/src/wifi/model/qos-utils.cc index 1257e098e..5bfad637a 100644 --- a/src/wifi/model/qos-utils.cc +++ b/src/wifi/model/qos-utils.cc @@ -20,7 +20,7 @@ */ #include "qos-utils.h" -#include "qos-tag.h" +#include "ns3/socket.h" namespace ns3 { @@ -61,13 +61,13 @@ QosUtilsMapTidToAc (uint8_t tid) uint8_t QosUtilsGetTidForPacket (Ptr packet) { - QosTag qos; + SocketPriorityTag qos; uint8_t tid = 8; if (packet->PeekPacketTag (qos)) { - if (qos.GetTid () < 8) + if (qos.GetPriority () < 8) { - tid = qos.GetTid (); + tid = qos.GetPriority (); } } return tid; diff --git a/src/wifi/model/sta-wifi-mac.cc b/src/wifi/model/sta-wifi-mac.cc index 3c7ca0306..ff037ac64 100644 --- a/src/wifi/model/sta-wifi-mac.cc +++ b/src/wifi/model/sta-wifi-mac.cc @@ -27,7 +27,6 @@ #include "ns3/pointer.h" #include "ns3/boolean.h" #include "ns3/trace-source-accessor.h" -#include "qos-tag.h" #include "mac-low.h" #include "dcf-manager.h" #include "mac-rx-middle.h" diff --git a/src/wifi/model/wifi-net-device.cc b/src/wifi/model/wifi-net-device.cc index ce0839687..90b615200 100644 --- a/src/wifi/model/wifi-net-device.cc +++ b/src/wifi/model/wifi-net-device.cc @@ -19,12 +19,14 @@ */ #include "wifi-net-device.h" -#include "wifi-mac.h" +#include "regular-wifi-mac.h" #include "wifi-phy.h" #include "wifi-remote-station-manager.h" #include "wifi-channel.h" +#include "qos-utils.h" #include "ns3/llc-snap-header.h" #include "ns3/packet.h" +#include "ns3/socket.h" #include "ns3/uinteger.h" #include "ns3/pointer.h" #include "ns3/node.h" @@ -94,6 +96,7 @@ WifiNetDevice::DoDispose (void) m_mac = 0; m_phy = 0; m_stationManager = 0; + m_queueInterface = 0; NetDevice::DoDispose (); } @@ -127,6 +130,42 @@ WifiNetDevice::CompleteConfig (void) m_configComplete = true; } +void +WifiNetDevice::NotifyNewAggregate (void) +{ + NS_LOG_FUNCTION (this); + if (m_queueInterface == 0) + { + Ptr ndqi = this->GetObject (); + //verify that it's a valid netdevice queue interface and that + //the netdevice queue interface was not set before + if (ndqi != 0) + { + m_queueInterface = ndqi; + if (m_mac == 0) + { + NS_LOG_WARN ("A mac has not been installed yet, using a single tx queue"); + } + else + { + Ptr mac = DynamicCast (m_mac); + if (mac != 0) + { + BooleanValue qosSupported; + mac->GetAttributeFailSafe ("QosSupported", qosSupported); + if (qosSupported.Get ()) + { + m_queueInterface->SetTxQueuesN (4); + // register the select queue callback + m_queueInterface->SetSelectQueueCallback (MakeCallback (&WifiNetDevice::SelectQueue, this)); + } + } + } + } + } + NetDevice::NotifyNewAggregate (); +} + void WifiNetDevice::SetMac (Ptr mac) { @@ -399,4 +438,36 @@ WifiNetDevice::SupportsSendFrom (void) const return m_mac->SupportsSendFrom (); } +uint8_t +WifiNetDevice::SelectQueue (Ptr item) const +{ + NS_LOG_FUNCTION (this << item); + + NS_ASSERT (m_queueInterface != 0); + + if (m_queueInterface->GetTxQueuesN () == 1) + { + return 0; + } + + uint8_t dscp, priority = 0; + if (item->GetUint8Value (QueueItem::IP_DSFIELD, dscp)) + { + // if the QoS map element is implemented, it should be used here + // to set the priority. + // User priority is set to the three most significant bits of the DS field + priority = dscp >> 5; + } + + // replace the priority tag + SocketPriorityTag priorityTag; + priorityTag.SetPriority (priority); + item->GetPacket ()->ReplacePacketTag (priorityTag); + + // if the admission control were implemented, here we should check whether + // the access category assigned to the packet should be downgraded + + return QosUtilsMapTidToAc (priority); +} + } //namespace ns3 diff --git a/src/wifi/model/wifi-net-device.h b/src/wifi/model/wifi-net-device.h index 83ae9cb4d..9791d1dc4 100644 --- a/src/wifi/model/wifi-net-device.h +++ b/src/wifi/model/wifi-net-device.h @@ -114,6 +114,7 @@ public: protected: virtual void DoDispose (void); virtual void DoInitialize (void); + virtual void NotifyNewAggregate (void); /** * Receive a packet from the lower layer and pass the * packet up the stack. @@ -150,10 +151,50 @@ private: */ void CompleteConfig (void); + /** + * \brief Determine the tx queue for a given packet + * \param item the packet + * + * Modelled after the Linux function ieee80211_select_queue (net/mac80211/wme.c). + * A SocketPriority tag is attached to the packet (or the existing one is + * replaced) to carry the user priority, which is set to the three most + * significant bits of the DS field (TOS field in case of IPv4 and Traffic + * Class field in case of IPv6). The Access Category corresponding to the + * user priority according to the QosUtilsMapTidToAc function is returned. + * + * The following table shows the mapping for the Diffserv Per Hop Behaviors. + * + * PHB | TOS (binary) | UP | Access Category + * -----|--------------|-----|----------------- + * EF | 101110xx | 5 | AC_VI + * AF11 | 001010xx | 1 | AC_BK + * AF21 | 010010xx | 2 | AC_BK + * AF31 | 011010xx | 3 | AC_BE + * AF41 | 100010xx | 4 | AC_VI + * AF12 | 001100xx | 1 | AC_BK + * AF22 | 010100xx | 2 | AC_BK + * AF32 | 011100xx | 3 | AC_BE + * AF42 | 100100xx | 4 | AC_VI + * AF13 | 001110xx | 1 | AC_BK + * AF23 | 010110xx | 2 | AC_BK + * AF33 | 011110xx | 3 | AC_BE + * AF43 | 100110xx | 4 | AC_VI + * CS0 | 000000xx | 0 | AC_BE + * CS1 | 001000xx | 1 | AC_BK + * CS2 | 010000xx | 2 | AC_BK + * CS3 | 011000xx | 3 | AC_BE + * CS4 | 100000xx | 4 | AC_VI + * CS5 | 101000xx | 5 | AC_VI + * CS6 | 110000xx | 6 | AC_VO + * CS7 | 111000xx | 7 | AC_VO + */ + uint8_t SelectQueue (Ptr item) const; + Ptr m_node; Ptr m_phy; Ptr m_mac; Ptr m_stationManager; + Ptr m_queueInterface; //!< NetDevice queue interface NetDevice::ReceiveCallback m_forwardUp; NetDevice::PromiscReceiveCallback m_promiscRx;