diff --git a/README b/README.md similarity index 57% rename from README rename to README.md index 6832e07..1b707de 100644 --- a/README +++ b/README.md @@ -1,143 +1,160 @@ -ll-simple-wireless has the following contents: -============================================== -ll-simple-wireless/: - /doc - /examples - /model - wscript - README - -ll-simple-wireless/doc: - simple-wireless.rst - -ll-simple-wireless/examples: - directional_test.cc - error_model_test.cc - fixed_contention_test.cc - mixed_directional_network.cc - multiple_interface_example.cc - queue_test.cc - wscript - -ll-simple-wireless/model: - drop-head-queue.cc - drop-head-queue.h - priority-queue.cc - priority-queue.h - simple-wireless-channel.cc - simple-wireless-channel.h - simple-wireless-net-device.cc - simple-wireless-net-device.h - - -*** Please refer to the file simple-wireless.rst in the /doc folder for more information about this model. - -Installation Instructions -============================================================ -(assumes NS3 is already installed; see below for NS3/DCE installation instructions) - -1. Modify the NS3 wscript file to include simple-wireless in the build - - For example, if using DCE add the following line at ~line 96 in dce/source/ns-3-dce/wscript - ns3waf.check_modules(conf, ['simple-wireless'], mandatory = False) - -2. Install the simple wireless in NS3 source using one of these methods: - a) Copy the files directly to the NS3 directory: /src/simple-wireless - OR - b) Use a softlink to your location of ll-simple-wireless to create the NS3 directory /src/simple-wireless - - NOTE: the directory from the tar file is named ll_simple_wireless but it is installed in NS3 as simple-wireless - -3. Add the simple-wireless as a module in the wscript used to build your NS3 scenario. - - For example: - def configure(conf): - ns3waf.check_modules(conf, ['core', 'internet', 'simple-wireless'], mandatory = True) - - def build(bld): - bld.build_a_script('dce', needed = ['core', 'internet', 'dce', 'mobility', 'simple-wireless'], - target='bin/my_test_script', - cxxflags=['-std=c++0x'], - source=[ my_test_script.cc'] ) - -4. Rebuild NS3 being sure to enable examples if you want to run the example models provided with the Simple Wireless model - -Miscellaneous Notes -=========================================================== -* The Simple Wireless model has been run with NS3.22/DCE1.5, NS3.21/DCE1.4 and NS3.20/DCE1.3 -* The PriorityQueue uses libpcap to classify control packets so this must be installed to use priority queues. - -Installation Instructions for NS3/DCE -============================================================ -The Simple Wireless model works in NS3.20/DCE1.3, NS3.21/DCE1.4 and NS3.22/DCE1.5. -If you have any of these versions currently installed you do not need to install a different version. -The instructions below are for installing NS3.22 and DCE1.5 release but it is not necessary to install -these if you have an earlier, compatible version already installed. - -NOTE: It is assumed that DCE will be installed at ~/dce - -1. Install Bake from your home directory - hg clone http://code.nsnam.org/bake bake - -2. Set path variables - Add the following lines to .profile: - BAKE_HOME="$HOME/bake" - PATH="$PATH:$BAKE_HOME" - PYTHONPATH="/usr/lib/python2.7:$BAKE_HOME" - - Execute the .profile: - . .profile - -3. Increase file descriptor limit to 2048 - To check the current value: $ ulimit –n - To change the current value: $ ulimit –n 2048 - -4. Create a directory for DCE - mkdir dce - -5. Configure, download and build DCE 1.5 (note: this automatically includes ns3.22) - cd dce - bake.py configure -e dce-ns3-1.5 - bake.py download [See note below] - bake.py build - - During download and build, you may run into missing packages. If so, install them using - sudo apt-get install xxxx (where xxxx is the name of the missing package) - Then after installing re-run the download or build command before proceeding to the next step. - - If the gccxml package is missing, the build may complain about pybindgen instead. Install gccxml and the pybindgen problem will probably go away. - - To diagnose a build failure, you may need to use the –vvv flag to get more information: - bake.py build -vvv - - NOTE: Some of the package names may not match what the dce install says is missing. Examples: - DCE name Actual Install Name - -------------------- ------------------- - pybindgen-0.17.0.868 bzr - qt4 qt4-dev-tools - lib_debug libc6-dbg - pygraphviz python-pygraphviz - pygoocanvas python-pygoocanvas - - -********************************************************************************************************************************** -Distribution Statement ----------------------- - - Copyright (C) 2015 Massachusetts Institute of Technology - All rights reserved. - - 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 - -********************************************************************************************************************************** +## Simple wireless module for ns-3 + +### Contents + +`simple-wireless` has the following contents: + +``` +simple-wireless/: + /doc + /examples + /model + wscript + README + +simple-wireless/doc: + simple-wireless.rst + +simple-wireless/examples: + directional_test.cc + error_model_test.cc + fixed_contention_test.cc + mixed_directional_network.cc + multiple_interface_example.cc + queue_test.cc + wscript + +simple-wireless/model: + drop-head-queue.cc + drop-head-queue.h + priority-queue.cc + priority-queue.h + simple-wireless-channel.cc + simple-wireless-channel.h + simple-wireless-net-device.cc + simple-wireless-net-device.h +``` + +** Please refer to the file simple-wireless.rst in the /doc folder for more information about this model.** + +### Installation Instructions + +(assumes `ns-3` is already installed; see below for NS3/DCE installation instructions) + +These installation instructions have been updated for the `ns-3.29` release. + +1. Install the simple wireless in `ns-3` source using one of these methods: + 1. Copy the files directly to the `src` or `contrib` directory: `src/simple-wireless` or `contrib/simple-wireless` (either works the same way), or + 2. Use a softlink to your location of `simple-wireless` to create the `ns-3` directory `src/simple-wireless` or `contrib/simple-wireless`, or + 3. Download using `bake` + +2. Add the `simple-wireless` as a module in the wscript used to build your `ns-3` scenario. For example: +``` + def configure(conf): + ns3waf.check_modules(conf, ['core', 'internet', 'simple-wireless'], mandatory = True) + + def build(bld): + bld.build_a_script('dce', needed = ['core', 'internet', 'dce', 'mobility', 'simple-wireless'], + target='bin/my_test_script', + cxxflags=['-std=c++0x'], + source=[ my_test_script.cc'] ) +``` + +3. Rebuild `ns-3` being sure to enable examples if you want to run the example models provided with the Simple Wireless model + +### Miscellaneous Notes + +* The Simple Wireless model available here is compatible with `ns-3.29`. +* The Simple Wireless model available at MIT-LL github site has been run with NS3.22/DCE1.5, NS3.21/DCE1.4 and NS3.20/DCE1.3 +* The PriorityQueue uses libpcap to classify control packets so this must be installed to use priority queues. + +### Installation Instructions for NS3/DCE + +**Note:** The following instructions pertain to the older v1.0 release. + +The Simple Wireless model works in NS3.20/DCE1.3, NS3.21/DCE1.4 and NS3.22/DCE1.5. +If you have any of these versions currently installed you do not need to install a different version. +The instructions below are for installing NS3.22 and DCE1.5 release but it is not necessary to install +these if you have an earlier, compatible version already installed. + +NOTE: It is assumed that DCE will be installed at ~/dce + +1. Install Bake from your home directory +``` + hg clone http://code.nsnam.org/bake bake +``` + +2. Set path variables. Add the following lines to .profile: +``` + BAKE_HOME="$HOME/bake" + PATH="$PATH:$BAKE_HOME" + PYTHONPATH="/usr/lib/python2.7:$BAKE_HOME" +``` + +3. Execute the .profile: + +``` + . .profile +``` + +4. Increase file descriptor limit to 2048 + * To check the current value: `$ ulimit –n` + * To change the current value: `$ ulimit –n 2048` + +5. Create a directory for DCE +``` + mkdir dce +``` + +6. Configure, download and build DCE 1.5 (note: this automatically includes ns3.22) +``` + cd dce + bake.py configure -e dce-ns3-1.5 + bake.py download [See note below] + bake.py build +``` + During download and build, you may run into missing packages. If so, install them using: + +``` + sudo apt-get install xxxx (where xxxx is the name of the missing package) +``` + Then after installing re-run the download or build command before proceeding to the next step. + + If the gccxml package is missing, the build may complain about pybindgen instead. Install gccxml and the pybindgen problem will probably go away. + + To diagnose a build failure, you may need to use the –vvv flag to get more information: +``` + bake.py build -vvv +``` + NOTE: Some of the package names may not match what the dce install says is missing. Examples: + +``` + DCE name Actual Install Name + -------------------- ------------------- + pybindgen-0.17.0.868 bzr + qt4 qt4-dev-tools + lib_debug libc6-dbg + pygraphviz python-pygraphviz + pygoocanvas python-pygoocanvas +``` + + +### Distribution Statement + +``` + Copyright (C) 2010 University of Washington + Copyright (C) 2015 Massachusetts Institute of Technology + + 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 +``` diff --git a/doc/simple-wireless.rst b/doc/simple-wireless.rst index 8fca45c..468bd5d 100644 --- a/doc/simple-wireless.rst +++ b/doc/simple-wireless.rst @@ -1,519 +1,519 @@ -.. include:: replace.txt -.. highlight:: cpp - -SimpleWireless --------------- - -|ns3| nodes can contain a collection of NetDevice objects, much like an actual -computer contains separate interface cards for Ethernet, Wifi, Bluetooth, etc. -This chapter describes the |ns3| SimpleWirelessNetDevice and related models. -By adding SimpleWirelessNetDevice objects to |ns3| nodes, one can create models -for wireless infrastructure and ad hoc networks. - -Overview of the model -********************* - -SimpleWireless models a wireless network interface controller that is -not based on any specific protocol. Instead, it provides a wireless interface that -is simple in protocol but still allows the user to configure it with useful features. -We will go into more detail below on these features but in brief, -|ns3| SimpleWireless provides models for these aspects of wireless communications: - -* propagation delay -* transmission delay based on the channel data rate (MIT LL) -* support for specifying transmission range -* support for multiple types of error including constant, range based, and stochastic (MIT LL) -* queue support with user configurable queue method (MIT LL) -* queueing of packets to limit the data rate (MIT LL) -* support for differentiating control and data traffic (MIT LL) -* pcap capture of packets sent and received (MIT LL) -* support for simulated directional networking through fixed neighbor lists (MIT LL) -* support for fixed contention (MIT LL) - - -The items marked with (MITLL) are items that have been added by MIT Lincoln Laboratory to -the basic simple wireless model developed by Tom Henderson (available at -http://code.nsnam.org/tomh/ns-3-simple-wireless) - -SimpleWireless does not include MAC protocols and does not model interference. - -In |ns3|, nodes can have multiple SimpleWirelessNetDevices on separate channels, and the -SimpleWirelessNetDevice can coexist with other device types. Presently, however, there is -no model for cross-channel interference or coupling. - -The source code for the SimpleWireless should be installed in the directory -``src/simplewireless``. - -The implementation provides two levels of models: - -* the PHY layer models (SimpleWirelessChannel) -* the device layer model (SimpleWirelessNetDevice) - -Change Log -======================= -**Version 0.3.3** -* Added MacTx and MacRx traces to net-device so that simple wireless has this -trace that exists in MAC models -* Fix bug in net-device which switches the source and destination MAC addresses -during enqueing. Bug only affected scenarios in which queues are NOT used. -* Modify the queue latency trace in net-device to take a pointer to the packet -* Modify net-device to call queue latency trace before stripping the Ethernet -header from packet so that information from the header is available in the -trace for users to access - -**Version 0.3.2** -* Modify implementation for directional networks so the packets are queued -at the device for each directional neighbor that is a destination for the -packet being sent. This includes support for sending unicast such that the -packet is only queued for that one directional neighbor. -* Modify the contention implementation so that the node itself is included -in the count of nodes sharing the bandwidth and also add support for -directional networks. - -**Version 0.3.1** -* Fix bug in drop head queue which can cause a segmentation fault. -Call to DropHeadQueue::DoDequeue was replaced with call to Dequeue method -of the base class so that the accounting of # of packets in the queue is -correct. - -**Version 0.3** -* Add stochastic error model -* Add PhyRxBegin and PhyRxEnd traces to SimpleWirelessNetDevice -* Add source Ethernet address to the SimpleWirelessNetDevice traces (destination Ethernet -address and protocol were already provided to the traces) - -**Version 0.2** -* Add support for simulated directional networking through fixed neighbor lists -* Add support for contention based transmisstion -* Fix bug in Priority Queue which caused segfault when running DCE in optimized mode -* Fix memory leak in Priority Queue in Classify function - -**Version 0.1** -* Implement transmission delay based on the channel data rate -* Implement support for specifying transmission range -* Implement multiple types of error including constant and range based error curves -* Create two new queue types (DropHead and Priority Queue) -* Implement support for user selectable queue method limit the data rate -* Add support for differentiating control and data traffic -* Add pcap capture of packets sent and received - - -SimpleWirelessChannel -======================= - -The SimpleWirelessChannel models the wireless channel used to transmit packets and this -includes the following features: -- Propogation Delay - calculated using packet size and spped of light -- Transmission Delay - calculated using packet size and the channel's data rate -- Transmission Range - user specified -- Packet Error - determined from the user configured range and error model - -When the SimpleWirelessChannel receives a packet from the upper layer to transmit, it -iterates over all the devices attached to channel to determine if it should send -the packet to each device. - -First, the channel looks to see if the device is attached to the node itself. -The channel does not send the packet to the device that is attached to -the node itself (preventing the node from receiving its own packets). - -Second, if directional networking is being used, the channel checks if the device -is attached to the destination node of the packet. If not then the packet is not -sent to the device. - -Next, the channel checks if stochastic error is being used and if so whether or not the -link between the sender and destination is currently on or off. If off, the packet is not -sent to the destiation node device. - -Next, the channel checks if the destination node is within the maximum transmission range -of the sending node based on distance between the sender and the destination. -If the destination node is out of range then the packet is not sent to the destination -node device. - -Finally, the channel checks if the packet would be in error if it were to be transmitted -to the device. This decision is based on the configured error model as follows: -+ If the error model is CONSTANT, then the packet is in error if a randomly -selected error value exceeds the configured error rate. Note that the error rate -is per packet and based on the size of the packet. -+ If the error model is PER_CURVE, then the packet error is determined using the -packet error rate curve specified by the user. The distance between the sender -and the receive is used to pick an error value from this curve, linearly interpolating -between points on the curve. If a random selected value exceeds this error rate, then -the packet is considered in error and is not sent to the device. This too is packet based -error rate. -+ If the error model is STOCHASTIC, then there is no packet error. The decision on handling -of packets (sent or not sent) is made earlier when the state of the link is checked. - -If a device passes all tests (the device is not on the sending node, the device is -in view of the sending, the link to the device is not in the OFF state if STOCHASTIC error -model is being use, the device is in range and the packet error rate is below the threshold) -then a reception event is scheduled for the destination device. - -This process is repeated for all the devices on the channel. - -The SimpleWirelessChannel is only involved on the send side and has no functions -associated with receiving packets. - -It is important to note that packets that are in error are NOT sent. In other words, the -decision is made on the send side and not the receive side. This minimizes the overhead -of a simulation because there are no resources spent on transmitting and receiving a packet -that ultimately will fail reception due to errors. However, this does impede the modeling -of packet interference if it were to be implemented in the SimpleWireless model. Since that -is currently not implemented, it is perfectly fine to drop packets at the source and conserve -simulation resources. - - -SimpleWirelessNetDevice -======================= -The SimpleWirelessNetDevice models the wireless device on the interface of a node and -includes the following features: -- Queue support with user configurable queue method -- Transmission limited by data rate -- Support for differentiating control and data traffic -- Support for pcap capture of packets sent and received -- Support for simulated directional networking through fixed neighbor lists -- Support for fixed contention - -The SimpleWirelessNetDevice supports the use of queue in which to hold packets for transmission. -When queues are used, their purpose is essentially to force a data rate for the device. -Queues are always FIFO but the drop method of the queue is configurable to be either -drop head or drop tail. In addition, there is support for priority queue which implements -separate control and data queues, each of which can be set independently as drop head or drop tail. -When a priority queue is used, a pcap string filter is used to differentiate control and -data packets. Note that it is possible to use no queuing which is the behavior of the original -simple wireless model. - -When queues are used, the SimpleWirelessNetDevice maintains a transmit state flag to indicate -if the device is currently transmitting or is idle. When the SimpleWirelessNetDevice receives -a packet from the upper layer to transmit, it places the packet into the queue and if currently -idle, immediately transmits the packet and sets the flag to busy. After the tranmission -is complete, it sets the flag back to idle and checks the queue to see if there is another -packet waiting to be sent. The transmission time of a packet is based on the packet size -and the data rate (configurable). - -Note that the busy state is set at the net device and not at the channel. As indicated above, -the channel does not actually send any packets that would be delivered in error at the -destination node. The device does not know about this and will be considered "busy" for the -amount of time required to transmit the packet even it the channel does not actually send it. - -When queues are not used, the SimpleWirelessNetDevice immediately sends a packet when it -receives it and does not maintain a busy flag. - -The SimpleWirelessNetDevice implements a simple version of directional networks with -the use of a "neighbor list" which is used to identify the nodes that are in view of the -node as though there was a directional antenna. If this feature is disabled then all nodes -are within view of the node. If this feature is enabled, then only the nodes listed in -the node's neighbor list are considered in view of the node. When directional networking -is enabled for the device, the SimpleWirelessNetDevice enqueues outbound packets as follows: -- A broadcast packet is duplicated and enqueued once for each directional neighbor. -- A unicast packet is enqueued only if the destination is a directional neighbor. - -Note that when the directional network feature is enabled, packets are enqueued for a specific -destination so that when the SimpleWirelessChannel gets the packet, there will be only one -destination device to which the packet will be sent. This differs from the case without a -directional network when only one packet is enqueued. As an example, suppose a node has -3 neighbors. If directional networks are enabled, the device will enqueue 3 packets -- 1 for each -destination. When the channel receives the packet to send, it will only deliver it to one -device on that destination node. If directional networks are not enabled, the device enqueues -one packet. When the channel receives the packet to send, it will deliver it to the three -devices on each of its neighbor nodes. - -The simple wireless model also implements a feature to account for contention. This is -called "fixed contention" feature. The model counts up the number of neigbor nodes that could -cause contention on the channel and reduces the data rate available to a sending node -based on this count. Thus the data rate becomes data rate/# neighbors. -The device uses this new data rate when it determines the transmit time used for setting -how long to keep the busy flag for the device set and for delay associated with transmission. -The manner in which the number of neighbors is counted is as follows: -the count first includes the node itself. Then when the channel transmits -a packet, it loops over all devices on the channel. During this loop the number of destination -devices that are within the user specificed contention range are counted and this is the count -that is used for the next time that a packet arrives on the device to be queued (or sent). -This the information is not the exact number of nodes within contention range at the instant -when a packet is queued but is based on the previous transmit. - -The SimpleWirelessNetDevice supports pcap tracing of packets that are sent and -received by the device. - -The SimpleWirelessNetDevice also supports a receive error model. - -SimpleWireless Model Configuration Items -**************************************** -The following items are configurable on the Simple Wireless Channel - -MaxRange -+ description: Error model used on the send side -+ units: --- -+ default: CONSTANT -+ possible values: CONSTANT, PER_CURVE, or STOCHASTIC - -ErrorModel -+ description: Error model used on the send side -+ units: --- -+ default: CONSTANT -+ possible values: CONSTANT, PER_CURVE, or STOCHASTIC - -ErrorRate -+ description: Error rate associated with the CONSTANT error model. Not used if ErrorModel is set to PER_CURVE. -+ units: --- -+ default: 0.0 -+ possible values: 0.0 to 1.0 inclusive - -AvgLinkUpDuration -+ description: Average duration of link ON state for STOCHASTIC error model. -+ units: TimeValue -+ default: 10000 usec -+ possible values: any TimeValue - -AvgLinkDownDuration -+ description: Avergage duration of link OFF state for STOCHASTIC error model. -+ units: TimeValue -+ default: 100 usec -+ possible values: any TimeValue - -EnableFixedContention -+ description: Flag used to enabled or disable the Fixed Contention feature -+ units: --- -+ default: false -+ possible values: true/false - -FixedContentionRange -+ description: Range used to count the number of neighbors for fixed contention. - If fixed contention is enabled and this value is 0, then uses the value set for MaxRange. -+ units: meters -+ default: 0 -+ possible values: any value > 0 - -PER Curve -+ description: Pairs of used to build the packet error rate (PER) curve. -+ units: meters,error -+ default: --- -+ possible values: distance: > 0 and error: 0.0-1.0 - - -+ description: -+ units: -+ default: -+ possible values: - - -The following items are configurable on the Simple Wireless Device - -ReceiveErrorModel -+ description: Error model used on the receive side. -+ units: --- -+ default: none -+ possible values: --- - -DataRate -+ description: Datarate to use for the device. -+ units: data rate -+ default: 1000000b/s -+ possible values: --- - -FixedNeighborListEnabled -+ description: Flag used to enabled or disable the simulated directional network with fixed neighbor list feature -+ units: --- -+ default: false -+ possible values: true/false - -Fixed Neighbor List -+ description: Node ids to add to the fixed neighbor list when simulating directional networks with neighbor lists. -+ units: node id -+ default: none -+ possible values: any value >= 0 - -TxQueue -+ description: Type of queuing to use if any. -+ units: --- -+ default: NULL (no queue) -+ possible values: NULL, DropTailQueue, DropHeadQueue, PriorityQueue - - -The following items are configurable on the Queues - -Mode -+ description: Drop mode for the queue. - If PACKETS, then packets are dropped from the queue when it is at capacity without regard to size. - If BYTES, then the size of the packets is considered when dropping packets. -+ units: -+ default: QUEUE_MODE_PACKETS -+ possible values: QUEUE_MODE_PACKETS or QUEUE_MODE_BYTES - -MaxPackets -+ description: Maximum number of packets to allow in the queue. Used when mode is QUEUE_MODE_PACKETS. -+ units: --- -+ default: 100 -+ possible values: any value > 0 - -MaxBytes -+ description: Maximum number of bytes to allow in the queue. Used when mode is QUEUE_MODE_BYTES. -+ units: --- -+ default: 6,553,500 -+ possible values: any value > 0 - -ControlPacketClassifier -+ description: String used to classify control packets using a pcap filter when Priority Queues are used. - Examples: - To classify packets based on port: StringValue ("port 698") - To classify packets based on ether type: StringValue ("ether proto 0x88B5") -+ units: --- -+ default: none -+ possible values: any string - - -Using the SimpleWireless Model -****************************** -To use the SimpleWireless model, users need to configure in the following steps: - -1) Create the SimpleWirelessChannel - Ptr phy = CreateObject (); - -2) Configure the SimpleWirelessChannel - a) Set the range for the channel - phy->SetDeviceAttribute ("MaxRange", DoubleValue (txRange)); - - Default value can be set as follows but this must be done BEFORE creating the channel: - Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (txRange)); - - b) Set the error model type - phy->setErrorModelType(CONSTANT); - - c) If the error model type is CONSTANT, set the error rate - phy->setErrorRate(errorRate); - - d) If the error model type is PER_CURVE, build the error curve by calling the function - phy->addToPERmodel(0.0, 0.0); - phy->addToPERmodel(10.0, 0.0); - phy->addToPERmodel(20.0, 0.0); - phy->addToPERmodel(30.0, 0.007); - phy->addToPERmodel(40.0, 0.1); - phy->addToPERmodel(50.0, 0.4); - phy->addToPERmodel(60.0, 0.7); - phy->addToPERmodel(70.0, 0.9); - - e) If the error model type is STOCHASTIC, set the up and down durations - phy->SetAttribute("AvgLinkUpDuration", TimeValue (MicroSeconds (errorUpAvg))); - phy->SetAttribute("AvgLinkDownDuration", TimeValue (MicroSeconds (errorDownAvg))); - - f) If using the fixed contention feature, enable the feature - phy->EnableFixedContention(); - - g) If using the fixed contention feature with a non-default value for the contention range (default value is channel's transmission range) set the contention range value - phy->SetFixedContentionRange(contentionRange); - -3) On EACH node, create SimpleWirelessNetDevice - Ptr simpleWireless = CreateObject (); - -4) Configure the SimpleWirelessChannel - a) Set the channel - simpleWireless->SetChannel(phy); - - b) Set the node - simpleWireless->SetNode(node); - - c) Set the data rate - simpleWireless->SetDataRate(DataRate ("1Mb/s")) - - Default value can be set as follows but this must be done BEFORE creating the devices: - Config::SetDefault ("ns3::SimpleWirelessNetDevice::DataRate", DataRateValue (DataRate (dataRate))); - - d) Set the address - simpleWireless->SetAddress(Mac48Address::Allocate ()); - - e) Create a queue and set this on the device. For example: - Ptr queue = CreateObject (); - simpleWireless->SetQueue(queue); - - The example model queue_test.cc show how to configure each type of queue - - f) Add the device to the node and device container - node->AddDevice (simpleWireless); - devices.Add (simpleWireless); - - g) Enable pcap capture if desired: - std::ostringstream stringStream; - stringStream << "scenario_name_" << node->GetId() << ".pcap"; - fileStr = stringStream.str(); - simpleWireless->EnablePcapAll(fileStr); - -5) If being use, enable directional networking and pass a list of neighbors - This must be done AFTER adding all the devices to each node - NOTE that the code checks the return code from the call to AddDirectionalNeighbors - - Example: In this example, Node 0 has directional neighbors 1, 3, 4, 7, 10, and 11 - Ptr dev0 = devices.Get(0); - Ptr swDev0 = DynamicCast(dev0); - simpleWireless->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); - // build a map of directional neighbor nodes and mac addresses - std::map nbrSet; - for ( NetDeviceContainer::Iterator dIt = devices.Begin(); dIt != devices.End(); ++dIt) - { - Ptr node = (*dIt)->GetNode(); - uint32_t id = node->GetId(); - // in this example, specific node ids are directional neighbors - if ( id == 1 || id == 3 || id == 4 || id == 7 || id == 10 || id == 11 ) - { - // Get mac addr of node and add to map - Address addr = (*dIt)->GetAddress(); - Mac48Address macAddr = Mac48Address::ConvertFrom (addr); - nbrSet.insert(std::pair(id, macAddr)); - std::cout << "Adding node " << id << " with mac address " << macAddr<< std::endl; - } - } - // Now add to dev on node 0 - if (!swDev0->AddDirectionalNeighbors(nbrSet)) - { - NS_FATAL_ERROR ("Call to AddDirectionalNeighbors failed. Please enabled directional neighbors."); - return 0; - } - - There are also functions to allow dynamic simulated directional networking through fixed neighbor lists - by adding and removing neighbor to/from the list over time. This can be done using calls to the methods: - AddDirectionalNeighbor - DeleteDirectionalNeighbor - - -6) Initial the Stochastic error model. This must be done AFTER adding all the devices and does nothing if not running STOCHASTIC error model - phy->InitStochasticModel(); - -SimpleWirelessNetDevice Model Traces -************************************ -The following traces are available for the device: - -* PhyTxBegin - called when the device sends the packet to the channel for Tx - -* PhyRxBegin - called when a packet has begun being received by the device - -* PhyRxEnd - called when a packet has been completely received by the device - -* PhyRxDrop - called if a packet is dropped by the device during receive - -* PromiscSniffer - called for pcap capture of packets; captures on send and receive - -* QueueLatency - called when a packet is dequeued for transmission - -* MacTx - called when a packet has been received from higher layers and is being queued for transmission - -* MacRx - called when a packet has been received over the air and is being forwarded up the local protocol stack - -SimpleWirelessChannel Model Traces -************************************ -NONE - -SimpleWireless Examples -************************************ -The examples directory has the following examples which show how to configure the -Simple Wireless model and use the features that it has. - -directional_test.cc Provides an example of how to use the simulated directional network feature - -error_model_test.cc Provides an example of how to use the error models added to the send side (CONSTANT, PER_CURVE and STOCHASTIC) - -fixed_contention_test.cc Provides an example of how to use the fixed contention feature - -multiple_interface_example.cc Provides a simple 2 node example of how to configure multiple interfaces on a node - -mixed_directional_network.cc Provides a more complex example of multiple interfaces per node in combination with the simulated directional networks. - -queue_test.cc Provides examples of how to configure each type of queuing. - +.. include:: replace.txt +.. highlight:: cpp + +SimpleWireless +-------------- + +|ns3| nodes can contain a collection of NetDevice objects, much like an actual +computer contains separate interface cards for Ethernet, Wifi, Bluetooth, etc. +This chapter describes the |ns3| SimpleWirelessNetDevice and related models. +By adding SimpleWirelessNetDevice objects to |ns3| nodes, one can create models +for wireless infrastructure and ad hoc networks. + +Overview of the model +********************* + +SimpleWireless models a wireless network interface controller that is +not based on any specific protocol. Instead, it provides a wireless interface that +is simple in protocol but still allows the user to configure it with useful features. +We will go into more detail below on these features but in brief, +|ns3| SimpleWireless provides models for these aspects of wireless communications: + +* propagation delay +* transmission delay based on the channel data rate (MIT LL) +* support for specifying transmission range +* support for multiple types of error including constant, range based, and stochastic (MIT LL) +* queue support with user configurable queue method (MIT LL) +* queueing of packets to limit the data rate (MIT LL) +* support for differentiating control and data traffic (MIT LL) +* pcap capture of packets sent and received (MIT LL) +* support for simulated directional networking through fixed neighbor lists (MIT LL) +* support for fixed contention (MIT LL) + + +The items marked with (MITLL) are items that have been added by MIT Lincoln Laboratory to +the basic simple wireless model developed by Tom Henderson (available at +http://code.nsnam.org/tomh/ns-3-simple-wireless) + +SimpleWireless does not include MAC protocols and does not model interference. + +In |ns3|, nodes can have multiple SimpleWirelessNetDevices on separate channels, and the +SimpleWirelessNetDevice can coexist with other device types. Presently, however, there is +no model for cross-channel interference or coupling. + +The source code for the SimpleWireless should be installed in the directory +``src/simplewireless``. + +The implementation provides two levels of models: + +* the PHY layer models (SimpleWirelessChannel) +* the device layer model (SimpleWirelessNetDevice) + +Change Log +======================= +**Version 0.3.3** +* Added MacTx and MacRx traces to net-device so that simple wireless has this +trace that exists in MAC models +* Fix bug in net-device which switches the source and destination MAC addresses +during enqueing. Bug only affected scenarios in which queues are NOT used. +* Modify the queue latency trace in net-device to take a pointer to the packet +* Modify net-device to call queue latency trace before stripping the Ethernet +header from packet so that information from the header is available in the +trace for users to access + +**Version 0.3.2** +* Modify implementation for directional networks so the packets are queued +at the device for each directional neighbor that is a destination for the +packet being sent. This includes support for sending unicast such that the +packet is only queued for that one directional neighbor. +* Modify the contention implementation so that the node itself is included +in the count of nodes sharing the bandwidth and also add support for +directional networks. + +**Version 0.3.1** +* Fix bug in drop head queue which can cause a segmentation fault. +Call to DropHeadQueue::DoDequeue was replaced with call to Dequeue method +of the base class so that the accounting of # of packets in the queue is +correct. + +**Version 0.3** +* Add stochastic error model +* Add PhyRxBegin and PhyRxEnd traces to SimpleWirelessNetDevice +* Add source Ethernet address to the SimpleWirelessNetDevice traces (destination Ethernet +address and protocol were already provided to the traces) + +**Version 0.2** +* Add support for simulated directional networking through fixed neighbor lists +* Add support for contention based transmisstion +* Fix bug in Priority Queue which caused segfault when running DCE in optimized mode +* Fix memory leak in Priority Queue in Classify function + +**Version 0.1** +* Implement transmission delay based on the channel data rate +* Implement support for specifying transmission range +* Implement multiple types of error including constant and range based error curves +* Create two new queue types (DropHead and Priority Queue) +* Implement support for user selectable queue method limit the data rate +* Add support for differentiating control and data traffic +* Add pcap capture of packets sent and received + + +SimpleWirelessChannel +======================= + +The SimpleWirelessChannel models the wireless channel used to transmit packets and this +includes the following features: +- Propogation Delay - calculated using packet size and spped of light +- Transmission Delay - calculated using packet size and the channel's data rate +- Transmission Range - user specified +- Packet Error - determined from the user configured range and error model + +When the SimpleWirelessChannel receives a packet from the upper layer to transmit, it +iterates over all the devices attached to channel to determine if it should send +the packet to each device. + +First, the channel looks to see if the device is attached to the node itself. +The channel does not send the packet to the device that is attached to +the node itself (preventing the node from receiving its own packets). + +Second, if directional networking is being used, the channel checks if the device +is attached to the destination node of the packet. If not then the packet is not +sent to the device. + +Next, the channel checks if stochastic error is being used and if so whether or not the +link between the sender and destination is currently on or off. If off, the packet is not +sent to the destiation node device. + +Next, the channel checks if the destination node is within the maximum transmission range +of the sending node based on distance between the sender and the destination. +If the destination node is out of range then the packet is not sent to the destination +node device. + +Finally, the channel checks if the packet would be in error if it were to be transmitted +to the device. This decision is based on the configured error model as follows: ++ If the error model is CONSTANT, then the packet is in error if a randomly +selected error value exceeds the configured error rate. Note that the error rate +is per packet and based on the size of the packet. ++ If the error model is PER_CURVE, then the packet error is determined using the +packet error rate curve specified by the user. The distance between the sender +and the receive is used to pick an error value from this curve, linearly interpolating +between points on the curve. If a random selected value exceeds this error rate, then +the packet is considered in error and is not sent to the device. This too is packet based +error rate. ++ If the error model is STOCHASTIC, then there is no packet error. The decision on handling +of packets (sent or not sent) is made earlier when the state of the link is checked. + +If a device passes all tests (the device is not on the sending node, the device is +in view of the sending, the link to the device is not in the OFF state if STOCHASTIC error +model is being use, the device is in range and the packet error rate is below the threshold) +then a reception event is scheduled for the destination device. + +This process is repeated for all the devices on the channel. + +The SimpleWirelessChannel is only involved on the send side and has no functions +associated with receiving packets. + +It is important to note that packets that are in error are NOT sent. In other words, the +decision is made on the send side and not the receive side. This minimizes the overhead +of a simulation because there are no resources spent on transmitting and receiving a packet +that ultimately will fail reception due to errors. However, this does impede the modeling +of packet interference if it were to be implemented in the SimpleWireless model. Since that +is currently not implemented, it is perfectly fine to drop packets at the source and conserve +simulation resources. + + +SimpleWirelessNetDevice +======================= +The SimpleWirelessNetDevice models the wireless device on the interface of a node and +includes the following features: +- Queue support with user configurable queue method +- Transmission limited by data rate +- Support for differentiating control and data traffic +- Support for pcap capture of packets sent and received +- Support for simulated directional networking through fixed neighbor lists +- Support for fixed contention + +The SimpleWirelessNetDevice supports the use of queue in which to hold packets for transmission. +When queues are used, their purpose is essentially to force a data rate for the device. +Queues are always FIFO but the drop method of the queue is configurable to be either +drop head or drop tail. In addition, there is support for priority queue which implements +separate control and data queues, each of which can be set independently as drop head or drop tail. +When a priority queue is used, a pcap string filter is used to differentiate control and +data packets. Note that it is possible to use no queuing which is the behavior of the original +simple wireless model. + +When queues are used, the SimpleWirelessNetDevice maintains a transmit state flag to indicate +if the device is currently transmitting or is idle. When the SimpleWirelessNetDevice receives +a packet from the upper layer to transmit, it places the packet into the queue and if currently +idle, immediately transmits the packet and sets the flag to busy. After the tranmission +is complete, it sets the flag back to idle and checks the queue to see if there is another +packet waiting to be sent. The transmission time of a packet is based on the packet size +and the data rate (configurable). + +Note that the busy state is set at the net device and not at the channel. As indicated above, +the channel does not actually send any packets that would be delivered in error at the +destination node. The device does not know about this and will be considered "busy" for the +amount of time required to transmit the packet even it the channel does not actually send it. + +When queues are not used, the SimpleWirelessNetDevice immediately sends a packet when it +receives it and does not maintain a busy flag. + +The SimpleWirelessNetDevice implements a simple version of directional networks with +the use of a "neighbor list" which is used to identify the nodes that are in view of the +node as though there was a directional antenna. If this feature is disabled then all nodes +are within view of the node. If this feature is enabled, then only the nodes listed in +the node's neighbor list are considered in view of the node. When directional networking +is enabled for the device, the SimpleWirelessNetDevice enqueues outbound packets as follows: +- A broadcast packet is duplicated and enqueued once for each directional neighbor. +- A unicast packet is enqueued only if the destination is a directional neighbor. + +Note that when the directional network feature is enabled, packets are enqueued for a specific +destination so that when the SimpleWirelessChannel gets the packet, there will be only one +destination device to which the packet will be sent. This differs from the case without a +directional network when only one packet is enqueued. As an example, suppose a node has +3 neighbors. If directional networks are enabled, the device will enqueue 3 packets -- 1 for each +destination. When the channel receives the packet to send, it will only deliver it to one +device on that destination node. If directional networks are not enabled, the device enqueues +one packet. When the channel receives the packet to send, it will deliver it to the three +devices on each of its neighbor nodes. + +The simple wireless model also implements a feature to account for contention. This is +called "fixed contention" feature. The model counts up the number of neigbor nodes that could +cause contention on the channel and reduces the data rate available to a sending node +based on this count. Thus the data rate becomes data rate/# neighbors. +The device uses this new data rate when it determines the transmit time used for setting +how long to keep the busy flag for the device set and for delay associated with transmission. +The manner in which the number of neighbors is counted is as follows: +the count first includes the node itself. Then when the channel transmits +a packet, it loops over all devices on the channel. During this loop the number of destination +devices that are within the user specificed contention range are counted and this is the count +that is used for the next time that a packet arrives on the device to be queued (or sent). +This the information is not the exact number of nodes within contention range at the instant +when a packet is queued but is based on the previous transmit. + +The SimpleWirelessNetDevice supports pcap tracing of packets that are sent and +received by the device. + +The SimpleWirelessNetDevice also supports a receive error model. + +SimpleWireless Model Configuration Items +**************************************** +The following items are configurable on the Simple Wireless Channel + +MaxRange ++ description: Error model used on the send side ++ units: --- ++ default: CONSTANT ++ possible values: CONSTANT, PER_CURVE, or STOCHASTIC + +ErrorModel ++ description: Error model used on the send side ++ units: --- ++ default: CONSTANT ++ possible values: CONSTANT, PER_CURVE, or STOCHASTIC + +ErrorRate ++ description: Error rate associated with the CONSTANT error model. Not used if ErrorModel is set to PER_CURVE. ++ units: --- ++ default: 0.0 ++ possible values: 0.0 to 1.0 inclusive + +AvgLinkUpDuration ++ description: Average duration of link ON state for STOCHASTIC error model. ++ units: TimeValue ++ default: 10000 usec ++ possible values: any TimeValue + +AvgLinkDownDuration ++ description: Avergage duration of link OFF state for STOCHASTIC error model. ++ units: TimeValue ++ default: 100 usec ++ possible values: any TimeValue + +EnableFixedContention ++ description: Flag used to enabled or disable the Fixed Contention feature ++ units: --- ++ default: false ++ possible values: true/false + +FixedContentionRange ++ description: Range used to count the number of neighbors for fixed contention. + If fixed contention is enabled and this value is 0, then uses the value set for MaxRange. ++ units: meters ++ default: 0 ++ possible values: any value > 0 + +PER Curve ++ description: Pairs of used to build the packet error rate (PER) curve. ++ units: meters,error ++ default: --- ++ possible values: distance: > 0 and error: 0.0-1.0 + + ++ description: ++ units: ++ default: ++ possible values: + + +The following items are configurable on the Simple Wireless Device + +ReceiveErrorModel ++ description: Error model used on the receive side. ++ units: --- ++ default: none ++ possible values: --- + +DataRate ++ description: Datarate to use for the device. ++ units: data rate ++ default: 1000000b/s ++ possible values: --- + +FixedNeighborListEnabled ++ description: Flag used to enabled or disable the simulated directional network with fixed neighbor list feature ++ units: --- ++ default: false ++ possible values: true/false + +Fixed Neighbor List ++ description: Node ids to add to the fixed neighbor list when simulating directional networks with neighbor lists. ++ units: node id ++ default: none ++ possible values: any value >= 0 + +TxQueue ++ description: Type of queuing to use if any. ++ units: --- ++ default: NULL (no queue) ++ possible values: NULL, DropTailQueue, DropHeadQueue, PriorityQueue + + +The following items are configurable on the Queues + +Mode ++ description: Drop mode for the queue. + If PACKETS, then packets are dropped from the queue when it is at capacity without regard to size. + If BYTES, then the size of the packets is considered when dropping packets. ++ units: ++ default: QUEUE_MODE_PACKETS ++ possible values: QUEUE_MODE_PACKETS or QUEUE_MODE_BYTES + +MaxPackets ++ description: Maximum number of packets to allow in the queue. Used when mode is QUEUE_MODE_PACKETS. ++ units: --- ++ default: 100 ++ possible values: any value > 0 + +MaxBytes ++ description: Maximum number of bytes to allow in the queue. Used when mode is QUEUE_MODE_BYTES. ++ units: --- ++ default: 6,553,500 ++ possible values: any value > 0 + +ControlPacketClassifier ++ description: String used to classify control packets using a pcap filter when Priority Queues are used. + Examples: + To classify packets based on port: StringValue ("port 698") + To classify packets based on ether type: StringValue ("ether proto 0x88B5") ++ units: --- ++ default: none ++ possible values: any string + + +Using the SimpleWireless Model +****************************** +To use the SimpleWireless model, users need to configure in the following steps: + +1) Create the SimpleWirelessChannel + Ptr phy = CreateObject (); + +2) Configure the SimpleWirelessChannel + a) Set the range for the channel + phy->SetDeviceAttribute ("MaxRange", DoubleValue (txRange)); + + Default value can be set as follows but this must be done BEFORE creating the channel: + Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (txRange)); + + b) Set the error model type + phy->setErrorModelType(CONSTANT); + + c) If the error model type is CONSTANT, set the error rate + phy->setErrorRate(errorRate); + + d) If the error model type is PER_CURVE, build the error curve by calling the function + phy->addToPERmodel(0.0, 0.0); + phy->addToPERmodel(10.0, 0.0); + phy->addToPERmodel(20.0, 0.0); + phy->addToPERmodel(30.0, 0.007); + phy->addToPERmodel(40.0, 0.1); + phy->addToPERmodel(50.0, 0.4); + phy->addToPERmodel(60.0, 0.7); + phy->addToPERmodel(70.0, 0.9); + + e) If the error model type is STOCHASTIC, set the up and down durations + phy->SetAttribute("AvgLinkUpDuration", TimeValue (MicroSeconds (errorUpAvg))); + phy->SetAttribute("AvgLinkDownDuration", TimeValue (MicroSeconds (errorDownAvg))); + + f) If using the fixed contention feature, enable the feature + phy->EnableFixedContention(); + + g) If using the fixed contention feature with a non-default value for the contention range (default value is channel's transmission range) set the contention range value + phy->SetFixedContentionRange(contentionRange); + +3) On EACH node, create SimpleWirelessNetDevice + Ptr simpleWireless = CreateObject (); + +4) Configure the SimpleWirelessChannel + a) Set the channel + simpleWireless->SetChannel(phy); + + b) Set the node + simpleWireless->SetNode(node); + + c) Set the data rate + simpleWireless->SetDataRate(DataRate ("1Mb/s")) + + Default value can be set as follows but this must be done BEFORE creating the devices: + Config::SetDefault ("ns3::SimpleWirelessNetDevice::DataRate", DataRateValue (DataRate (dataRate))); + + d) Set the address + simpleWireless->SetAddress(Mac48Address::Allocate ()); + + e) Create a queue and set this on the device. For example: + Ptr queue = CreateObject (); + simpleWireless->SetQueue(queue); + + The example model queue_test.cc show how to configure each type of queue + + f) Add the device to the node and device container + node->AddDevice (simpleWireless); + devices.Add (simpleWireless); + + g) Enable pcap capture if desired: + std::ostringstream stringStream; + stringStream << "scenario_name_" << node->GetId() << ".pcap"; + fileStr = stringStream.str(); + simpleWireless->EnablePcapAll(fileStr); + +5) If being use, enable directional networking and pass a list of neighbors + This must be done AFTER adding all the devices to each node + NOTE that the code checks the return code from the call to AddDirectionalNeighbors + + Example: In this example, Node 0 has directional neighbors 1, 3, 4, 7, 10, and 11 + Ptr dev0 = devices.Get(0); + Ptr swDev0 = DynamicCast(dev0); + simpleWireless->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); + // build a map of directional neighbor nodes and mac addresses + std::map nbrSet; + for ( NetDeviceContainer::Iterator dIt = devices.Begin(); dIt != devices.End(); ++dIt) + { + Ptr node = (*dIt)->GetNode(); + uint32_t id = node->GetId(); + // in this example, specific node ids are directional neighbors + if ( id == 1 || id == 3 || id == 4 || id == 7 || id == 10 || id == 11 ) + { + // Get mac addr of node and add to map + Address addr = (*dIt)->GetAddress(); + Mac48Address macAddr = Mac48Address::ConvertFrom (addr); + nbrSet.insert(std::pair(id, macAddr)); + std::cout << "Adding node " << id << " with mac address " << macAddr<< std::endl; + } + } + // Now add to dev on node 0 + if (!swDev0->AddDirectionalNeighbors(nbrSet)) + { + NS_FATAL_ERROR ("Call to AddDirectionalNeighbors failed. Please enabled directional neighbors."); + return 0; + } + + There are also functions to allow dynamic simulated directional networking through fixed neighbor lists + by adding and removing neighbor to/from the list over time. This can be done using calls to the methods: + AddDirectionalNeighbor + DeleteDirectionalNeighbor + + +6) Initial the Stochastic error model. This must be done AFTER adding all the devices and does nothing if not running STOCHASTIC error model + phy->InitStochasticModel(); + +SimpleWirelessNetDevice Model Traces +************************************ +The following traces are available for the device: + +* PhyTxBegin - called when the device sends the packet to the channel for Tx + +* PhyRxBegin - called when a packet has begun being received by the device + +* PhyRxEnd - called when a packet has been completely received by the device + +* PhyRxDrop - called if a packet is dropped by the device during receive + +* PromiscSniffer - called for pcap capture of packets; captures on send and receive + +* QueueLatency - called when a packet is dequeued for transmission + +* MacTx - called when a packet has been received from higher layers and is being queued for transmission + +* MacRx - called when a packet has been received over the air and is being forwarded up the local protocol stack + +SimpleWirelessChannel Model Traces +************************************ +NONE + +SimpleWireless Examples +************************************ +The examples directory has the following examples which show how to configure the +Simple Wireless model and use the features that it has. + +directional_test.cc Provides an example of how to use the simulated directional network feature + +error_model_test.cc Provides an example of how to use the error models added to the send side (CONSTANT, PER_CURVE and STOCHASTIC) + +fixed_contention_test.cc Provides an example of how to use the fixed contention feature + +multiple_interface_example.cc Provides a simple 2 node example of how to configure multiple interfaces on a node + +mixed_directional_network.cc Provides a more complex example of multiple interfaces per node in combination with the simulated directional networks. + +queue_test.cc Provides examples of how to configure each type of queuing. + diff --git a/examples/directional_test.cc b/examples/directional_test.cc index 131aeb7..e6a4a8c 100644 --- a/examples/directional_test.cc +++ b/examples/directional_test.cc @@ -1,441 +1,442 @@ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * All rights reserved. - * - * 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 -*/ - -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ - -#include -#include -#include -#include -#include -#include "ns3/core-module.h" -#include "ns3/network-module.h" -#include "ns3/olsr-module.h" -#include "ns3/mobility-module.h" -#include "ns3/applications-module.h" -#include "ns3/internet-module.h" -#include "ns3/simple-wireless-module.h" - - -// This file is used to test the directional network option. -// For directional networks, the user must specify a list of neighbors that -// can be seen. If a neighbor can not be seen, all packets are dropped for -// that neighbr. If a neighbor can be seen, the configured error is then -// applied to the packet transmit. -// -// The scenario has the following: -// - 13 nodes -// - node 0 is at the center of a circle -// - nodes 1-12 are placed on a circle of radius 50 in a clock face layout -// (i.e., node 1 at 1 o'clock position, node 2 at 2 o'clock position, etc.) -// - no mobility -// - simple wireless model has: -// + constant error rate of 0 -// + tx range of 100 so that all nodes are in range of node 0 -// + drop head queue -// + 10Mbps data rate -// + simple wireless is configured to NOT drop any packets due to queueing -// - OLSR used for routing -// - On/Off application used for node 0 to send 1Mb/s to all 12 neighbor nodes -// - capability to enable pcap capture - -// The following nodes are added to the list of neighbors for directional networking: -// 1, 3, 4, 7, 10, 11 -// -// X -// 11 1 -// 10 X -// X O 3 -// X 4 -// 7 X -// X - -using namespace ns3; - -NS_LOG_COMPONENT_DEFINE ("directional_test"); - -uint32_t app_count_sent = 0; -uint32_t app_count_recv = 0; -uint32_t pkts_sent_data = 0; -uint32_t pkts_rcvd_data = 0; -uint32_t pkts_sent_cntl = 0; - -// variables for queue latency: overall, data and control -double_t avg_queue_latency = 0.0; -uint32_t queue_pkt_count = 0; -double_t avg_queue_latency_data = 0.0; -uint32_t queue_pkt_count_data = 0; -double_t avg_queue_latency_cntl = 0.0; -uint32_t queue_pkt_count_cntl = 0; - -#define NUM_NODES 13 -#define NUM_DIR_NBR_NODES 6 // nodes 1, 3, 4, 7, 10, 11 are directional neighbors -uint32_t pkts_rcvd_by_node[NUM_NODES]; - -#define APP_PKT_SIZE 1000 -std::string PktSize = "1000"; - - -// ****************************************************************** -// This function supports OLSR when running on Simple Wireless -// ****************************************************************** -static void TransmitStatsSW (Ptr p, Mac48Address from, Mac48Address to , uint16_t protocol) -{ - // Figure out if this is OLSR or data - if (p->GetSize() == (APP_PKT_SIZE + 28)) - { - pkts_sent_data++; - } - else - { - pkts_sent_cntl++; - } - - -} - - -static void MacRxSuccess (std::string context, Ptr p) -{ - int id = atoi(context.c_str()); - if (p->GetSize() == (APP_PKT_SIZE + 28)) - { - pkts_rcvd_by_node[id]++; - pkts_rcvd_data++; - } -} - -// ****************************************************************** -// This function supports Simple Wireless -// ****************************************************************** -static void QueueLatencyStats (Ptr p, Time latency) -{ - double_t pkt_latency = double_t(latency.GetMicroSeconds())/1000000.0; - - queue_pkt_count++; - avg_queue_latency = avg_queue_latency * (queue_pkt_count-1)/queue_pkt_count + pkt_latency/queue_pkt_count; - - // add 28 bytes to ap size for UDP/IP header and also add 14 for ethernet header. - // Packet passed in this trace still has the Ethernet header - if (p->GetSize() == (APP_PKT_SIZE + 28 + 14)) - { - queue_pkt_count_data++; - avg_queue_latency_data = avg_queue_latency_data * (queue_pkt_count_data-1)/queue_pkt_count_data + pkt_latency/queue_pkt_count_data; - //std::cout << Simulator::Now ().GetSeconds () << " DATA Packet latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; - } - else - { - queue_pkt_count_cntl++; - avg_queue_latency_cntl = avg_queue_latency_cntl * (queue_pkt_count_cntl-1)/queue_pkt_count_cntl + pkt_latency/queue_pkt_count_cntl; - //std::cout << Simulator::Now ().GetSeconds () << " CONTROL Packet ("<< p->GetSize() << ") latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; - } - -} - - -// ****************************************************************** -// These functions support OLSR and are related to the Applications -// ****************************************************************** - -static void SinkReceivedBytes (Ptr p, const Address & from) -{ - app_count_recv++; - //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; -} - -static void AppSendBytes (Ptr p) -{ - app_count_sent++; - //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; -} - - -// ****************************************************************** -// MAIN -// ****************************************************************** - -int -main (int argc, char *argv[]) -{ - NodeContainer::Iterator it; - NodeContainer::Iterator it2; - std::list destAddresses; // used by OLSR - - Ipv4Address sourceNodeAddr; - - - // *********************************************************************** - // Initialize all value that are to be used in the scenario - // *********************************************************************** - double simtime = 65; - bool collectPcap = false; - double dataRate = 10000000.0; - - // *********************************************************************** - // parse command line - // *********************************************************************** - CommandLine cmd; - cmd.AddValue ("pcap", "Set to 1 to collect pcap traces", collectPcap); - cmd.Parse (argc,argv); - - std::cout << "Running scenario for " << simtime << " seconds "<< std::endl; - - // *********************************************************************** - // Create all the nodes - // *********************************************************************** - NodeContainer myNodes; - myNodes.Create (NUM_NODES); - NodeContainer const & n = NodeContainer::GetGlobal (); - - // Create container to hold devices - NetDeviceContainer devices; - - // *********************************************************************** - // Set up the physical/radio layer - // *********************************************************************** - // Set transmission range - Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); - - // Create error model and set as default for the device Receive side - // ALWAYS set the error rate to 0 here. The error is handled on the send side - // by the channel model in the simple wireless - Ptr em = CreateObject (); - em->SetAttribute ("ErrorRate", DoubleValue (0.0)); - em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); - Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue(em)); - - // create channel - Ptr phy = CreateObject (); - phy->setErrorRate(0.0); - phy->setErrorModelType(CONSTANT); - - // Uncomment these two lines if you would like to also use contention - //phy->EnableFixedContention(); - //phy->SetFixedContentionRange(100.0); - - // create simple wireless device on each node - std::string fileStr; - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - - // create device - Ptr simpleWireless = CreateObject (); - simpleWireless->SetChannel(phy); - simpleWireless->SetNode(node); - simpleWireless->SetAddress(Mac48Address::Allocate ()); - simpleWireless->SetDataRate((DataRate (dataRate))); - std::cout << "node id " << node->GetId() << " has macAddress of " << simpleWireless->GetAddress() << std::endl; - - // Set queue type to use - Config::SetDefault ("ns3::DropHeadQueue::Mode", StringValue ("QUEUE_MODE_PACKETS")); - Config::SetDefault ("ns3::DropHeadQueue::MaxPackets", UintegerValue (100)); - Ptr queue = CreateObject (); - simpleWireless->SetQueue(queue); - - // Set up trace to pass node id on the RX end - std::ostringstream oss; - oss << node->GetId(); - simpleWireless->TraceConnect ("MacRx", oss.str(), MakeCallback (&MacRxSuccess)); - - node->AddDevice (simpleWireless); - devices.Add (simpleWireless); - - // set up pcap capture - if (collectPcap) - { - std::ostringstream stringStream; - stringStream << "QUEUE_node_" << node->GetId() << ".pcap"; - fileStr = stringStream.str(); - simpleWireless->EnablePcapAll(fileStr); - } - } - - - // ------------------------------------------------------------------------ - // Set up directional network. Do this after adding all the devices because - // we need to get MAC addresses for the neighbors we want to add - // Only node 0 has directional neighbors. - - // Get node 0 device on the container. - // we added them in numerical order so we know that 0 is node0 - Ptr dev0 = devices.Get(0); - Ptr swDev0 = DynamicCast(dev0); - swDev0->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); - std::map nbrSet; - // Now in this example, we use an iterator to get the devices. - for ( NetDeviceContainer::Iterator dIt = devices.Begin(); dIt != devices.End(); ++dIt) - { - Ptr node = (*dIt)->GetNode(); - uint32_t id = node->GetId(); - - if ( id == 1 || id == 3 || id == 4 || id == 7 || id == 10 || id == 11 ) - { - // Get mac addr of node and add to map - Address addr = (*dIt)->GetAddress(); - Mac48Address macAddr = Mac48Address::ConvertFrom (addr); - nbrSet.insert(std::pair(id, macAddr)); - std::cout << "Adding node " << id << " with mac address " << macAddr<< std::endl; - } - } - // Now add to dev on node 0 - if (!swDev0->AddDirectionalNeighbors(nbrSet)) - { - NS_FATAL_ERROR ("Call to AddDirectionalNeighbors failed. Please enabled directional neighbors."); - return 0; - } - // ------------------------------------------------------------------------ - - - // set up call back for traces - Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/QueueLatency", MakeCallback (&QueueLatencyStats)); - Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/PhyTxBegin", MakeCallback (&TransmitStatsSW)); - - // *********************************************************************** - // Define positions. - MobilityHelper mobility; - Ptr positionAlloc = CreateObject (); - positionAlloc->Add (Vector ( 0.0, 0.0, 0.0)); - positionAlloc->Add (Vector (25.0, 43.0, 0.0)); - positionAlloc->Add (Vector (43.0, 25.0, 0.0)); - positionAlloc->Add (Vector (50.0, 0.0, 0.0)); - positionAlloc->Add (Vector (43.0, -25.0, 0.0)); - positionAlloc->Add (Vector (25.0, -43.0, 0.0)); - positionAlloc->Add (Vector ( 0.0, -50.0, 0.0)); - positionAlloc->Add (Vector (-25.0,-43.0, 0.0)); - positionAlloc->Add (Vector (-43.0,-25.0, 0.0)); - positionAlloc->Add (Vector (-50.0, 0.0, 0.0)); - positionAlloc->Add (Vector (-43.0, 25.0, 0.0)); - positionAlloc->Add (Vector (-25.0, 43.0, 0.0)); - positionAlloc->Add (Vector ( 0.0, 50.0, 0.0)); - mobility.SetPositionAllocator (positionAlloc); - mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); - mobility.Install (myNodes); - - - // *********************************************************************** - // Set up routing OLSR - // *********************************************************************** - // don't have to use the Ipv4ListRoutingHelper but it prints - // the routing table in a better format than directly installing olsr. - InternetStackHelper stack; - OlsrHelper olsr; - Ipv4ListRoutingHelper list; - - // Add the routing to the route helper - list.Add (olsr, 10); - - // now set the routing and install on all nodes - stack.SetRoutingHelper (list); - stack.Install (myNodes); - - // set up IP addresses - Ipv4AddressHelper address; - address.SetBase ("10.0.0.0", "255.255.0.0"); - Ipv4InterfaceContainer interfaces = address.Assign (devices); - - // *********************************************************************** - // Set up application - // *********************************************************************** - // start the packet sink on all nodes except node 0 - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - uint32_t id = node->GetId(); - - if (id == 0) - { - // **** Choose if you want bcast or unicast traffic by uncommented appropriate line below. - - // start the OnOff app on source to destinations (using broadcast) - OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); - std::cout << "Node 0 installed app to send to 255.255.255.255" << std::endl; - - // start the OnOff app on source to destinations (using unicast) - //OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (1), 8080)); - //std::cout << "Node 0 installed app to send to " << interfaces.GetAddress (1) << std::endl; - - onoff.SetAttribute ("PacketSize", StringValue (PktSize)); - onoff.SetAttribute ("DataRate", StringValue ("1000000")); - onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); - onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); - - ApplicationContainer apps = onoff.Install (myNodes.Get (0)); - apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); - - apps.Start (Seconds (5.0)); - apps.Stop (Seconds (simtime - 5.0)); - } - else - { - // on all other nodes start a packet sink - PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (id), 8080)); - ApplicationContainer apps_sink = sink.Install (myNodes.Get (id)); - apps_sink.Start (Seconds (0.0)); - std::cout << "Node " << id << " installed sink to receive on " << interfaces.GetAddress (id) << std::endl; - } - } - - // set up the sink receive callback on all packet sinks - Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); - - // *********************************************************************** - // and finally ... off we go! - // *********************************************************************** - - Simulator::Stop (Seconds(simtime)); - Simulator::Run (); - Simulator::Destroy (); - - // *********************************************************************** - // For OLSR we need to get some stats - // *********************************************************************** - double rcvPercentData = 0.0; - uint32_t dataDropped = app_count_sent*NUM_DIR_NBR_NODES - app_count_recv; - if (app_count_sent) - rcvPercentData = ((double)app_count_recv/((double)app_count_sent*NUM_DIR_NBR_NODES))*100.0; - - std::cout << "App Packets Sent: " << app_count_sent << "\nApp Packets Received: " << app_count_recv - << "\nControl Packets Sent: " << pkts_sent_cntl - << "\nData Packets Sent: " << pkts_sent_data - << "\nData Packets Received: " << pkts_rcvd_data - << "\nData Packets Dropped: " << dataDropped - << "\n% Data Received: " << std::fixed << std::setprecision(1) << rcvPercentData << std::noshowpoint << std::setprecision(0)< dev = devices.Get(0); - PointerValue val; - dev->GetAttribute("TxQueue", val); - Ptr queue = val.Get(); - Ptr dropHead = DynamicCast(queue); - std::cout << "Packets Dropped at Queue on Node 0: " << dropHead->GetTotalDroppedPackets() << std::endl; - - for (int i = 1; i < NUM_NODES; i++) - { - std::cout << "Packets received by Node " << i << ": " << pkts_rcvd_by_node[i] << std::endl; - } - - - - NS_LOG_INFO ("Run Completed Successfully"); - - return 0; -} +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * All rights reserved. + * + * 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 +*/ + +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include +#include +#include +#include +#include +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/olsr-module.h" +#include "ns3/mobility-module.h" +#include "ns3/applications-module.h" +#include "ns3/internet-module.h" +#include "ns3/simple-wireless-module.h" + + +// This file is used to test the directional network option. +// For directional networks, the user must specify a list of neighbors that +// can be seen. If a neighbor can not be seen, all packets are dropped for +// that neighbr. If a neighbor can be seen, the configured error is then +// applied to the packet transmit. +// +// The scenario has the following: +// - 13 nodes +// - node 0 is at the center of a circle +// - nodes 1-12 are placed on a circle of radius 50 in a clock face layout +// (i.e., node 1 at 1 o'clock position, node 2 at 2 o'clock position, etc.) +// - no mobility +// - simple wireless model has: +// + constant error rate of 0 +// + tx range of 100 so that all nodes are in range of node 0 +// + drop head queue +// + 10Mbps data rate +// + simple wireless is configured to NOT drop any packets due to queueing +// - OLSR used for routing +// - On/Off application used for node 0 to send 1Mb/s to all 12 neighbor nodes +// - capability to enable pcap capture + +// The following nodes are added to the list of neighbors for directional networking: +// 1, 3, 4, 7, 10, 11 +// +// X +// 11 1 +// 10 X +// X O 3 +// X 4 +// 7 X +// X + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("directional_test"); + +uint32_t app_count_sent = 0; +uint32_t app_count_recv = 0; +uint32_t pkts_sent_data = 0; +uint32_t pkts_rcvd_data = 0; +uint32_t pkts_sent_cntl = 0; + +// variables for queue latency: overall, data and control +double_t avg_queue_latency = 0.0; +uint32_t queue_pkt_count = 0; +double_t avg_queue_latency_data = 0.0; +uint32_t queue_pkt_count_data = 0; +double_t avg_queue_latency_cntl = 0.0; +uint32_t queue_pkt_count_cntl = 0; + +#define NUM_NODES 13 +#define NUM_DIR_NBR_NODES 6 // nodes 1, 3, 4, 7, 10, 11 are directional neighbors +uint32_t pkts_rcvd_by_node[NUM_NODES]; + +#define APP_PKT_SIZE 1000 +std::string PktSize = "1000"; + + +// ****************************************************************** +// This function supports OLSR when running on Simple Wireless +// ****************************************************************** +static void TransmitStatsSW (Ptr p, Mac48Address from, Mac48Address to, uint16_t protocol) +{ + // Figure out if this is OLSR or data + if (p->GetSize () == (APP_PKT_SIZE + 28)) + { + pkts_sent_data++; + } + else + { + pkts_sent_cntl++; + } + + +} + + +static void MacRxSuccess (std::string context, Ptr p) +{ + int id = atoi (context.c_str ()); + if (p->GetSize () == (APP_PKT_SIZE + 28)) + { + pkts_rcvd_by_node[id]++; + pkts_rcvd_data++; + } +} + +// ****************************************************************** +// This function supports Simple Wireless +// ****************************************************************** +static void QueueLatencyStats (Ptr p, Time latency) +{ + double_t pkt_latency = double_t (latency.GetMicroSeconds ()) / 1000000.0; + + queue_pkt_count++; + avg_queue_latency = avg_queue_latency * (queue_pkt_count - 1) / queue_pkt_count + pkt_latency / queue_pkt_count; + + // add 28 bytes to ap size for UDP/IP header and also add 14 for ethernet header. + // Packet passed in this trace still has the Ethernet header + if (p->GetSize () == (APP_PKT_SIZE + 28 + 14)) + { + queue_pkt_count_data++; + avg_queue_latency_data = avg_queue_latency_data * (queue_pkt_count_data - 1) / queue_pkt_count_data + pkt_latency / queue_pkt_count_data; + //std::cout << Simulator::Now ().GetSeconds () << " DATA Packet latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; + } + else + { + queue_pkt_count_cntl++; + avg_queue_latency_cntl = avg_queue_latency_cntl * (queue_pkt_count_cntl - 1) / queue_pkt_count_cntl + pkt_latency / queue_pkt_count_cntl; + //std::cout << Simulator::Now ().GetSeconds () << " CONTROL Packet ("<< p->GetSize() << ") latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; + } + +} + + +// ****************************************************************** +// These functions support OLSR and are related to the Applications +// ****************************************************************** + +static void SinkReceivedBytes (Ptr p, const Address & from) +{ + app_count_recv++; + //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; +} + +static void AppSendBytes (Ptr p) +{ + app_count_sent++; + //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; +} + + +// ****************************************************************** +// MAIN +// ****************************************************************** + +int +main (int argc, char *argv[]) +{ + NodeContainer::Iterator it; + NodeContainer::Iterator it2; + std::list destAddresses; // used by OLSR + + Ipv4Address sourceNodeAddr; + + + // *********************************************************************** + // Initialize all value that are to be used in the scenario + // *********************************************************************** + double simtime = 65; + bool collectPcap = false; + double dataRate = 10000000.0; + + // *********************************************************************** + // parse command line + // *********************************************************************** + CommandLine cmd; + cmd.AddValue ("pcap", "Set to 1 to collect pcap traces", collectPcap); + cmd.Parse (argc,argv); + + std::cout << "Running scenario for " << simtime << " seconds " << std::endl; + + // *********************************************************************** + // Create all the nodes + // *********************************************************************** + NodeContainer myNodes; + myNodes.Create (NUM_NODES); + NodeContainer const & n = NodeContainer::GetGlobal (); + + // Create container to hold devices + NetDeviceContainer devices; + + // *********************************************************************** + // Set up the physical/radio layer + // *********************************************************************** + // Set transmission range + Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); + + // Create error model and set as default for the device Receive side + // ALWAYS set the error rate to 0 here. The error is handled on the send side + // by the channel model in the simple wireless + Ptr em = CreateObject (); + em->SetAttribute ("ErrorRate", DoubleValue (0.0)); + em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); + Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue (em)); + + // create channel + Ptr phy = CreateObject (); + phy->setErrorRate (0.0); + phy->setErrorModelType (CONSTANT); + + // Uncomment these two lines if you would like to also use contention + //phy->EnableFixedContention(); + //phy->SetFixedContentionRange(100.0); + + // create simple wireless device on each node + std::string fileStr; + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + + // create device + Ptr simpleWireless = CreateObject (); + simpleWireless->SetChannel (phy); + simpleWireless->SetNode (node); + simpleWireless->SetAddress (Mac48Address::Allocate ()); + simpleWireless->SetDataRate ((DataRate (dataRate))); + std::cout << "node id " << node->GetId () << " has macAddress of " << simpleWireless->GetAddress () << std::endl; + + // Set queue type to use + Ptr> queue = CreateObject> (); + queue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + simpleWireless->SetQueue (queue); + + // Set up trace to pass node id on the RX end + std::ostringstream oss; + oss << node->GetId (); + simpleWireless->TraceConnect ("MacRx", oss.str (), MakeCallback (&MacRxSuccess)); + + node->AddDevice (simpleWireless); + devices.Add (simpleWireless); + + // set up pcap capture + if (collectPcap) + { + std::ostringstream stringStream; + stringStream << "QUEUE_node_" << node->GetId () << ".pcap"; + fileStr = stringStream.str (); + simpleWireless->EnablePcapAll (fileStr); + } + } + + + // ------------------------------------------------------------------------ + // Set up directional network. Do this after adding all the devices because + // we need to get MAC addresses for the neighbors we want to add + // Only node 0 has directional neighbors. + + // Get node 0 device on the container. + // we added them in numerical order so we know that 0 is node0 + Ptr dev0 = devices.Get (0); + Ptr swDev0 = DynamicCast (dev0); + swDev0->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); + std::map nbrSet; + // Now in this example, we use an iterator to get the devices. + for ( NetDeviceContainer::Iterator dIt = devices.Begin (); dIt != devices.End (); ++dIt) + { + Ptr node = (*dIt)->GetNode (); + uint32_t id = node->GetId (); + + if ( id == 1 || id == 3 || id == 4 || id == 7 || id == 10 || id == 11 ) + { + // Get mac addr of node and add to map + Address addr = (*dIt)->GetAddress (); + Mac48Address macAddr = Mac48Address::ConvertFrom (addr); + nbrSet.insert (std::pair (id, macAddr)); + std::cout << "Adding node " << id << " with mac address " << macAddr << std::endl; + } + } + // Now add to dev on node 0 + if (!swDev0->AddDirectionalNeighbors (nbrSet)) + { + NS_FATAL_ERROR ("Call to AddDirectionalNeighbors failed. Please enabled directional neighbors."); + return 0; + } + // ------------------------------------------------------------------------ + + + // set up call back for traces + Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/QueueLatency", MakeCallback (&QueueLatencyStats)); + Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/PhyTxBegin", MakeCallback (&TransmitStatsSW)); + + // *********************************************************************** + // Define positions. + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector ( 0.0, 0.0, 0.0)); + positionAlloc->Add (Vector (25.0, 43.0, 0.0)); + positionAlloc->Add (Vector (43.0, 25.0, 0.0)); + positionAlloc->Add (Vector (50.0, 0.0, 0.0)); + positionAlloc->Add (Vector (43.0, -25.0, 0.0)); + positionAlloc->Add (Vector (25.0, -43.0, 0.0)); + positionAlloc->Add (Vector ( 0.0, -50.0, 0.0)); + positionAlloc->Add (Vector (-25.0,-43.0, 0.0)); + positionAlloc->Add (Vector (-43.0,-25.0, 0.0)); + positionAlloc->Add (Vector (-50.0, 0.0, 0.0)); + positionAlloc->Add (Vector (-43.0, 25.0, 0.0)); + positionAlloc->Add (Vector (-25.0, 43.0, 0.0)); + positionAlloc->Add (Vector ( 0.0, 50.0, 0.0)); + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (myNodes); + + + // *********************************************************************** + // Set up routing OLSR + // *********************************************************************** + // don't have to use the Ipv4ListRoutingHelper but it prints + // the routing table in a better format than directly installing olsr. + InternetStackHelper stack; + OlsrHelper olsr; + Ipv4ListRoutingHelper list; + + // Add the routing to the route helper + list.Add (olsr, 10); + + // now set the routing and install on all nodes + stack.SetRoutingHelper (list); + stack.Install (myNodes); + + // set up IP addresses + Ipv4AddressHelper address; + address.SetBase ("10.0.0.0", "255.255.0.0"); + Ipv4InterfaceContainer interfaces = address.Assign (devices); + + // *********************************************************************** + // Set up application + // *********************************************************************** + // start the packet sink on all nodes except node 0 + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + uint32_t id = node->GetId (); + + if (id == 0) + { + // **** Choose if you want bcast or unicast traffic by uncommented appropriate line below. + + // start the OnOff app on source to destinations (using broadcast) + OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); + std::cout << "Node 0 installed app to send to 255.255.255.255" << std::endl; + + // start the OnOff app on source to destinations (using unicast) + //OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (1), 8080)); + //std::cout << "Node 0 installed app to send to " << interfaces.GetAddress (1) << std::endl; + + onoff.SetAttribute ("PacketSize", StringValue (PktSize)); + onoff.SetAttribute ("DataRate", StringValue ("1000000")); + onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + + ApplicationContainer apps = onoff.Install (myNodes.Get (0)); + apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); + + apps.Start (Seconds (5.0)); + apps.Stop (Seconds (simtime - 5.0)); + } + else + { + // on all other nodes start a packet sink + PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (id), 8080)); + ApplicationContainer apps_sink = sink.Install (myNodes.Get (id)); + apps_sink.Start (Seconds (0.0)); + std::cout << "Node " << id << " installed sink to receive on " << interfaces.GetAddress (id) << std::endl; + } + } + + // set up the sink receive callback on all packet sinks + Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); + + // *********************************************************************** + // and finally ... off we go! + // *********************************************************************** + + Simulator::Stop (Seconds (simtime)); + Simulator::Run (); + Simulator::Destroy (); + + // *********************************************************************** + // For OLSR we need to get some stats + // *********************************************************************** + double rcvPercentData = 0.0; + uint32_t dataDropped = app_count_sent * NUM_DIR_NBR_NODES - app_count_recv; + if (app_count_sent) + { + rcvPercentData = ((double)app_count_recv / ((double)app_count_sent * NUM_DIR_NBR_NODES)) * 100.0; + } + + std::cout << "App Packets Sent: " << app_count_sent << "\nApp Packets Received: " << app_count_recv + << "\nControl Packets Sent: " << pkts_sent_cntl + << "\nData Packets Sent: " << pkts_sent_data + << "\nData Packets Received: " << pkts_rcvd_data + << "\nData Packets Dropped: " << dataDropped + << "\n% Data Received: " << std::fixed << std::setprecision (1) << rcvPercentData << std::noshowpoint << std::setprecision (0) << std::endl; + std::cout << "Average Queue Latency Data: " << std::fixed << std::setprecision (6) << avg_queue_latency_data + << "\nAverage Queue Latency Control: " << std::fixed << std::setprecision (6) << avg_queue_latency_cntl << std::noshowpoint << std::setprecision (0) << std::endl; + std::cout << "Overall Average Queue Latency: " << std::fixed << std::setprecision (6) << avg_queue_latency << std::noshowpoint << std::setprecision (0) << std::endl; + + // get queue packets dropped + Ptr dev = devices.Get (0); + PointerValue val; + dev->GetAttribute ("TxQueue", val); + Ptr> queue = val.Get>(); + Ptr> dropHead = DynamicCast> (queue); + std::cout << "Packets Dropped at Queue on Node 0: " << dropHead->GetTotalDroppedPackets () << std::endl; + + for (int i = 1; i < NUM_NODES; i++) + { + std::cout << "Packets received by Node " << i << ": " << pkts_rcvd_by_node[i] << std::endl; + } + + + + NS_LOG_INFO ("Run Completed Successfully"); + + return 0; +} diff --git a/examples/error_model_test.cc b/examples/error_model_test.cc index 2f9f879..c37c380 100644 --- a/examples/error_model_test.cc +++ b/examples/error_model_test.cc @@ -1,373 +1,373 @@ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * All rights reserved. - * - * 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 -*/ - -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ - -#include -#include -#include -#include -#include -#include "ns3/core-module.h" -#include "ns3/network-module.h" -#include "ns3/olsr-module.h" -#include "ns3/mobility-module.h" -#include "ns3/applications-module.h" -#include "ns3/internet-module.h" -#include "ns3/simple-wireless-module.h" - - -// This file is used to test the error models added to the send side and -// support CONSTANT, PER_CURVE and STOCHASTIC. -// -// The scenario has the following: -// - 101 nodes -// - node 0 is at the center of a circle -// - nodes 1-100 are randomly placed on a circle of radius 100 -// - NO mobility -// - simple wireless model has: -// + User specified error type -// + tx range of 100 -// + NO queue -// - OLSR used for routing -// - On/Off application used for node 0 to send 1Mb/s to all 100 neighbor nodes - -using namespace ns3; - -NS_LOG_COMPONENT_DEFINE ("error_model_test"); - -uint32_t count_sent = 0; -// These are only used by OLSR -uint32_t count_recv = 0; -uint32_t pkts_sent_data = 0; -uint32_t bytes_sent_data = 0; -uint32_t pkts_sent_cntl = 0; -uint32_t bytes_sent_cntl = 0; - -#define APP_PKT_SIZE 1000 -std::string PktSize = "1000"; - -#define NUM_NODES 101 // node 0 is source + N neighbors -uint32_t pkts_rcvd_by_node[NUM_NODES]; - -// ****************************************************************** -// This function supports OLSR when running on Simple Wireless -// ****************************************************************** -static void TransmitStatsSW (Ptr p, Mac48Address from, Mac48Address to , uint16_t protocol) -{ - // Figure out if this is OLSR or data - if (to.IsBroadcast () && p->GetSize() != (APP_PKT_SIZE + 28)) - { - pkts_sent_cntl++; - bytes_sent_cntl += p->GetSize(); - //std::cout << Simulator::Now ().GetSeconds () << " Node sending CONTROL packet of " << p->GetSize() << " bytes to address " << to << std::endl; - } - else - { - pkts_sent_data++; - bytes_sent_data += p->GetSize(); - //std::cout << Simulator::Now ().GetSeconds () << " Node sending DATA packet of " << p->GetSize() << " bytes to address " << to << std::endl; - } -} - -static void MacRxSuccess (std::string context, Ptr p) -{ - int id = atoi(context.c_str()); - if (p->GetSize() == (APP_PKT_SIZE + 28)) - { - pkts_rcvd_by_node[id]++; - // Uncomment this line for STOCHASTIC so that you can graph packets received vs time - std::cout << Simulator::Now ().GetSeconds () << " Node " << id << " receiving packet of " << p->GetSize() << " bytes."<< std::endl; - } - - -} - - -// ****************************************************************** -// These functions are related to the Applications -// ****************************************************************** -static void SinkReceivedBytes (Ptr p, const Address & from) -{ - count_recv++; - //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; -} - -static void AppSendBytes (Ptr p) -{ - count_sent++; - //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; -} - - -// ****************************************************************** -// MAIN -// ****************************************************************** - -int -main (int argc, char *argv[]) -{ - NodeContainer::Iterator it; - NodeContainer::Iterator it2; - std::list destAddresses; // used by OLSR - - Ipv4Address sourceNodeAddr; - - // *********************************************************************** - // Initialize all value that are to be used in the scenario - // *********************************************************************** - double simtime = 65; - double dataRate = 1000000.0; - - bool collectPcap = false; - std::string errorModel = "CONSTANT"; - double errorRate = 0.0; - double errorUpAvg = 15000000.0; // 15 seconds up - double errorDownAvg = 5000000.0; // 5 second down - - // *********************************************************************** - // parse command line - // *********************************************************************** - CommandLine cmd; - cmd.AddValue ("pcap", "Set to 1 to collect pcap traces", collectPcap); - cmd.AddValue ("errorModel", "Error model to use. Must be one of: CONSTANT, CURVE, STOCHASTIC", errorModel); - cmd.AddValue ("errorRate", "Error rate if CONSTANT error model is used", errorRate); - cmd.AddValue ("errorUpAvg", "Average link up duration (microseconds) if STOCHASTIC error model is used", errorUpAvg); - cmd.AddValue ("errorDownAvg", "Average link down duration (microseconds) if STOCHASTIC error model is used", errorDownAvg); - cmd.Parse (argc,argv); - - if ((errorModel != "CONSTANT") && (errorModel != "CURVE") && (errorModel != "STOCHASTIC") ) - { - NS_ABORT_MSG ("Invalid errorModel type: Use --errorModel=CONSTANT or --errorModel=CURVE or --errorModel=STOCHASTIC"); - } - - std::cout << "Running scenario for " << simtime << " seconds using error type of "<< errorModel << std::endl; - - // *********************************************************************** - // Create all the nodes - // *********************************************************************** - NodeContainer myNodes; - myNodes.Create (NUM_NODES); - NodeContainer const & n = NodeContainer::GetGlobal (); - - // Create container to hold devices - NetDeviceContainer devices; - - // *********************************************************************** - // Set up the physical/radio layer - // *********************************************************************** - // Set transmission range - Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); - - // Create error model and set as default for the device Receive side - // ALWAYS set the error rate to 0 here. The error is handled on the send side - // by the channel model in the simple wireless - Ptr em = CreateObject (); - em->SetAttribute ("ErrorRate", DoubleValue (0.0)); - em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); - Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue(em)); - - // create channel - Ptr phy = CreateObject (); - if ( errorModel.compare ("CURVE") == 0 ) - { - phy->setErrorModelType(PER_CURVE); - phy->addToPERmodel(0.0, 0.0); - phy->addToPERmodel(10.0, 0.0); - phy->addToPERmodel(20.0, 0.05); - phy->addToPERmodel(30.0, 0.07); - phy->addToPERmodel(40.0, 0.12); - phy->addToPERmodel(50.0, 0.15); - phy->addToPERmodel(60.0, 0.5); - phy->addToPERmodel(70.0, 0.6); - phy->addToPERmodel(80.0, 0.70); - phy->addToPERmodel(90.0, 0.80); - phy->addToPERmodel(100.0, 1.0); - } - else if ( errorModel.compare ("CONSTANT") == 0 ) - { - phy->setErrorModelType (CONSTANT); - phy->setErrorRate (errorRate); - } - else if ( errorModel.compare ("STOCHASTIC") == 0 ) - { - phy->setErrorModelType(STOCHASTIC); - phy->SetAttribute("AvgLinkUpDuration", TimeValue (MicroSeconds (errorUpAvg))); - phy->SetAttribute("AvgLinkDownDuration", TimeValue (MicroSeconds (errorDownAvg))); - } - - // create simple wireless device on each node - std::string fileStr; - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - - // create device - Ptr simpleWireless = CreateObject (); - simpleWireless->SetChannel(phy); - simpleWireless->SetNode(node); - simpleWireless->SetAddress(Mac48Address::Allocate ()); - simpleWireless->SetDataRate((DataRate (dataRate))); - - // Set up trace to pass node id on the RX end - std::ostringstream oss; - oss << node->GetId(); - simpleWireless->TraceConnect ("MacRx", oss.str(), MakeCallback (&MacRxSuccess)); - - node->AddDevice (simpleWireless); - devices.Add (simpleWireless); - - // set up pcap capture - if (collectPcap) - { - std::ostringstream stringStream; - stringStream << "ErrorModelTest_node_" << node->GetId() << ".pcap"; - fileStr = stringStream.str(); - simpleWireless->EnablePcapAll(fileStr); - } - } - - // Must be done AFTER adding all the devices. Does nothing if not running STOCHASTIC error model - phy->InitStochasticModel(); - - - // set up call back for traces - Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/PhyTxBegin", MakeCallback (&TransmitStatsSW)); - - // *********************************************************************** - // Define positions. - ObjectFactory pos; - pos.SetTypeId ("ns3::UniformDiscPositionAllocator"); - pos.Set ("X", DoubleValue (0.0)); - pos.Set ("Y", DoubleValue (0.0)); - pos.Set ("rho", DoubleValue (100)); - Ptr positionAlloc = pos.Create ()->GetObject (); - - // *********************************************************************** - // Define and install random mobility. Here we are using the circle set up above - // as the position allocator for mobility (i.e., the area they can move in) - // *********************************************************************** - MobilityHelper mobility; - mobility.SetPositionAllocator (positionAlloc); - mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); - mobility.Install (myNodes); - - // print starting positions - for (it = n.Begin (); it != n.End (); ++it) - { - // get node ptr, position and node id - Ptr node = *it; - Ptr mob = node->GetObject (); - int id = node->GetId(); - - // set up source node - if (id == 0) - { - // placed at the center and is the source node! - mob->SetPosition (Vector (0.0,0.0,0.0)); - } - Vector pos = mob->GetPosition (); - double distance = sqrt(pos.x*pos.x + pos.y*pos.y); - std::cout << "Node " << id << ". Position (" << pos.x << ", " << pos.y << ", " << pos.z << ") Distance to Node 0: "<< distance << std::endl; - } - - - - // *********************************************************************** - // Set up routing OLSR - // *********************************************************************** - // don't have to use the Ipv4ListRoutingHelper but it prints - // the routing table in a better format than directly installing olsr. - InternetStackHelper stack; - OlsrHelper olsr; - Ipv4ListRoutingHelper list; - - // Add the routing to the route helper - list.Add (olsr, 10); - - // now set the routing and install on all nodes - stack.SetRoutingHelper (list); - stack.Install (myNodes); - - // set up IP addresses - Ipv4AddressHelper address; - address.SetBase ("10.0.0.0", "255.255.0.0"); - Ipv4InterfaceContainer interfaces = address.Assign (devices); - - // *********************************************************************** - // Set up application - // *********************************************************************** - // start the packet sink on all nodes except node 0 - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - uint32_t id = node->GetId(); - - if (id == 0) - { - // start the OnOff app on source to destinations (using broadcast) - OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); - onoff.SetAttribute ("PacketSize", StringValue (PktSize)); - onoff.SetAttribute ("DataRate", StringValue ("1000000")); - onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); - onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); - - ApplicationContainer apps = onoff.Install (myNodes.Get (0)); - std::cout << "Node 0 installed app to send to 255.255.255.255" << std::endl; - apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); - - apps.Start (Seconds (5.0)); - apps.Stop (Seconds (simtime - 5.0)); - } - else - { - // on all other nodes start a packet sink - PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (id), 8080)); - ApplicationContainer apps_sink = sink.Install (myNodes.Get (id)); - apps_sink.Start (Seconds (0.0)); - //std::cout << "Node " << id << " installed sink to receive on " << interfaces.GetAddress (id) << std::endl; - pkts_rcvd_by_node[id] = 0; - } - } - - // set up the sink receive callback on all packet sinks - Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); - - // *********************************************************************** - // and finally ... off we go! - // *********************************************************************** - - Simulator::Stop (Seconds(simtime)); - Simulator::Run (); - Simulator::Destroy (); - - // *********************************************************************** - // For OLSR we need to get some stats - // *********************************************************************** - std::cout << "App Sent Count: " << count_sent << "\nApp Receive Count: " << count_recv << std::endl; - std::cout << "Control Sent Count: " << pkts_sent_cntl << "\nData Sent Count: " << pkts_sent_data << std::endl; - for (int i = 1; i < NUM_NODES; i++) - { - std::cout << "Packets received by Node " << i << ": " << pkts_rcvd_by_node[i] << std::endl; - } - - - NS_LOG_INFO ("Run Completed Successfully"); - - return 0; -} +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * All rights reserved. + * + * 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 +*/ + +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include +#include +#include +#include +#include +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/olsr-module.h" +#include "ns3/mobility-module.h" +#include "ns3/applications-module.h" +#include "ns3/internet-module.h" +#include "ns3/simple-wireless-module.h" + + +// This file is used to test the error models added to the send side and +// support CONSTANT, PER_CURVE and STOCHASTIC. +// +// The scenario has the following: +// - 101 nodes +// - node 0 is at the center of a circle +// - nodes 1-100 are randomly placed on a circle of radius 100 +// - NO mobility +// - simple wireless model has: +// + User specified error type +// + tx range of 100 +// + NO queue +// - OLSR used for routing +// - On/Off application used for node 0 to send 1Mb/s to all 100 neighbor nodes + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("error_model_test"); + +uint32_t count_sent = 0; +// These are only used by OLSR +uint32_t count_recv = 0; +uint32_t pkts_sent_data = 0; +uint32_t bytes_sent_data = 0; +uint32_t pkts_sent_cntl = 0; +uint32_t bytes_sent_cntl = 0; + +#define APP_PKT_SIZE 1000 +std::string PktSize = "1000"; + +#define NUM_NODES 101 // node 0 is source + N neighbors +uint32_t pkts_rcvd_by_node[NUM_NODES]; + +// ****************************************************************** +// This function supports OLSR when running on Simple Wireless +// ****************************************************************** +static void TransmitStatsSW (Ptr p, Mac48Address from, Mac48Address to, uint16_t protocol) +{ + // Figure out if this is OLSR or data + if (to.IsBroadcast () && p->GetSize () != (APP_PKT_SIZE + 28)) + { + pkts_sent_cntl++; + bytes_sent_cntl += p->GetSize (); + //std::cout << Simulator::Now ().GetSeconds () << " Node sending CONTROL packet of " << p->GetSize() << " bytes to address " << to << std::endl; + } + else + { + pkts_sent_data++; + bytes_sent_data += p->GetSize (); + //std::cout << Simulator::Now ().GetSeconds () << " Node sending DATA packet of " << p->GetSize() << " bytes to address " << to << std::endl; + } +} + +static void MacRxSuccess (std::string context, Ptr p) +{ + int id = atoi (context.c_str ()); + if (p->GetSize () == (APP_PKT_SIZE + 28)) + { + pkts_rcvd_by_node[id]++; + // Uncomment this line for STOCHASTIC so that you can graph packets received vs time + std::cout << Simulator::Now ().GetSeconds () << " Node " << id << " receiving packet of " << p->GetSize () << " bytes." << std::endl; + } + + +} + + +// ****************************************************************** +// These functions are related to the Applications +// ****************************************************************** +static void SinkReceivedBytes (Ptr p, const Address & from) +{ + count_recv++; + //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; +} + +static void AppSendBytes (Ptr p) +{ + count_sent++; + //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; +} + + +// ****************************************************************** +// MAIN +// ****************************************************************** + +int +main (int argc, char *argv[]) +{ + NodeContainer::Iterator it; + NodeContainer::Iterator it2; + std::list destAddresses; // used by OLSR + + Ipv4Address sourceNodeAddr; + + // *********************************************************************** + // Initialize all value that are to be used in the scenario + // *********************************************************************** + double simtime = 65; + double dataRate = 1000000.0; + + bool collectPcap = false; + std::string errorModel = "CONSTANT"; + double errorRate = 0.0; + double errorUpAvg = 15000000.0; // 15 seconds up + double errorDownAvg = 5000000.0; // 5 second down + + // *********************************************************************** + // parse command line + // *********************************************************************** + CommandLine cmd; + cmd.AddValue ("pcap", "Set to 1 to collect pcap traces", collectPcap); + cmd.AddValue ("errorModel", "Error model to use. Must be one of: CONSTANT, CURVE, STOCHASTIC", errorModel); + cmd.AddValue ("errorRate", "Error rate if CONSTANT error model is used", errorRate); + cmd.AddValue ("errorUpAvg", "Average link up duration (microseconds) if STOCHASTIC error model is used", errorUpAvg); + cmd.AddValue ("errorDownAvg", "Average link down duration (microseconds) if STOCHASTIC error model is used", errorDownAvg); + cmd.Parse (argc,argv); + + if ((errorModel != "CONSTANT") && (errorModel != "CURVE") && (errorModel != "STOCHASTIC") ) + { + NS_ABORT_MSG ("Invalid errorModel type: Use --errorModel=CONSTANT or --errorModel=CURVE or --errorModel=STOCHASTIC"); + } + + std::cout << "Running scenario for " << simtime << " seconds using error type of " << errorModel << std::endl; + + // *********************************************************************** + // Create all the nodes + // *********************************************************************** + NodeContainer myNodes; + myNodes.Create (NUM_NODES); + NodeContainer const & n = NodeContainer::GetGlobal (); + + // Create container to hold devices + NetDeviceContainer devices; + + // *********************************************************************** + // Set up the physical/radio layer + // *********************************************************************** + // Set transmission range + Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); + + // Create error model and set as default for the device Receive side + // ALWAYS set the error rate to 0 here. The error is handled on the send side + // by the channel model in the simple wireless + Ptr em = CreateObject (); + em->SetAttribute ("ErrorRate", DoubleValue (0.0)); + em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); + Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue (em)); + + // create channel + Ptr phy = CreateObject (); + if ( errorModel.compare ("CURVE") == 0 ) + { + phy->setErrorModelType (PER_CURVE); + phy->addToPERmodel (0.0, 0.0); + phy->addToPERmodel (10.0, 0.0); + phy->addToPERmodel (20.0, 0.05); + phy->addToPERmodel (30.0, 0.07); + phy->addToPERmodel (40.0, 0.12); + phy->addToPERmodel (50.0, 0.15); + phy->addToPERmodel (60.0, 0.5); + phy->addToPERmodel (70.0, 0.6); + phy->addToPERmodel (80.0, 0.70); + phy->addToPERmodel (90.0, 0.80); + phy->addToPERmodel (100.0, 1.0); + } + else if ( errorModel.compare ("CONSTANT") == 0 ) + { + phy->setErrorModelType (CONSTANT); + phy->setErrorRate (errorRate); + } + else if ( errorModel.compare ("STOCHASTIC") == 0 ) + { + phy->setErrorModelType (STOCHASTIC); + phy->SetAttribute ("AvgLinkUpDuration", TimeValue (MicroSeconds (errorUpAvg))); + phy->SetAttribute ("AvgLinkDownDuration", TimeValue (MicroSeconds (errorDownAvg))); + } + + // create simple wireless device on each node + std::string fileStr; + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + + // create device + Ptr simpleWireless = CreateObject (); + simpleWireless->SetChannel (phy); + simpleWireless->SetNode (node); + simpleWireless->SetAddress (Mac48Address::Allocate ()); + simpleWireless->SetDataRate ((DataRate (dataRate))); + + // Set up trace to pass node id on the RX end + std::ostringstream oss; + oss << node->GetId (); + simpleWireless->TraceConnect ("MacRx", oss.str (), MakeCallback (&MacRxSuccess)); + + node->AddDevice (simpleWireless); + devices.Add (simpleWireless); + + // set up pcap capture + if (collectPcap) + { + std::ostringstream stringStream; + stringStream << "ErrorModelTest_node_" << node->GetId () << ".pcap"; + fileStr = stringStream.str (); + simpleWireless->EnablePcapAll (fileStr); + } + } + + // Must be done AFTER adding all the devices. Does nothing if not running STOCHASTIC error model + phy->InitStochasticModel (); + + + // set up call back for traces + Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/PhyTxBegin", MakeCallback (&TransmitStatsSW)); + + // *********************************************************************** + // Define positions. + ObjectFactory pos; + pos.SetTypeId ("ns3::UniformDiscPositionAllocator"); + pos.Set ("X", DoubleValue (0.0)); + pos.Set ("Y", DoubleValue (0.0)); + pos.Set ("rho", DoubleValue (100)); + Ptr positionAlloc = pos.Create ()->GetObject (); + + // *********************************************************************** + // Define and install random mobility. Here we are using the circle set up above + // as the position allocator for mobility (i.e., the area they can move in) + // *********************************************************************** + MobilityHelper mobility; + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (myNodes); + + // print starting positions + for (it = n.Begin (); it != n.End (); ++it) + { + // get node ptr, position and node id + Ptr node = *it; + Ptr mob = node->GetObject (); + int id = node->GetId (); + + // set up source node + if (id == 0) + { + // placed at the center and is the source node! + mob->SetPosition (Vector (0.0,0.0,0.0)); + } + Vector pos = mob->GetPosition (); + double distance = sqrt (pos.x * pos.x + pos.y * pos.y); + std::cout << "Node " << id << ". Position (" << pos.x << ", " << pos.y << ", " << pos.z << ") Distance to Node 0: " << distance << std::endl; + } + + + + // *********************************************************************** + // Set up routing OLSR + // *********************************************************************** + // don't have to use the Ipv4ListRoutingHelper but it prints + // the routing table in a better format than directly installing olsr. + InternetStackHelper stack; + OlsrHelper olsr; + Ipv4ListRoutingHelper list; + + // Add the routing to the route helper + list.Add (olsr, 10); + + // now set the routing and install on all nodes + stack.SetRoutingHelper (list); + stack.Install (myNodes); + + // set up IP addresses + Ipv4AddressHelper address; + address.SetBase ("10.0.0.0", "255.255.0.0"); + Ipv4InterfaceContainer interfaces = address.Assign (devices); + + // *********************************************************************** + // Set up application + // *********************************************************************** + // start the packet sink on all nodes except node 0 + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + uint32_t id = node->GetId (); + + if (id == 0) + { + // start the OnOff app on source to destinations (using broadcast) + OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); + onoff.SetAttribute ("PacketSize", StringValue (PktSize)); + onoff.SetAttribute ("DataRate", StringValue ("1000000")); + onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + + ApplicationContainer apps = onoff.Install (myNodes.Get (0)); + std::cout << "Node 0 installed app to send to 255.255.255.255" << std::endl; + apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); + + apps.Start (Seconds (5.0)); + apps.Stop (Seconds (simtime - 5.0)); + } + else + { + // on all other nodes start a packet sink + PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (id), 8080)); + ApplicationContainer apps_sink = sink.Install (myNodes.Get (id)); + apps_sink.Start (Seconds (0.0)); + //std::cout << "Node " << id << " installed sink to receive on " << interfaces.GetAddress (id) << std::endl; + pkts_rcvd_by_node[id] = 0; + } + } + + // set up the sink receive callback on all packet sinks + Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); + + // *********************************************************************** + // and finally ... off we go! + // *********************************************************************** + + Simulator::Stop (Seconds (simtime)); + Simulator::Run (); + Simulator::Destroy (); + + // *********************************************************************** + // For OLSR we need to get some stats + // *********************************************************************** + std::cout << "App Sent Count: " << count_sent << "\nApp Receive Count: " << count_recv << std::endl; + std::cout << "Control Sent Count: " << pkts_sent_cntl << "\nData Sent Count: " << pkts_sent_data << std::endl; + for (int i = 1; i < NUM_NODES; i++) + { + std::cout << "Packets received by Node " << i << ": " << pkts_rcvd_by_node[i] << std::endl; + } + + + NS_LOG_INFO ("Run Completed Successfully"); + + return 0; +} diff --git a/examples/fixed_contention_test.cc b/examples/fixed_contention_test.cc index 0a60ed9..6bf7b00 100644 --- a/examples/fixed_contention_test.cc +++ b/examples/fixed_contention_test.cc @@ -1,400 +1,401 @@ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * All rights reserved. - * - * 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 -*/ - -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ - -#include -#include -#include -#include -#include -#include "ns3/core-module.h" -#include "ns3/network-module.h" -#include "ns3/olsr-module.h" -#include "ns3/mobility-module.h" -#include "ns3/applications-module.h" -#include "ns3/internet-module.h" -#include "ns3/simple-wireless-module.h" - - -// This file is used to test the fixed contention option. -// When this feature is enabled, all nodes within a certain -// range (user specified, defaults to the tx range) act -// like contention and are used to reduce the datarate to -// data rate/ # neighbors -// -// The scenario has the following: -// - 20 nodes -// - node 0 is at the center of a circle -// - nodes 1-19 are randomly placed on a circle of radius 100 -// - random mobility within the circle -// - simple wireless model has: -// + constant error rate of 0 -// + tx range of 50 -// + No queue -// + fixed contention enabled -// + fixed contention range is defaulted to 50 but is user configurable -// - OLSR used for routing -// - On/Off application used for node 0 to send 1Mb/s to all 19 neighbor nodes - -// By changing the contention range, the effective data rate will decrease. - -using namespace ns3; - -NS_LOG_COMPONENT_DEFINE ("fixed_contention_test"); - -uint32_t app_count_sent = 0; -uint32_t app_count_recv = 0; -uint32_t pkts_sent_data = 0; -uint32_t pkts_rcvd_data = 0; -uint32_t pkts_sent_cntl = 0; - -// variables for queue latency: overall, data and control -double_t avg_queue_latency = 0.0; -uint32_t queue_pkt_count = 0; -double_t avg_queue_latency_data = 0.0; -uint32_t queue_pkt_count_data = 0; -double_t avg_queue_latency_cntl = 0.0; -uint32_t queue_pkt_count_cntl = 0; - -#define APP_PKT_SIZE 1000 -std::string PktSize = "1000"; - -#define NUM_NODES 101 // node 0 is source + N neighbors -uint32_t pkts_rcvd_by_node[NUM_NODES]; - -uint32_t nodePlacementRadius = 100; - -// ****************************************************************** -// This function supports OLSR when running on Simple Wireless -// ****************************************************************** -static void TransmitStatsSW (Ptr p, Mac48Address from, Mac48Address to , uint16_t protocol) -{ - // Figure out if this is OLSR or data - if (p->GetSize() == (APP_PKT_SIZE + 28)) - { - pkts_sent_data++; - } - else - { - pkts_sent_cntl++; - } -} - - -static void MacRxSuccess (std::string context, Ptr p) -{ - int id = atoi(context.c_str()); - if (p->GetSize() == (APP_PKT_SIZE + 28)) - { - pkts_rcvd_by_node[id]++; - pkts_rcvd_data++; - } -} - -// ****************************************************************** -// This function supports Simple Wireless -// ****************************************************************** -static void QueueLatencyStats (Ptr p, Time latency) -{ - double_t pkt_latency = double_t(latency.GetMicroSeconds())/1000000.0; - - queue_pkt_count++; - avg_queue_latency = avg_queue_latency * (queue_pkt_count-1)/queue_pkt_count + pkt_latency/queue_pkt_count; - - // add 28 bytes to ap size for UDP/IP header and also add 14 for ethernet header. - // Packet passed in this trace still has the Ethernet header - if (p->GetSize() == (APP_PKT_SIZE + 28 + 14)) - { - queue_pkt_count_data++; - avg_queue_latency_data = avg_queue_latency_data * (queue_pkt_count_data-1)/queue_pkt_count_data + pkt_latency/queue_pkt_count_data; - //std::cout << Simulator::Now ().GetSeconds () << " DATA Packet latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; - } - else - { - queue_pkt_count_cntl++; - avg_queue_latency_cntl = avg_queue_latency_cntl * (queue_pkt_count_cntl-1)/queue_pkt_count_cntl + pkt_latency/queue_pkt_count_cntl; - //std::cout << Simulator::Now ().GetSeconds () << " CONTROL Packet ("<< p->GetSize() << ") latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; - } - -} - - -// ****************************************************************** -// These functions support OLSR and are related to the Applications -// ****************************************************************** - -static void SinkReceivedBytes (Ptr p, const Address & from) -{ - app_count_recv++; - //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; -} - -static void AppSendBytes (Ptr p) -{ - app_count_sent++; - //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; -} - - -// ****************************************************************** -// MAIN -// ****************************************************************** - -int -main (int argc, char *argv[]) -{ - NodeContainer::Iterator it; - NodeContainer::Iterator it2; - std::list destAddresses; // used by OLSR - - Ipv4Address sourceNodeAddr; - - // *********************************************************************** - // Initialize all value that are to be used in the scenario - // *********************************************************************** - double simtime = 65; - bool collectPcap = false; - double dataRate = 10000000.0; - double contentionRange = 50.0; - - // *********************************************************************** - // parse command line - // *********************************************************************** - CommandLine cmd; - cmd.AddValue ("pcap", "Set to 1 to collect pcap traces", collectPcap); - cmd.AddValue ("contentionRange", "Distance to use for simple wireless contention range", contentionRange); - cmd.Parse (argc,argv); - - std::cout << "Running scenario for " << simtime << " seconds with contention range "<< contentionRange << std::endl; - - // *********************************************************************** - // Create all the nodes - // *********************************************************************** - NodeContainer myNodes; - myNodes.Create (NUM_NODES); - NodeContainer const & n = NodeContainer::GetGlobal (); - - // Create container to hold devices - NetDeviceContainer devices; - - // *********************************************************************** - // Set up the physical/radio layer - // *********************************************************************** - // Set transmission range - Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); - - // Create error model and set as default for the device Receive side - // ALWAYS set the error rate to 0 here. The error is handled on the send side - // by the channel model in the simple wireless - Ptr em = CreateObject (); - em->SetAttribute ("ErrorRate", DoubleValue (0.0)); - em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); - Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue(em)); - - // create channel - Ptr phy = CreateObject (); - phy->setErrorRate(0.0); - phy->setErrorModelType(CONSTANT); - phy->EnableFixedContention(); - phy->SetFixedContentionRange(contentionRange); - - // create simple wireless device on each node - std::string fileStr; - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - - // create device - Ptr simpleWireless = CreateObject (); - simpleWireless->SetChannel(phy); - simpleWireless->SetNode(node); - simpleWireless->SetAddress(Mac48Address::Allocate ()); - simpleWireless->SetDataRate((DataRate (dataRate))); - - Config::SetDefault ("ns3::DropHeadQueue::Mode", StringValue ("QUEUE_MODE_PACKETS")); - Config::SetDefault ("ns3::DropHeadQueue::MaxPackets", UintegerValue (100)); - Ptr queue = CreateObject (); - simpleWireless->SetQueue(queue); - - // Set up trace to pass node id on the RX end - std::ostringstream oss; - oss << node->GetId(); - simpleWireless->TraceConnect ("MacRx", oss.str(), MakeCallback (&MacRxSuccess)); - - node->AddDevice (simpleWireless); - devices.Add (simpleWireless); - - // set up pcap capture - if (collectPcap) - { - std::ostringstream stringStream; - stringStream << "CONTENTION_node_" << node->GetId() << ".pcap"; - fileStr = stringStream.str(); - simpleWireless->EnablePcapAll(fileStr); - } - } - - // set up call back for traces - Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/QueueLatency", MakeCallback (&QueueLatencyStats)); - Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/PhyTxBegin", MakeCallback (&TransmitStatsSW)); - Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); - - // *********************************************************************** - // Define positions. - ObjectFactory pos; - pos.SetTypeId ("ns3::UniformDiscPositionAllocator"); - pos.Set ("X", DoubleValue (0.0)); - pos.Set ("Y", DoubleValue (0.0)); - pos.Set ("rho", DoubleValue (nodePlacementRadius)); - Ptr positionAlloc = pos.Create ()->GetObject (); - - // *********************************************************************** - // Define and install random mobility. Here we are using the circle set up above - // as the position allocator for mobility (i.e., the area they can move in) - // *********************************************************************** - MobilityHelper mobility; - mobility.SetPositionAllocator (positionAlloc); - mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); - mobility.Install (myNodes); - - // print starting positions - for (it = n.Begin (); it != n.End (); ++it) - { - // get node ptr, position and node id - Ptr node = *it; - Ptr mob = node->GetObject (); - int id = node->GetId(); - - // set up source node - if (id == 0) - { - // placed at the center and is the source node! - mob->SetPosition (Vector (0.0,0.0,0.0)); - } - Vector pos = mob->GetPosition (); - double distance = sqrt(pos.x*pos.x + pos.y*pos.y); - std::cout << "Node " << id << ". Position (" << pos.x << ", " << pos.y << ", " << pos.z << ") Distance to Node 0: "<< distance << std::endl; - } - - - - // *********************************************************************** - // Set up routing OLSR - // *********************************************************************** - // don't have to use the Ipv4ListRoutingHelper but it prints - // the routing table in a better format than directly installing olsr. - InternetStackHelper stack; - OlsrHelper olsr; - Ipv4ListRoutingHelper list; - - // Add the routing to the route helper - list.Add (olsr, 10); - - // now set the routing and install on all nodes - stack.SetRoutingHelper (list); - stack.Install (myNodes); - - // set up IP addresses - Ipv4AddressHelper address; - address.SetBase ("10.0.0.0", "255.255.0.0"); - Ipv4InterfaceContainer interfaces = address.Assign (devices); - - // *********************************************************************** - // Set up application - // *********************************************************************** - // start the packet sink on all nodes except node 0 - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - uint32_t id = node->GetId(); - - if (id == 0) - { - // start the OnOff app on source to destinations (using broadcast) - OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); - onoff.SetAttribute ("PacketSize", StringValue (PktSize)); - onoff.SetAttribute ("DataRate", StringValue ("1000000")); - onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); - onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); - - ApplicationContainer apps = onoff.Install (myNodes.Get (0)); - std::cout << "Node 0 installed app to send to 255.255.255.255" << std::endl; - apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); - - apps.Start (Seconds (5.0)); - apps.Stop (Seconds (simtime - 5.0)); - } - else - { - // on all other nodes start a packet sink - PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (id), 8080)); - ApplicationContainer apps_sink = sink.Install (myNodes.Get (id)); - apps_sink.Start (Seconds (0.0)); - //std::cout << "Node " << id << " installed sink to receive on " << interfaces.GetAddress (id) << std::endl; - pkts_rcvd_by_node[id] = 0; - } - } - - // set up the sink receive callback on all packet sinks - Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); - - // *********************************************************************** - // and finally ... off we go! - // *********************************************************************** - - Simulator::Stop (Seconds(simtime)); - Simulator::Run (); - Simulator::Destroy (); - - // *********************************************************************** - // stats - // *********************************************************************** - double rcvPercentData = 0.0; - uint32_t dataDropped = app_count_sent*(NUM_NODES -1) - app_count_recv; - if (app_count_sent) - rcvPercentData = ((double)app_count_recv/((double)app_count_sent*(NUM_NODES -1)))*100.0; - - std::cout << "App Packets Sent: " << app_count_sent << "\nApp Packets Received: " << app_count_recv - << "\nControl Packets Sent: " << pkts_sent_cntl - << "\nData Packets Sent: " << pkts_sent_data - << "\nData Packets Received: " << pkts_rcvd_data - << "\nData Packets Dropped: " << dataDropped - << "\n% Data Received: " << std::fixed << std::setprecision(1) << rcvPercentData << std::noshowpoint << std::setprecision(0)< dev = devices.Get(0); - PointerValue val; - dev->GetAttribute("TxQueue", val); - Ptr queue = val.Get(); - Ptr dropHead = DynamicCast(queue); - std::cout << "Packets Dropped at Queue on Node 0: " << dropHead->GetTotalDroppedPackets() << std::endl; - - for (int i = 1; i < NUM_NODES; i++) - { - //std::cout << "Packets received by Node " << i << ": " << pkts_rcvd_by_node[i] << std::endl; - } - - - NS_LOG_INFO ("Run Completed Successfully"); - - return 0; -} +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * All rights reserved. + * + * 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 +*/ + +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +#include +#include +#include +#include +#include +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/olsr-module.h" +#include "ns3/mobility-module.h" +#include "ns3/applications-module.h" +#include "ns3/internet-module.h" +#include "ns3/simple-wireless-module.h" + + +// This file is used to test the fixed contention option. +// When this feature is enabled, all nodes within a certain +// range (user specified, defaults to the tx range) act +// like contention and are used to reduce the datarate to +// data rate/ # neighbors +// +// The scenario has the following: +// - 20 nodes +// - node 0 is at the center of a circle +// - nodes 1-19 are randomly placed on a circle of radius 100 +// - random mobility within the circle +// - simple wireless model has: +// + constant error rate of 0 +// + tx range of 50 +// + No queue +// + fixed contention enabled +// + fixed contention range is defaulted to 50 but is user configurable +// - OLSR used for routing +// - On/Off application used for node 0 to send 1Mb/s to all 19 neighbor nodes + +// By changing the contention range, the effective data rate will decrease. + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("fixed_contention_test"); + +uint32_t app_count_sent = 0; +uint32_t app_count_recv = 0; +uint32_t pkts_sent_data = 0; +uint32_t pkts_rcvd_data = 0; +uint32_t pkts_sent_cntl = 0; + +// variables for queue latency: overall, data and control +double_t avg_queue_latency = 0.0; +uint32_t queue_pkt_count = 0; +double_t avg_queue_latency_data = 0.0; +uint32_t queue_pkt_count_data = 0; +double_t avg_queue_latency_cntl = 0.0; +uint32_t queue_pkt_count_cntl = 0; + +#define APP_PKT_SIZE 1000 +std::string PktSize = "1000"; + +#define NUM_NODES 101 // node 0 is source + N neighbors +uint32_t pkts_rcvd_by_node[NUM_NODES]; + +uint32_t nodePlacementRadius = 100; + +// ****************************************************************** +// This function supports OLSR when running on Simple Wireless +// ****************************************************************** +static void TransmitStatsSW (Ptr p, Mac48Address from, Mac48Address to, uint16_t protocol) +{ + // Figure out if this is OLSR or data + if (p->GetSize () == (APP_PKT_SIZE + 28)) + { + pkts_sent_data++; + } + else + { + pkts_sent_cntl++; + } +} + + +static void MacRxSuccess (std::string context, Ptr p) +{ + int id = atoi (context.c_str ()); + if (p->GetSize () == (APP_PKT_SIZE + 28)) + { + pkts_rcvd_by_node[id]++; + pkts_rcvd_data++; + } +} + +// ****************************************************************** +// This function supports Simple Wireless +// ****************************************************************** +static void QueueLatencyStats (Ptr p, Time latency) +{ + double_t pkt_latency = double_t (latency.GetMicroSeconds ()) / 1000000.0; + + queue_pkt_count++; + avg_queue_latency = avg_queue_latency * (queue_pkt_count - 1) / queue_pkt_count + pkt_latency / queue_pkt_count; + + // add 28 bytes to ap size for UDP/IP header and also add 14 for ethernet header. + // Packet passed in this trace still has the Ethernet header + if (p->GetSize () == (APP_PKT_SIZE + 28 + 14)) + { + queue_pkt_count_data++; + avg_queue_latency_data = avg_queue_latency_data * (queue_pkt_count_data - 1) / queue_pkt_count_data + pkt_latency / queue_pkt_count_data; + //std::cout << Simulator::Now ().GetSeconds () << " DATA Packet latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; + } + else + { + queue_pkt_count_cntl++; + avg_queue_latency_cntl = avg_queue_latency_cntl * (queue_pkt_count_cntl - 1) / queue_pkt_count_cntl + pkt_latency / queue_pkt_count_cntl; + //std::cout << Simulator::Now ().GetSeconds () << " CONTROL Packet ("<< p->GetSize() << ") latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; + } + +} + + +// ****************************************************************** +// These functions support OLSR and are related to the Applications +// ****************************************************************** + +static void SinkReceivedBytes (Ptr p, const Address & from) +{ + app_count_recv++; + //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; +} + +static void AppSendBytes (Ptr p) +{ + app_count_sent++; + //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; +} + + +// ****************************************************************** +// MAIN +// ****************************************************************** + +int +main (int argc, char *argv[]) +{ + NodeContainer::Iterator it; + NodeContainer::Iterator it2; + std::list destAddresses; // used by OLSR + + Ipv4Address sourceNodeAddr; + + // *********************************************************************** + // Initialize all value that are to be used in the scenario + // *********************************************************************** + double simtime = 65; + bool collectPcap = false; + double dataRate = 10000000.0; + double contentionRange = 50.0; + + // *********************************************************************** + // parse command line + // *********************************************************************** + CommandLine cmd; + cmd.AddValue ("pcap", "Set to 1 to collect pcap traces", collectPcap); + cmd.AddValue ("contentionRange", "Distance to use for simple wireless contention range", contentionRange); + cmd.Parse (argc,argv); + + std::cout << "Running scenario for " << simtime << " seconds with contention range " << contentionRange << std::endl; + + // *********************************************************************** + // Create all the nodes + // *********************************************************************** + NodeContainer myNodes; + myNodes.Create (NUM_NODES); + NodeContainer const & n = NodeContainer::GetGlobal (); + + // Create container to hold devices + NetDeviceContainer devices; + + // *********************************************************************** + // Set up the physical/radio layer + // *********************************************************************** + // Set transmission range + Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); + + // Create error model and set as default for the device Receive side + // ALWAYS set the error rate to 0 here. The error is handled on the send side + // by the channel model in the simple wireless + Ptr em = CreateObject (); + em->SetAttribute ("ErrorRate", DoubleValue (0.0)); + em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); + Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue (em)); + + // create channel + Ptr phy = CreateObject (); + phy->setErrorRate (0.0); + phy->setErrorModelType (CONSTANT); + phy->EnableFixedContention (); + phy->SetFixedContentionRange (contentionRange); + + // create simple wireless device on each node + std::string fileStr; + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + + // create device + Ptr simpleWireless = CreateObject (); + simpleWireless->SetChannel (phy); + simpleWireless->SetNode (node); + simpleWireless->SetAddress (Mac48Address::Allocate ()); + simpleWireless->SetDataRate ((DataRate (dataRate))); + + Ptr> queue = CreateObject> (); + queue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + simpleWireless->SetQueue (queue); + + // Set up trace to pass node id on the RX end + std::ostringstream oss; + oss << node->GetId (); + simpleWireless->TraceConnect ("MacRx", oss.str (), MakeCallback (&MacRxSuccess)); + + node->AddDevice (simpleWireless); + devices.Add (simpleWireless); + + // set up pcap capture + if (collectPcap) + { + std::ostringstream stringStream; + stringStream << "CONTENTION_node_" << node->GetId () << ".pcap"; + fileStr = stringStream.str (); + simpleWireless->EnablePcapAll (fileStr); + } + } + + // set up call back for traces + Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/QueueLatency", MakeCallback (&QueueLatencyStats)); + Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/PhyTxBegin", MakeCallback (&TransmitStatsSW)); + Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); + + // *********************************************************************** + // Define positions. + ObjectFactory pos; + pos.SetTypeId ("ns3::UniformDiscPositionAllocator"); + pos.Set ("X", DoubleValue (0.0)); + pos.Set ("Y", DoubleValue (0.0)); + pos.Set ("rho", DoubleValue (nodePlacementRadius)); + Ptr positionAlloc = pos.Create ()->GetObject (); + + // *********************************************************************** + // Define and install random mobility. Here we are using the circle set up above + // as the position allocator for mobility (i.e., the area they can move in) + // *********************************************************************** + MobilityHelper mobility; + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (myNodes); + + // print starting positions + for (it = n.Begin (); it != n.End (); ++it) + { + // get node ptr, position and node id + Ptr node = *it; + Ptr mob = node->GetObject (); + int id = node->GetId (); + + // set up source node + if (id == 0) + { + // placed at the center and is the source node! + mob->SetPosition (Vector (0.0,0.0,0.0)); + } + Vector pos = mob->GetPosition (); + double distance = sqrt (pos.x * pos.x + pos.y * pos.y); + std::cout << "Node " << id << ". Position (" << pos.x << ", " << pos.y << ", " << pos.z << ") Distance to Node 0: " << distance << std::endl; + } + + + + // *********************************************************************** + // Set up routing OLSR + // *********************************************************************** + // don't have to use the Ipv4ListRoutingHelper but it prints + // the routing table in a better format than directly installing olsr. + InternetStackHelper stack; + OlsrHelper olsr; + Ipv4ListRoutingHelper list; + + // Add the routing to the route helper + list.Add (olsr, 10); + + // now set the routing and install on all nodes + stack.SetRoutingHelper (list); + stack.Install (myNodes); + + // set up IP addresses + Ipv4AddressHelper address; + address.SetBase ("10.0.0.0", "255.255.0.0"); + Ipv4InterfaceContainer interfaces = address.Assign (devices); + + // *********************************************************************** + // Set up application + // *********************************************************************** + // start the packet sink on all nodes except node 0 + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + uint32_t id = node->GetId (); + + if (id == 0) + { + // start the OnOff app on source to destinations (using broadcast) + OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); + onoff.SetAttribute ("PacketSize", StringValue (PktSize)); + onoff.SetAttribute ("DataRate", StringValue ("1000000")); + onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + + ApplicationContainer apps = onoff.Install (myNodes.Get (0)); + std::cout << "Node 0 installed app to send to 255.255.255.255" << std::endl; + apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); + + apps.Start (Seconds (5.0)); + apps.Stop (Seconds (simtime - 5.0)); + } + else + { + // on all other nodes start a packet sink + PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (id), 8080)); + ApplicationContainer apps_sink = sink.Install (myNodes.Get (id)); + apps_sink.Start (Seconds (0.0)); + //std::cout << "Node " << id << " installed sink to receive on " << interfaces.GetAddress (id) << std::endl; + pkts_rcvd_by_node[id] = 0; + } + } + + // set up the sink receive callback on all packet sinks + Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); + + // *********************************************************************** + // and finally ... off we go! + // *********************************************************************** + + Simulator::Stop (Seconds (simtime)); + Simulator::Run (); + Simulator::Destroy (); + + // *********************************************************************** + // stats + // *********************************************************************** + double rcvPercentData = 0.0; + uint32_t dataDropped = app_count_sent * (NUM_NODES - 1) - app_count_recv; + if (app_count_sent) + { + rcvPercentData = ((double)app_count_recv / ((double)app_count_sent * (NUM_NODES - 1))) * 100.0; + } + + std::cout << "App Packets Sent: " << app_count_sent << "\nApp Packets Received: " << app_count_recv + << "\nControl Packets Sent: " << pkts_sent_cntl + << "\nData Packets Sent: " << pkts_sent_data + << "\nData Packets Received: " << pkts_rcvd_data + << "\nData Packets Dropped: " << dataDropped + << "\n% Data Received: " << std::fixed << std::setprecision (1) << rcvPercentData << std::noshowpoint << std::setprecision (0) << std::endl; + std::cout << "Average Queue Latency Data: " << std::fixed << std::setprecision (6) << avg_queue_latency_data + << "\nAverage Queue Latency Control: " << std::fixed << std::setprecision (6) << avg_queue_latency_cntl << std::noshowpoint << std::setprecision (0) << std::endl; + std::cout << "Overall Average Queue Latency: " << std::fixed << std::setprecision (6) << avg_queue_latency << std::noshowpoint << std::setprecision (0) << std::endl; + + // get queue packets dropped + Ptr dev = devices.Get (0); + PointerValue val; + dev->GetAttribute ("TxQueue", val); + Ptr> queue = val.Get>(); + Ptr> dropHead = DynamicCast> (queue); + std::cout << "Packets Dropped at Queue on Node 0: " << dropHead->GetTotalDroppedPackets () << std::endl; + + for (int i = 1; i < NUM_NODES; i++) + { + //std::cout << "Packets received by Node " << i << ": " << pkts_rcvd_by_node[i] << std::endl; + } + + + NS_LOG_INFO ("Run Completed Successfully"); + + return 0; +} diff --git a/examples/mixed_directional_network.cc b/examples/mixed_directional_network.cc index 1e8d96d..9689c0e 100644 --- a/examples/mixed_directional_network.cc +++ b/examples/mixed_directional_network.cc @@ -1,321 +1,319 @@ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * All rights reserved. - * - * 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 -*/ - -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ - -// This uses global routing -// -// Network topology -// -// 1 -// || -// || -// 7--- || ---5 -// |---4======0======2-| -// 8--- || ---6 -// || -// || -// 3 - -// Node 0 is placed at the origin (0,0) -// Nodes 1, 2, 3, 4 are 50m away from Node 0 -// Nodes 5, 6 are placed 10m away from Node 2 -// Nodes 7, 8 are placed 10m away from Node 4 - - -// two wireless networks: -// - one network has all nodes and has a range of 40m -// - second network has node 0, 1, 2, 3, 4 and has a range of 100m -// + node 0 uses a directional network with node 1 and 4 as neighbors -// + node 2 uses a directional network but has no neighbors -// Note that nodes 0, 1, 2, 3, 4 each have two interfaces - -// Traffic: -// - Node 0 sends broadcast traffic. Received at nodes 1 & 4 -// - Node 2 sends broadcast traffic. Received at nodes 5 & 6 - - -#include -#include -#include -#include -#include - -#include "ns3/core-module.h" -#include "ns3/network-module.h" -#include "ns3/mobility-module.h" -#include "ns3/applications-module.h" -#include "ns3/internet-module.h" -#include "ns3/simple-wireless-module.h" - -using namespace ns3; - -NS_LOG_COMPONENT_DEFINE ("MixedDirectionalNetworkExample"); - -uint32_t count_sent = 0; -uint32_t count_recv = 0; - - -// ****************************************************************** -// These functions support the Applications -// ****************************************************************** -static void SinkReceivedBytes (Ptr p, const Address & from) -{ - count_recv++; - //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; -} - -static void AppSendBytes (Ptr p) -{ - count_sent++; - //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; -} - -int -main (int argc, char *argv[]) -{ - NodeContainer::Iterator it; - double simtime = 60; - double dataRate = 10000000.0; - - NodeContainer n; - n.Create (9); - // create node container for the second network - NodeContainer n01234 = NodeContainer (n.Get (0), n.Get (1), n.Get (2), n.Get (3), n.Get (4)); - - InternetStackHelper internet; - internet.Install (n); - - - // Create container to hold devices - NetDeviceContainer dAll; - NetDeviceContainer d2; - - // *********************************************************************** - // Set up the physical/radio layer - // *********************************************************************** - // Create error model and set as default - Ptr em = CreateObject (); - em->SetAttribute ("ErrorRate", DoubleValue (0.0)); - em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); - Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue(em)); - - // *********************************************************************** - // create first network - Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (40.0)); - Ptr phy1 = CreateObject (); - phy1->setErrorRate(0.0); - phy1->setErrorModelType(CONSTANT); - - // create simple wireless device on each node - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - - // create device - Ptr simpleWireless1 = CreateObject (); - simpleWireless1->SetChannel(phy1); - simpleWireless1->SetNode(node); - simpleWireless1->SetAddress(Mac48Address::Allocate ()); - simpleWireless1->SetDataRate((DataRate (dataRate))); - - // Set queue type to use - Config::SetDefault ("ns3::DropHeadQueue::Mode", StringValue ("QUEUE_MODE_PACKETS")); - Config::SetDefault ("ns3::DropHeadQueue::MaxPackets", UintegerValue (100)); - Ptr queue = CreateObject (); - simpleWireless1->SetQueue(queue); - - node->AddDevice (simpleWireless1); - dAll.Add (simpleWireless1); - } - - // *********************************************************************** - // create second network - Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); - Ptr phy2 = CreateObject (); - phy2->setErrorRate(0.0); - phy2->setErrorModelType(CONSTANT); - - // create simple wireless device on each node - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - uint32_t id = node->GetId(); - - // network 2 is only on node 0, 1, 2, 3, 4 - if (id < 5) - { - // create device - Ptr simpleWireless2 = CreateObject (); - simpleWireless2->SetChannel(phy2); - simpleWireless2->SetNode(node); - simpleWireless2->SetAddress(Mac48Address::Allocate ()); - simpleWireless2->SetDataRate((DataRate (dataRate))); - - std::cout << "node id " << id << " has macAddress of " << simpleWireless2->GetAddress() << std::endl; - - // Set queue type to use - Config::SetDefault ("ns3::DropHeadQueue::Mode", StringValue ("QUEUE_MODE_PACKETS")); - Config::SetDefault ("ns3::DropHeadQueue::MaxPackets", UintegerValue (100)); - Ptr queue = CreateObject (); - simpleWireless2->SetQueue(queue); - - node->AddDevice (simpleWireless2); - d2.Add (simpleWireless2); - } - } - - // ------------------------------------------------------------------------ - // Set up directional network. Do this after adding all the devices because - // we need to get MAC addresses for the neighbors we want to add - // network 2 is only on node 0, 1, 2, 3, 4 - // node 0 has directional neighbors to nodes 1, 4 - // node 2 has directional networking but no neighbors - - // Get node 0, 1, 2, 4 device on the container. MUST use d2 container - // since that is the container with the SW interfaces that use directional - // network. - // In this example we get the ptr to the NetDevice using the index in the - // containter. We added them in numerical order so we know that 0 is node0, - // 1 is node 1, etc. - Ptr dev0 = d2.Get(0); - Ptr dev1 = d2.Get(1); - Ptr dev2 = d2.Get(2); - Ptr dev4 = d2.Get(4); - Ptr swDev0 = DynamicCast(dev0); - Ptr swDev1 = DynamicCast(dev1); - Ptr swDev2 = DynamicCast(dev2); - Ptr swDev4 = DynamicCast(dev4); - - // node 0 has directional neighbors to nodes 1, 4 - swDev0->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); - // Here we use the function that takes map to add multiple neighbors one call - std::map nbrSet; - // Get mac addr of node 1 and add to map - Address addr = swDev1->GetAddress(); - Mac48Address macAddr = Mac48Address::ConvertFrom (addr); - nbrSet.insert(std::pair(1, macAddr)); - std::cout << "Adding node 1 with mac address " << macAddr<< std::endl; - // Get mac addr of node 4 and add to map - addr = swDev4->GetAddress(); - macAddr = Mac48Address::ConvertFrom (addr); - nbrSet.insert(std::pair(4, macAddr)); - std::cout << "Adding node 4 with mac address " << macAddr<< std::endl; - // Now add to dev on node 0 - swDev0->AddDirectionalNeighbors(nbrSet); - - // Now just set the fixed neigbor feature enabled on dev 2 but don't - // add any neighbors because it has none - swDev2->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); - // ------------------------------------------------------------------------ - - - // Later, we add IP addresses. - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.0"); - Ipv4InterfaceContainer interfaces = ipv4.Assign (dAll); - - ipv4.SetBase ("10.1.2.0", "255.255.255.0"); - ipv4.Assign (d2); - - // Create router nodes, initialize routing database and set up the routing - // tables in the nodes. - Ipv4GlobalRoutingHelper::PopulateRoutingTables (); - - // *********************************************************************** - // Define positions. - MobilityHelper mobility; - Ptr positionAlloc = CreateObject (); - positionAlloc->Add (Vector ( 0.0, 0.0, 0.0)); - positionAlloc->Add (Vector ( 0.0, 50.0, 0.0)); - positionAlloc->Add (Vector (50.0, 0.0, 0.0)); - positionAlloc->Add (Vector ( 0.0, -50.0, 0.0)); - positionAlloc->Add (Vector (-50.0, 0.0, 0.0)); - positionAlloc->Add (Vector (60.0, -2.0, 0.0)); - positionAlloc->Add (Vector (60.0, 2.0, 0.0)); - positionAlloc->Add (Vector (-60.0, 2.0, 0.0)); - positionAlloc->Add (Vector (-60.0, -2.0, 0.0)); - mobility.SetPositionAllocator (positionAlloc); - mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); - mobility.Install (n); - - - // *********************************************************************** - // Set up application - // *********************************************************************** - // start the packet sink on all nodes except node 0 - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - uint32_t id = node->GetId(); - - if (id == 0) - { - // start the OnOff app on source to destinations (using broadcast) - OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); - onoff.SetAttribute ("PacketSize", StringValue ("1000")); - onoff.SetAttribute ("DataRate", StringValue ("100000")); - onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); - onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); - - ApplicationContainer apps = onoff.Install (n.Get (0)); - apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); - - apps.Start (Seconds (5.0)); - apps.Stop (Seconds (simtime - 1.0)); - } - else if (id == 2) - { - // start the OnOff app on source to destinations (using broadcast) - OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); - onoff.SetAttribute ("PacketSize", StringValue ("1000")); - onoff.SetAttribute ("DataRate", StringValue ("100000")); - onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); - onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); - - ApplicationContainer apps = onoff.Install (n.Get (2)); - apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); - - apps.Start (Seconds (5.0)); - apps.Stop (Seconds (simtime - 1.0)); - } - - // on nodes start a packet sink - PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), 8080)); - ApplicationContainer apps_sink = sink.Install (n.Get (id)); - apps_sink.Start (Seconds (0.0)); - std::cout << "Node " << id << " installed sink " << std::endl; - - } - - // set up the sink receive callback on all packet sinks - Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); - - // *********************************************************************** - // and finally ... off we go! - // *********************************************************************** - - Simulator::Stop (Seconds(simtime)); - Simulator::Run (); - Simulator::Destroy (); - - std::cout << "Sent: " << count_sent << "\nReceive Count: " << count_recv << std::endl; - - - NS_LOG_INFO ("Run Completed Successfully"); -} +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * All rights reserved. + * + * 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 +*/ + +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +// This uses global routing +// +// Network topology +// +// 1 +// || +// || +// 7--- || ---5 +// |---4======0======2-| +// 8--- || ---6 +// || +// || +// 3 + +// Node 0 is placed at the origin (0,0) +// Nodes 1, 2, 3, 4 are 50m away from Node 0 +// Nodes 5, 6 are placed 10m away from Node 2 +// Nodes 7, 8 are placed 10m away from Node 4 + + +// two wireless networks: +// - one network has all nodes and has a range of 40m +// - second network has node 0, 1, 2, 3, 4 and has a range of 100m +// + node 0 uses a directional network with node 1 and 4 as neighbors +// + node 2 uses a directional network but has no neighbors +// Note that nodes 0, 1, 2, 3, 4 each have two interfaces + +// Traffic: +// - Node 0 sends broadcast traffic. Received at nodes 1 & 4 +// - Node 2 sends broadcast traffic. Received at nodes 5 & 6 + + +#include +#include +#include +#include +#include + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/mobility-module.h" +#include "ns3/applications-module.h" +#include "ns3/internet-module.h" +#include "ns3/simple-wireless-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("MixedDirectionalNetworkExample"); + +uint32_t count_sent = 0; +uint32_t count_recv = 0; + + +// ****************************************************************** +// These functions support the Applications +// ****************************************************************** +static void SinkReceivedBytes (Ptr p, const Address & from) +{ + count_recv++; + //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; +} + +static void AppSendBytes (Ptr p) +{ + count_sent++; + //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; +} + +int +main (int argc, char *argv[]) +{ + NodeContainer::Iterator it; + double simtime = 60; + double dataRate = 10000000.0; + + NodeContainer n; + n.Create (9); + // create node container for the second network + NodeContainer n01234 = NodeContainer (n.Get (0), n.Get (1), n.Get (2), n.Get (3), n.Get (4)); + + InternetStackHelper internet; + internet.Install (n); + + + // Create container to hold devices + NetDeviceContainer dAll; + NetDeviceContainer d2; + + // *********************************************************************** + // Set up the physical/radio layer + // *********************************************************************** + // Create error model and set as default + Ptr em = CreateObject (); + em->SetAttribute ("ErrorRate", DoubleValue (0.0)); + em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); + Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue (em)); + + // *********************************************************************** + // create first network + Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (40.0)); + Ptr phy1 = CreateObject (); + phy1->setErrorRate (0.0); + phy1->setErrorModelType (CONSTANT); + + // create simple wireless device on each node + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + + // create device + Ptr simpleWireless1 = CreateObject (); + simpleWireless1->SetChannel (phy1); + simpleWireless1->SetNode (node); + simpleWireless1->SetAddress (Mac48Address::Allocate ()); + simpleWireless1->SetDataRate ((DataRate (dataRate))); + + // Set queue type to use + Ptr> queue = CreateObject> (); + queue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + simpleWireless1->SetQueue (queue); + + node->AddDevice (simpleWireless1); + dAll.Add (simpleWireless1); + } + + // *********************************************************************** + // create second network + Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); + Ptr phy2 = CreateObject (); + phy2->setErrorRate (0.0); + phy2->setErrorModelType (CONSTANT); + + // create simple wireless device on each node + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + uint32_t id = node->GetId (); + + // network 2 is only on node 0, 1, 2, 3, 4 + if (id < 5) + { + // create device + Ptr simpleWireless2 = CreateObject (); + simpleWireless2->SetChannel (phy2); + simpleWireless2->SetNode (node); + simpleWireless2->SetAddress (Mac48Address::Allocate ()); + simpleWireless2->SetDataRate ((DataRate (dataRate))); + + std::cout << "node id " << id << " has macAddress of " << simpleWireless2->GetAddress () << std::endl; + + // Set queue type to use + Ptr> queue = CreateObject> (); + queue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + simpleWireless2->SetQueue (queue); + + node->AddDevice (simpleWireless2); + d2.Add (simpleWireless2); + } + } + + // ------------------------------------------------------------------------ + // Set up directional network. Do this after adding all the devices because + // we need to get MAC addresses for the neighbors we want to add + // network 2 is only on node 0, 1, 2, 3, 4 + // node 0 has directional neighbors to nodes 1, 4 + // node 2 has directional networking but no neighbors + + // Get node 0, 1, 2, 4 device on the container. MUST use d2 container + // since that is the container with the SW interfaces that use directional + // network. + // In this example we get the ptr to the NetDevice using the index in the + // containter. We added them in numerical order so we know that 0 is node0, + // 1 is node 1, etc. + Ptr dev0 = d2.Get (0); + Ptr dev1 = d2.Get (1); + Ptr dev2 = d2.Get (2); + Ptr dev4 = d2.Get (4); + Ptr swDev0 = DynamicCast (dev0); + Ptr swDev1 = DynamicCast (dev1); + Ptr swDev2 = DynamicCast (dev2); + Ptr swDev4 = DynamicCast (dev4); + + // node 0 has directional neighbors to nodes 1, 4 + swDev0->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); + // Here we use the function that takes map to add multiple neighbors one call + std::map nbrSet; + // Get mac addr of node 1 and add to map + Address addr = swDev1->GetAddress (); + Mac48Address macAddr = Mac48Address::ConvertFrom (addr); + nbrSet.insert (std::pair (1, macAddr)); + std::cout << "Adding node 1 with mac address " << macAddr << std::endl; + // Get mac addr of node 4 and add to map + addr = swDev4->GetAddress (); + macAddr = Mac48Address::ConvertFrom (addr); + nbrSet.insert (std::pair (4, macAddr)); + std::cout << "Adding node 4 with mac address " << macAddr << std::endl; + // Now add to dev on node 0 + swDev0->AddDirectionalNeighbors (nbrSet); + + // Now just set the fixed neigbor feature enabled on dev 2 but don't + // add any neighbors because it has none + swDev2->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); + // ------------------------------------------------------------------------ + + + // Later, we add IP addresses. + Ipv4AddressHelper ipv4; + ipv4.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer interfaces = ipv4.Assign (dAll); + + ipv4.SetBase ("10.1.2.0", "255.255.255.0"); + ipv4.Assign (d2); + + // Create router nodes, initialize routing database and set up the routing + // tables in the nodes. + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + + // *********************************************************************** + // Define positions. + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector ( 0.0, 0.0, 0.0)); + positionAlloc->Add (Vector ( 0.0, 50.0, 0.0)); + positionAlloc->Add (Vector (50.0, 0.0, 0.0)); + positionAlloc->Add (Vector ( 0.0, -50.0, 0.0)); + positionAlloc->Add (Vector (-50.0, 0.0, 0.0)); + positionAlloc->Add (Vector (60.0, -2.0, 0.0)); + positionAlloc->Add (Vector (60.0, 2.0, 0.0)); + positionAlloc->Add (Vector (-60.0, 2.0, 0.0)); + positionAlloc->Add (Vector (-60.0, -2.0, 0.0)); + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (n); + + + // *********************************************************************** + // Set up application + // *********************************************************************** + // start the packet sink on all nodes except node 0 + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + uint32_t id = node->GetId (); + + if (id == 0) + { + // start the OnOff app on source to destinations (using broadcast) + OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); + onoff.SetAttribute ("PacketSize", StringValue ("1000")); + onoff.SetAttribute ("DataRate", StringValue ("100000")); + onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + + ApplicationContainer apps = onoff.Install (n.Get (0)); + apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); + + apps.Start (Seconds (5.0)); + apps.Stop (Seconds (simtime - 1.0)); + } + else if (id == 2) + { + // start the OnOff app on source to destinations (using broadcast) + OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("255.255.255.255"), 8080)); + onoff.SetAttribute ("PacketSize", StringValue ("1000")); + onoff.SetAttribute ("DataRate", StringValue ("100000")); + onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + + ApplicationContainer apps = onoff.Install (n.Get (2)); + apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); + + apps.Start (Seconds (5.0)); + apps.Stop (Seconds (simtime - 1.0)); + } + + // on nodes start a packet sink + PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), 8080)); + ApplicationContainer apps_sink = sink.Install (n.Get (id)); + apps_sink.Start (Seconds (0.0)); + std::cout << "Node " << id << " installed sink " << std::endl; + + } + + // set up the sink receive callback on all packet sinks + Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); + + // *********************************************************************** + // and finally ... off we go! + // *********************************************************************** + + Simulator::Stop (Seconds (simtime)); + Simulator::Run (); + Simulator::Destroy (); + + std::cout << "Sent: " << count_sent << "\nReceive Count: " << count_recv << std::endl; + + + NS_LOG_INFO ("Run Completed Successfully"); +} diff --git a/examples/multiple_interface_example.cc b/examples/multiple_interface_example.cc index 67cbb53..409621e 100644 --- a/examples/multiple_interface_example.cc +++ b/examples/multiple_interface_example.cc @@ -1,290 +1,298 @@ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * All rights reserved. - * - * 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 -*/ - -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ - -// Network topology -// -// 0 ------------ 1 --- simple wireless network -// ++++++++++++ +++ directional simple wireless network -// -// This network has 2 nodes and 2 interfaces per node. -// Both interfaces are simple wireless -// One interface on each node is directional -// -// Node 0 sends traffic over both interfaces. part way into the simulation, -// node 0 loses its directional neighbor and the traffic over that link stops -// being received. - - - - -#include -#include -#include -#include -#include - -#include "ns3/core-module.h" -#include "ns3/network-module.h" -#include "ns3/mobility-module.h" -#include "ns3/applications-module.h" -#include "ns3/internet-module.h" -#include "ns3/simple-wireless-module.h" - -using namespace ns3; - -NS_LOG_COMPONENT_DEFINE ("MixedDirectionalNetworkExample"); - -uint32_t count_sent_app1 = 0; -uint32_t count_recv_app1 = 0; -uint32_t count_sent_app2 = 0; -uint32_t count_recv_app2 = 0; - - -// ****************************************************************** -// These functions support the Applications -// ****************************************************************** -static void SinkReceivedBytes (Ptr p, const Address & from) -{ - if (p->GetSize() > 500) - count_recv_app1++; - else - count_recv_app2++; - - - std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes."<< std::endl; -} - -static void AppSendBytes (Ptr p) -{ - if (p->GetSize() > 500) - count_sent_app1++; - else - count_sent_app2++; - - std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. "<< std::endl; -} - - -static void removeDirectionalNbr (Ptr sw) -{ - // remove directional neigbhor 1 - sw->DeleteDirectionalNeighbor(1); -} - -int -main (int argc, char *argv[]) -{ - NodeContainer::Iterator it; - double simtime = 126; - double dataRate = 10000000.0; //10Mb/s - - // create node container for the omni network - NodeContainer n1; - n1.Create (2); - // create node container for the directional network - NodeContainer n2_dir = NodeContainer (n1.Get (0), n1.Get (1)); - - - InternetStackHelper internet; - internet.Install (n1); - - - // Create container to hold devices - NetDeviceContainer d1_omni; - NetDeviceContainer d2_dir; - - // *********************************************************************** - // Set up the physical/radio layer - // *********************************************************************** - // Create error model and set as default - Ptr em = CreateObject (); - em->SetAttribute ("ErrorRate", DoubleValue (0.0)); - em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); - Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue(em)); - - // *********************************************************************** - // create first network - Config::SetDefault ("ns3::DropHeadQueue::Mode", StringValue ("QUEUE_MODE_PACKETS")); - Config::SetDefault ("ns3::DropHeadQueue::MaxPackets", UintegerValue (100)); - Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); - - // channel - Ptr phy1 = CreateObject (); - phy1->setErrorRate(0.0); - phy1->setErrorModelType(CONSTANT); - - // create simple wireless device on each node - for (it = n1.Begin (); it != n1.End (); ++it) - { - Ptr node = *it; - - // create device - Ptr simpleWireless1 = CreateObject (); - simpleWireless1->SetChannel(phy1); - simpleWireless1->SetNode(node); - simpleWireless1->SetAddress(Mac48Address::Allocate ()); - simpleWireless1->SetDataRate((DataRate (dataRate))); - - // create queue type - Ptr queue = CreateObject (); - simpleWireless1->SetQueue(queue); - - node->AddDevice (simpleWireless1); - d1_omni.Add (simpleWireless1); - } - - // *********************************************************************** - // create second network - Ptr phy2 = CreateObject (); - phy2->setErrorRate(0.0); - phy2->setErrorModelType(CONSTANT); - - // create simple wireless device on each node - for (it = n2_dir.Begin (); it != n2_dir.End (); ++it) - { - Ptr node = *it; - uint32_t id = node->GetId(); - - // create device - Ptr simpleWireless2 = CreateObject (); - simpleWireless2->SetChannel(phy2); - simpleWireless2->SetNode(node); - simpleWireless2->SetAddress(Mac48Address::Allocate ()); - simpleWireless2->SetDataRate((DataRate (dataRate))); - std::cout << "node id " << id << " has macAddress of " << simpleWireless2->GetAddress() << std::endl; - - // create queue type - Ptr queue = CreateObject (); - simpleWireless2->SetQueue(queue); - - if (id == 0) - { - // schedule function which removed node 0's directional neighbor - Simulator::Schedule (Seconds (60.0), &removeDirectionalNbr, simpleWireless2); - } - - node->AddDevice (simpleWireless2); - d2_dir.Add (simpleWireless2); - } - - - // *********************************************************************** - // Set up directional network. Do this after adding all the devices because - // we need to get MAC addresses for the neighbors we want to add - - // Get node 0, 1 device on the container. MUST use d2_dir container - // since that is the container with the SW interfaces that use directional - // network. - // In this example we get the ptr to the NetDevice using the index in the - // containter. We added them in numerical order so we know that 0 is node0, - // 1 is node 1, etc. - Ptr dev0 = d2_dir.Get(0); - Ptr dev1 = d2_dir.Get(1); - Ptr swDev0 = DynamicCast(dev0); - Ptr swDev1 = DynamicCast(dev1); - - // node 0 has directional neighbors to node 1 - swDev0->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); - // Here we use the function that takes a single node to add - Address addr = swDev1->GetAddress(); - Mac48Address macAddr = Mac48Address::ConvertFrom (addr); - swDev0->AddDirectionalNeighbor(1,macAddr); - - // node 1 has directional neighbors to node 0 - swDev1->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); - addr = swDev0->GetAddress(); - macAddr = Mac48Address::ConvertFrom (addr); - swDev1->AddDirectionalNeighbor(0,macAddr); - - - // *********************************************************************** - // add IP addresses. - Ipv4AddressHelper ipv4; - ipv4.SetBase ("10.1.1.0", "255.255.255.0"); - Ipv4InterfaceContainer interfaces = ipv4.Assign (d1_omni); - - ipv4.SetBase ("10.1.2.0", "255.255.255.0"); - ipv4.Assign (d2_dir); - - // Create router nodes, initialize routing database and set up the routing - // tables in the nodes. - Ipv4GlobalRoutingHelper::PopulateRoutingTables (); - - // *********************************************************************** - // Define positions. - MobilityHelper mobility; - Ptr positionAlloc = CreateObject (); - positionAlloc->Add (Vector ( 0.0, 0.0, 0.0)); - positionAlloc->Add (Vector ( 0.0, 50.0, 0.0)); - mobility.SetPositionAllocator (positionAlloc); - mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); - mobility.Install (n1); - - - // *********************************************************************** - // Set up application - // *********************************************************************** - // start the packet sink on node 1 - PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), 8080)); - ApplicationContainer apps_sink = sink.Install (n1.Get (1)); - apps_sink.Start (Seconds (0.0)); - std::cout << "Node 1 installed sink " << std::endl; - - // start the OnOff app on source to destinations in the omni network - OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("10.1.1.255"), 8080)); - onoff.SetAttribute ("PacketSize", StringValue ("1000")); - onoff.SetAttribute ("DataRate", StringValue ("100000")); - onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); - onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); - ApplicationContainer apps1 = onoff.Install (n1.Get (0)); - apps1.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); - apps1.Start (Seconds (5.0)); - apps1.Stop (Seconds (simtime - 1.0)); - - // **** Choose if you want bcast or unicast traffic by uncommented appropriate line below. - // start the OnOff app on source to destinations in the directional network - onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("10.1.2.255"), 8080)); - //onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("10.1.2.2"), 8080)); - onoff.SetAttribute ("PacketSize", StringValue ("500")); - onoff.SetAttribute ("DataRate", StringValue ("100000")); - onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); - onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); - ApplicationContainer apps2 = onoff.Install (n2_dir.Get (0)); - apps2.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); - apps2.Start (Seconds (5.0)); - apps2.Stop (Seconds (simtime - 1.0)); - - // set up the sink receive callback on all packet sinks - Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); - - // *********************************************************************** - // and finally ... off we go! - // *********************************************************************** - - Simulator::Stop (Seconds(simtime)); - Simulator::Run (); - Simulator::Destroy (); - - std::cout << "App1 Sent: " << count_sent_app1 << " Received: " << count_recv_app1 << std::endl; - std::cout << "App2 Sent: " << count_sent_app2 << " Received: " << count_recv_app2 << std::endl; - - - NS_LOG_INFO ("Run Completed Successfully"); -} +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * All rights reserved. + * + * 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 +*/ + +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ + +// Network topology +// +// 0 ------------ 1 --- simple wireless network +// ++++++++++++ +++ directional simple wireless network +// +// This network has 2 nodes and 2 interfaces per node. +// Both interfaces are simple wireless +// One interface on each node is directional +// +// Node 0 sends traffic over both interfaces. part way into the simulation, +// node 0 loses its directional neighbor and the traffic over that link stops +// being received. + + + + +#include +#include +#include +#include +#include + +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/mobility-module.h" +#include "ns3/applications-module.h" +#include "ns3/internet-module.h" +#include "ns3/simple-wireless-module.h" + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("MixedDirectionalNetworkExample"); + +uint32_t count_sent_app1 = 0; +uint32_t count_recv_app1 = 0; +uint32_t count_sent_app2 = 0; +uint32_t count_recv_app2 = 0; + + +// ****************************************************************** +// These functions support the Applications +// ****************************************************************** +static void SinkReceivedBytes (Ptr p, const Address & from) +{ + if (p->GetSize () > 500) + { + count_recv_app1++; + } + else + { + count_recv_app2++; + } + + + std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize () << " bytes." << std::endl; +} + +static void AppSendBytes (Ptr p) +{ + if (p->GetSize () > 500) + { + count_sent_app1++; + } + else + { + count_sent_app2++; + } + + std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize () << " bytes. " << std::endl; +} + + +static void removeDirectionalNbr (Ptr sw) +{ + // remove directional neigbhor 1 + sw->DeleteDirectionalNeighbor (1); +} + +int +main (int argc, char *argv[]) +{ + NodeContainer::Iterator it; + double simtime = 126; + double dataRate = 10000000.0; //10Mb/s + + // create node container for the omni network + NodeContainer n1; + n1.Create (2); + // create node container for the directional network + NodeContainer n2_dir = NodeContainer (n1.Get (0), n1.Get (1)); + + + InternetStackHelper internet; + internet.Install (n1); + + + // Create container to hold devices + NetDeviceContainer d1_omni; + NetDeviceContainer d2_dir; + + // *********************************************************************** + // Set up the physical/radio layer + // *********************************************************************** + // Create error model and set as default + Ptr em = CreateObject (); + em->SetAttribute ("ErrorRate", DoubleValue (0.0)); + em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); + Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue (em)); + + // *********************************************************************** + // create first network + Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); + + // channel + Ptr phy1 = CreateObject (); + phy1->setErrorRate (0.0); + phy1->setErrorModelType (CONSTANT); + + // create simple wireless device on each node + for (it = n1.Begin (); it != n1.End (); ++it) + { + Ptr node = *it; + + // create device + Ptr simpleWireless1 = CreateObject (); + simpleWireless1->SetChannel (phy1); + simpleWireless1->SetNode (node); + simpleWireless1->SetAddress (Mac48Address::Allocate ()); + simpleWireless1->SetDataRate ((DataRate (dataRate))); + + // create queue type + Ptr> queue = CreateObject> (); + queue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + simpleWireless1->SetQueue (queue); + + node->AddDevice (simpleWireless1); + d1_omni.Add (simpleWireless1); + } + + // *********************************************************************** + // create second network + Ptr phy2 = CreateObject (); + phy2->setErrorRate (0.0); + phy2->setErrorModelType (CONSTANT); + + // create simple wireless device on each node + for (it = n2_dir.Begin (); it != n2_dir.End (); ++it) + { + Ptr node = *it; + uint32_t id = node->GetId (); + + // create device + Ptr simpleWireless2 = CreateObject (); + simpleWireless2->SetChannel (phy2); + simpleWireless2->SetNode (node); + simpleWireless2->SetAddress (Mac48Address::Allocate ()); + simpleWireless2->SetDataRate ((DataRate (dataRate))); + std::cout << "node id " << id << " has macAddress of " << simpleWireless2->GetAddress () << std::endl; + + // create queue type + Ptr> queue = CreateObject> (); + queue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + simpleWireless2->SetQueue (queue); + + if (id == 0) + { + // schedule function which removed node 0's directional neighbor + Simulator::Schedule (Seconds (60.0), &removeDirectionalNbr, simpleWireless2); + } + + node->AddDevice (simpleWireless2); + d2_dir.Add (simpleWireless2); + } + + + // *********************************************************************** + // Set up directional network. Do this after adding all the devices because + // we need to get MAC addresses for the neighbors we want to add + + // Get node 0, 1 device on the container. MUST use d2_dir container + // since that is the container with the SW interfaces that use directional + // network. + // In this example we get the ptr to the NetDevice using the index in the + // containter. We added them in numerical order so we know that 0 is node0, + // 1 is node 1, etc. + Ptr dev0 = d2_dir.Get (0); + Ptr dev1 = d2_dir.Get (1); + Ptr swDev0 = DynamicCast (dev0); + Ptr swDev1 = DynamicCast (dev1); + + // node 0 has directional neighbors to node 1 + swDev0->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); + // Here we use the function that takes a single node to add + Address addr = swDev1->GetAddress (); + Mac48Address macAddr = Mac48Address::ConvertFrom (addr); + swDev0->AddDirectionalNeighbor (1,macAddr); + + // node 1 has directional neighbors to node 0 + swDev1->SetAttributeFailSafe ("FixedNeighborListEnabled", BooleanValue (true)); + addr = swDev0->GetAddress (); + macAddr = Mac48Address::ConvertFrom (addr); + swDev1->AddDirectionalNeighbor (0,macAddr); + + + // *********************************************************************** + // add IP addresses. + Ipv4AddressHelper ipv4; + ipv4.SetBase ("10.1.1.0", "255.255.255.0"); + Ipv4InterfaceContainer interfaces = ipv4.Assign (d1_omni); + + ipv4.SetBase ("10.1.2.0", "255.255.255.0"); + ipv4.Assign (d2_dir); + + // Create router nodes, initialize routing database and set up the routing + // tables in the nodes. + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + + // *********************************************************************** + // Define positions. + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector ( 0.0, 0.0, 0.0)); + positionAlloc->Add (Vector ( 0.0, 50.0, 0.0)); + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (n1); + + + // *********************************************************************** + // Set up application + // *********************************************************************** + // start the packet sink on node 1 + PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address::GetAny (), 8080)); + ApplicationContainer apps_sink = sink.Install (n1.Get (1)); + apps_sink.Start (Seconds (0.0)); + std::cout << "Node 1 installed sink " << std::endl; + + // start the OnOff app on source to destinations in the omni network + OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("10.1.1.255"), 8080)); + onoff.SetAttribute ("PacketSize", StringValue ("1000")); + onoff.SetAttribute ("DataRate", StringValue ("100000")); + onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + ApplicationContainer apps1 = onoff.Install (n1.Get (0)); + apps1.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); + apps1.Start (Seconds (5.0)); + apps1.Stop (Seconds (simtime - 1.0)); + + // **** Choose if you want bcast or unicast traffic by uncommented appropriate line below. + // start the OnOff app on source to destinations in the directional network + onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("10.1.2.255"), 8080)); + //onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (Ipv4Address ("10.1.2.2"), 8080)); + onoff.SetAttribute ("PacketSize", StringValue ("500")); + onoff.SetAttribute ("DataRate", StringValue ("100000")); + onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + ApplicationContainer apps2 = onoff.Install (n2_dir.Get (0)); + apps2.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); + apps2.Start (Seconds (5.0)); + apps2.Stop (Seconds (simtime - 1.0)); + + // set up the sink receive callback on all packet sinks + Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); + + // *********************************************************************** + // and finally ... off we go! + // *********************************************************************** + + Simulator::Stop (Seconds (simtime)); + Simulator::Run (); + Simulator::Destroy (); + + std::cout << "App1 Sent: " << count_sent_app1 << " Received: " << count_recv_app1 << std::endl; + std::cout << "App2 Sent: " << count_sent_app2 << " Received: " << count_recv_app2 << std::endl; + + + NS_LOG_INFO ("Run Completed Successfully"); +} diff --git a/examples/queue_test.cc b/examples/queue_test.cc index 9948629..242597e 100644 --- a/examples/queue_test.cc +++ b/examples/queue_test.cc @@ -1,412 +1,414 @@ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * All rights reserved. - * - * 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 -*/ - -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ - -#include -#include -#include -#include -#include -#include "ns3/core-module.h" -#include "ns3/network-module.h" -#include "ns3/olsr-module.h" -#include "ns3/mobility-module.h" -#include "ns3/applications-module.h" -#include "ns3/internet-module.h" -#include "ns3/simple-wireless-module.h" - - -// This file is used to test the queue options available: -// - no queues -// - drop queue tail (provided with ns3) -// - drop queue head (new; provided with the MIT LL simple wireless model) -// - priority queue (new; provided with the MIT LL simple wireless model) -// -// All queues are FIFO -// -// Drop Queue Tail - when queues are full, drop at the tail of the queue. That is, the -// newly received packet is dropped -// Drop Queue Head - when queues are full, drop at the head of the queue. That is, the -// oldest packet is dropped and newly received packet is inserted -// into the queue -// Priority Queue - defines two queues: control and data. Each queue is configured -// independently to be either drop head or drop tail. Differentiation -// of control and data is based on a user specified pcap filter string -// -// The scenario has the following: -// - 2 nodes placed 50 units apart with no mobility -// - simple wireless model with user configurable data rate -// - OLSR used for routing -// - On/Off application used to send 1Mb/s -// - capability to enable pcap capture -// -// Queue capabilities can be tested by changing the data rate of the simple wireless model - -using namespace ns3; - -NS_LOG_COMPONENT_DEFINE ("queue_test"); - -uint32_t app_count_sent = 0; -uint32_t app_count_recv = 0; -uint32_t pkts_sent_data = 0; -uint32_t bytes_sent_data = 0; -uint32_t pkts_sent_cntl = 0; -uint32_t bytes_sent_cntl = 0; -uint32_t pkts_rcvd_data = 0; -uint32_t pkts_rcvd_cntl = 0; - -// variables for queue latency: overall, data and control -double_t avg_queue_latency = 0.0; -uint32_t queue_pkt_count = 0; -double_t avg_queue_latency_data = 0.0; -uint32_t queue_pkt_count_data = 0; -double_t avg_queue_latency_cntl = 0.0; -uint32_t queue_pkt_count_cntl = 0; - -#define APP_PKT_SIZE 1000 -std::string PktSize = "1000"; - - -// ****************************************************************** -// This function supports OLSR when running on Simple Wireless -// ****************************************************************** -static void TransmitStatsSW (Ptr p, Mac48Address from, Mac48Address to , uint16_t protocol) -{ - // Figure out if this is OLSR or data - if (p->GetSize() == (APP_PKT_SIZE + 28)) - { - pkts_sent_data++; - bytes_sent_data += p->GetSize(); - } - else - { - pkts_sent_cntl++; - bytes_sent_cntl += p->GetSize(); - } -} - - -static void MacRxSuccess (std::string context, Ptr p) -{ - if (p->GetSize() == (APP_PKT_SIZE + 28)) - { - pkts_rcvd_data++; - } - else - { - pkts_rcvd_cntl++; - } - - -} - -// ****************************************************************** -// This function supports Simple Wireless -// ****************************************************************** -static void QueueLatencyStats (Ptr p, Time latency) -{ - double_t pkt_latency = double_t(latency.GetMicroSeconds())/1000000.0; - - queue_pkt_count++; - avg_queue_latency = avg_queue_latency * (queue_pkt_count-1)/queue_pkt_count + pkt_latency/queue_pkt_count; - - // add 28 bytes to ap size for UDP/IP header and also add 14 for ethernet header. - // Packet passed in this trace still has the Ethernet header - if (p->GetSize() == (APP_PKT_SIZE + 28 + 14)) - { - queue_pkt_count_data++; - avg_queue_latency_data = avg_queue_latency_data * (queue_pkt_count_data-1)/queue_pkt_count_data + pkt_latency/queue_pkt_count_data; - //std::cout << Simulator::Now ().GetSeconds () << " DATA Packet latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; - } - else - { - queue_pkt_count_cntl++; - avg_queue_latency_cntl = avg_queue_latency_cntl * (queue_pkt_count_cntl-1)/queue_pkt_count_cntl + pkt_latency/queue_pkt_count_cntl; - //std::cout << Simulator::Now ().GetSeconds () << " CONTROL Packet ("<< p->GetSize() << ") latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; - } - -} - - -// ****************************************************************** -// These functions support OLSR and are related to the Applications -// ****************************************************************** - -static void SinkReceivedBytes (Ptr p, const Address & from) -{ - app_count_recv++; - //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; -} - -static void AppSendBytes (Ptr p) -{ - app_count_sent++; - //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; -} - - -// ****************************************************************** -// MAIN -// ****************************************************************** - -int -main (int argc, char *argv[]) -{ - NodeContainer::Iterator it; - NodeContainer::Iterator it2; - std::list destAddresses; // used by OLSR - - Ipv4Address sourceNodeAddr; - - - // *********************************************************************** - // Initialize all value that are to be used in the scenario - // *********************************************************************** - double simtime = 120; - bool collectPcap = false; - double dataRate = 10000000.0; - std::string queueType = "DropTail"; - - // *********************************************************************** - // parse command line - // *********************************************************************** - CommandLine cmd; - cmd.AddValue ("pcap", "Set to 1 to collect pcap traces", collectPcap); - cmd.AddValue ("datarate", "Data Rate of wireless link in bits per second", dataRate); - cmd.AddValue ("queueType", "Set Queue type to NoQueue, DropHead, DropTail or PriorityHead or PriorityTail", queueType); - cmd.Parse (argc,argv); - - std::cout << "Running scenario for " << simtime << " seconds with queue type: "<< queueType <<" and data rate: " << std::fixed << std::setprecision(1) << dataRate <<"bps"<< std::endl; - - if ((queueType != "NoQueue") && (queueType != "DropHead") && (queueType != "DropTail") && (queueType != "PriorityHead") && (queueType != "PriorityTail")) - { - NS_ABORT_MSG ("Invalid queue type: Use --queueType=DropHead or --queueType=DropTail or --queueType=PriorityHead or --queueType=PriorityTail"); - } - - // *********************************************************************** - // Create all the nodes - // *********************************************************************** - NodeContainer NpNodes; - NpNodes.Create (2); - NodeContainer const & n = NodeContainer::GetGlobal (); - - // Create container to hold devices - NetDeviceContainer devices; - - // *********************************************************************** - // Set up the physical/radio layer - // *********************************************************************** - // Set transmission range - Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); - - // Create error model and set as default for the device Receive side - // ALWAYS set the error rate to 0 here. The error is handled on the send side - // by the channel model in the simple wireless - Ptr em = CreateObject (); - em->SetAttribute ("ErrorRate", DoubleValue (0.0)); - em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); - Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue(em)); - - // create channel - Ptr phy = CreateObject (); - phy->setErrorRate(0.0); - phy->setErrorModelType(CONSTANT); - - // create simple wireless device on each node - std::string fileStr; - for (it = n.Begin (); it != n.End (); ++it) - { - Ptr node = *it; - - // create device - Ptr simpleWireless = CreateObject (); - simpleWireless->SetChannel(phy); - simpleWireless->SetNode(node); - simpleWireless->SetAddress(Mac48Address::Allocate ()); - simpleWireless->SetDataRate((DataRate (dataRate))); - - // Set queue type to use. Set nothing if NoQueue - if (queueType == "DropHead") - { - Config::SetDefault ("ns3::DropHeadQueue::Mode", StringValue ("QUEUE_MODE_PACKETS")); - Config::SetDefault ("ns3::DropHeadQueue::MaxPackets", UintegerValue (100)); - Ptr queue = CreateObject (); - simpleWireless->SetQueue(queue); - } - else if (queueType == "DropTail") - { - Config::SetDefault ("ns3::DropTailQueue::Mode", StringValue ("QUEUE_MODE_PACKETS")); - Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (100)); - Ptr queue = CreateObject (); - simpleWireless->SetQueue(queue); - } - else if (queueType == "PriorityHead") - { - Config::SetDefault ("ns3::PriorityQueue::ControlPacketClassifier", StringValue ("port 698")); - Config::SetDefault ("ns3::DropHeadQueue::Mode", StringValue ("QUEUE_MODE_PACKETS")); - Config::SetDefault ("ns3::DropHeadQueue::MaxPackets", UintegerValue (100)); - Ptr controlQueue = CreateObject (); - Ptr dataQueue = CreateObject (); - Ptr queue = CreateObject (); - queue->Initialize(); - queue->SetControlQueue(controlQueue); - queue->SetDataQueue(dataQueue); - simpleWireless->SetQueue(queue); - } - else if (queueType == "PriorityTail") - { - Config::SetDefault ("ns3::PriorityQueue::ControlPacketClassifier", StringValue ("port 698")); - Config::SetDefault ("ns3::DropTailQueue::Mode", StringValue ("QUEUE_MODE_PACKETS")); - Config::SetDefault ("ns3::DropTailQueue::MaxPackets", UintegerValue (100)); - Ptr controlQueue = CreateObject (); - Ptr dataQueue = CreateObject (); - Ptr queue = CreateObject (); - queue->Initialize(); - queue->SetControlQueue(controlQueue); - queue->SetDataQueue(dataQueue); - simpleWireless->SetQueue(queue); - } - - // Set up trace to pass node id on the RX end - std::ostringstream oss; - oss << node->GetId(); - simpleWireless->TraceConnect ("MacRx", oss.str(), MakeCallback (&MacRxSuccess)); - - node->AddDevice (simpleWireless); - devices.Add (simpleWireless); - - // set up pcap capture - if (collectPcap) - { - std::ostringstream stringStream; - stringStream << "QUEUE_node_" << node->GetId() << ".pcap"; - fileStr = stringStream.str(); - simpleWireless->EnablePcapAll(fileStr); - } - } - - // set up call back for traces - Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/QueueLatency", MakeCallback (&QueueLatencyStats)); - Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/PhyTxBegin", MakeCallback (&TransmitStatsSW)); - - // *********************************************************************** - // Define positions. Nodes are 50 apart - MobilityHelper mobility; - Ptr positionAlloc = CreateObject (); - positionAlloc->Add (Vector (0.0, 0.0, 0.0)); - positionAlloc->Add (Vector (50.0, 0.0, 0.0)); - mobility.SetPositionAllocator (positionAlloc); - mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); - mobility.Install (NpNodes); - - - // *********************************************************************** - // Set up routing OLSR - // *********************************************************************** - // don't have to use the Ipv4ListRoutingHelper but it prints - // the routing table in a better format than directly installing olsr. - InternetStackHelper stack; - OlsrHelper olsr; - Ipv4ListRoutingHelper list; - - // Add the routing to the route helper - list.Add (olsr, 10); - - // print the olsr routing table to a file every 10 seconds - //Ptr routingStream = Create ("400node_OLSR.routes", std::ios::out); - //olsr.PrintRoutingTableAllEvery (Seconds (10), routingStream); - - // now set the routing and install on all nodes - stack.SetRoutingHelper (list); - stack.Install (NpNodes); - - // set up IP addresses - Ipv4AddressHelper address; - address.SetBase ("10.0.0.0", "255.255.0.0"); - Ipv4InterfaceContainer interfaces = address.Assign (devices); - - // *********************************************************************** - // Set up application - // *********************************************************************** - // start the packet sink on destination node - PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (1), 8080)); - ApplicationContainer apps_sink = sink.Install (NpNodes.Get (1)); - apps_sink.Start (Seconds (0.0)); - std::cout << "Node 1 installed sink to receive on " << interfaces.GetAddress (1) << std::endl; - - // set up the sink receive callback on all packet sinks - Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); - - // Now start the OnOff app on source to destinations - OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (1), 8080)); - onoff.SetAttribute ("PacketSize", StringValue (PktSize)); - onoff.SetAttribute ("DataRate", StringValue ("1000000")); - onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); - onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); - - ApplicationContainer apps = onoff.Install (NpNodes.Get (0)); - std::cout << "Node 0 installed app to send to " << interfaces.GetAddress (1) << std::endl; - apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); - - apps.Start (Seconds (5.0)); - apps.Stop (Seconds (simtime - 5.0)); - - - // *********************************************************************** - // and finally ... off we go! - // *********************************************************************** - - Simulator::Stop (Seconds(simtime)); - Simulator::Run (); - Simulator::Destroy (); - - // *********************************************************************** - // For OLSR we need to get some stats - // *********************************************************************** - double rcvPercentData = 0.0; - uint32_t dataDropped = app_count_sent - app_count_recv; - if (app_count_sent) - rcvPercentData = ((double)app_count_recv/(double)app_count_sent)*100.0; - - double rcvPercentCntrl = 0.0; - uint32_t cntlDropped = pkts_sent_cntl - pkts_rcvd_cntl; - if (pkts_sent_cntl) - rcvPercentCntrl = ((double)pkts_rcvd_cntl/(double)pkts_sent_cntl)*100.0; - - std::cout << "App Packets Sent: " << app_count_sent << "\nApp Packets Received: " << app_count_recv - << "\nControl Packets Sent: " << pkts_sent_cntl << "\nControl Bytes Sent: " << bytes_sent_cntl - << "\nData Packets Sent: " << pkts_sent_data << "\nData Bytes Sent: " << bytes_sent_data - << "\nControl Packets Received: " << pkts_rcvd_cntl << "\nData Packets Received: " << pkts_rcvd_data - << "\nData Packets Dropped: " << dataDropped << "\nControl Packets Dropped: " << cntlDropped - << "\n% Data Received: " << std::fixed << std::setprecision(1) << rcvPercentData << std::noshowpoint << std::setprecision(0) - << "\n% Control Received: " << std::fixed << std::setprecision(1) << rcvPercentCntrl << std::noshowpoint << std::setprecision(0) < +#include +#include +#include +#include +#include "ns3/core-module.h" +#include "ns3/network-module.h" +#include "ns3/olsr-module.h" +#include "ns3/mobility-module.h" +#include "ns3/applications-module.h" +#include "ns3/internet-module.h" +#include "ns3/simple-wireless-module.h" + + +// This file is used to test the queue options available: +// - no queues +// - drop queue tail (provided with ns3) +// - drop queue head (new; provided with the MIT LL simple wireless model) +// - priority queue (new; provided with the MIT LL simple wireless model) +// +// All queues are FIFO +// +// Drop Queue Tail - when queues are full, drop at the tail of the queue. That is, the +// newly received packet is dropped +// Drop Queue Head - when queues are full, drop at the head of the queue. That is, the +// oldest packet is dropped and newly received packet is inserted +// into the queue +// Priority Queue - defines two queues: control and data. Each queue is configured +// independently to be either drop head or drop tail. Differentiation +// of control and data is based on a user specified pcap filter string +// +// The scenario has the following: +// - 2 nodes placed 50 units apart with no mobility +// - simple wireless model with user configurable data rate +// - OLSR used for routing +// - On/Off application used to send 1Mb/s +// - capability to enable pcap capture +// +// Queue capabilities can be tested by changing the data rate of the simple wireless model + +using namespace ns3; + +NS_LOG_COMPONENT_DEFINE ("queue_test"); + +uint32_t app_count_sent = 0; +uint32_t app_count_recv = 0; +uint32_t pkts_sent_data = 0; +uint32_t bytes_sent_data = 0; +uint32_t pkts_sent_cntl = 0; +uint32_t bytes_sent_cntl = 0; +uint32_t pkts_rcvd_data = 0; +uint32_t pkts_rcvd_cntl = 0; + +// variables for queue latency: overall, data and control +double_t avg_queue_latency = 0.0; +uint32_t queue_pkt_count = 0; +double_t avg_queue_latency_data = 0.0; +uint32_t queue_pkt_count_data = 0; +double_t avg_queue_latency_cntl = 0.0; +uint32_t queue_pkt_count_cntl = 0; + +#define APP_PKT_SIZE 1000 +std::string PktSize = "1000"; + + +// ****************************************************************** +// This function supports OLSR when running on Simple Wireless +// ****************************************************************** +static void TransmitStatsSW (Ptr p, Mac48Address from, Mac48Address to, uint16_t protocol) +{ + // Figure out if this is OLSR or data + if (p->GetSize () == (APP_PKT_SIZE + 28)) + { + pkts_sent_data++; + bytes_sent_data += p->GetSize (); + } + else + { + pkts_sent_cntl++; + bytes_sent_cntl += p->GetSize (); + } +} + + +static void MacRxSuccess (std::string context, Ptr p) +{ + if (p->GetSize () == (APP_PKT_SIZE + 28)) + { + pkts_rcvd_data++; + } + else + { + pkts_rcvd_cntl++; + } + + +} + +// ****************************************************************** +// This function supports Simple Wireless +// ****************************************************************** +static void QueueLatencyStats (Ptr p, Time latency) +{ + double_t pkt_latency = double_t (latency.GetMicroSeconds ()) / 1000000.0; + + queue_pkt_count++; + avg_queue_latency = avg_queue_latency * (queue_pkt_count - 1) / queue_pkt_count + pkt_latency / queue_pkt_count; + + // add 28 bytes to ap size for UDP/IP header and also add 14 for ethernet header. + // Packet passed in this trace still has the Ethernet header + if (p->GetSize () == (APP_PKT_SIZE + 28 + 14)) + { + queue_pkt_count_data++; + avg_queue_latency_data = avg_queue_latency_data * (queue_pkt_count_data - 1) / queue_pkt_count_data + pkt_latency / queue_pkt_count_data; + //std::cout << Simulator::Now ().GetSeconds () << " DATA Packet latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; + } + else + { + queue_pkt_count_cntl++; + avg_queue_latency_cntl = avg_queue_latency_cntl * (queue_pkt_count_cntl - 1) / queue_pkt_count_cntl + pkt_latency / queue_pkt_count_cntl; + //std::cout << Simulator::Now ().GetSeconds () << " CONTROL Packet ("<< p->GetSize() << ") latency: " << std::setprecision(9) << pkt_latency << " seconds"<< std::endl; + } + +} + + +// ****************************************************************** +// These functions support OLSR and are related to the Applications +// ****************************************************************** + +static void SinkReceivedBytes (Ptr p, const Address & from) +{ + app_count_recv++; + //std::cout << Simulator::Now ().GetSeconds () << " Node receiving packet of " << p->GetSize() << " bytes. count_recv is "<< count_recv << std::endl; +} + +static void AppSendBytes (Ptr p) +{ + app_count_sent++; + //std::cout << Simulator::Now ().GetSeconds () << " Node sending packet of " << p->GetSize() << " bytes. count_sent is "<< count_sent << std::endl; +} + + +// ****************************************************************** +// MAIN +// ****************************************************************** + +int +main (int argc, char *argv[]) +{ + NodeContainer::Iterator it; + NodeContainer::Iterator it2; + std::list destAddresses; // used by OLSR + + Ipv4Address sourceNodeAddr; + + + // *********************************************************************** + // Initialize all value that are to be used in the scenario + // *********************************************************************** + double simtime = 120; + bool collectPcap = false; + double dataRate = 10000000.0; + std::string queueType = "DropTail"; + + // *********************************************************************** + // parse command line + // *********************************************************************** + CommandLine cmd; + cmd.AddValue ("pcap", "Set to 1 to collect pcap traces", collectPcap); + cmd.AddValue ("datarate", "Data Rate of wireless link in bits per second", dataRate); + cmd.AddValue ("queueType", "Set Queue type to NoQueue, DropHead, DropTail or PriorityHead or PriorityTail", queueType); + cmd.Parse (argc,argv); + + std::cout << "Running scenario for " << simtime << " seconds with queue type: " << queueType << " and data rate: " << std::fixed << std::setprecision (1) << dataRate << "bps" << std::endl; + + if ((queueType != "NoQueue") && (queueType != "DropHead") && (queueType != "DropTail") && (queueType != "PriorityHead") && (queueType != "PriorityTail")) + { + NS_ABORT_MSG ("Invalid queue type: Use --queueType=DropHead or --queueType=DropTail or --queueType=PriorityHead or --queueType=PriorityTail"); + } + + // *********************************************************************** + // Create all the nodes + // *********************************************************************** + NodeContainer NpNodes; + NpNodes.Create (2); + NodeContainer const & n = NodeContainer::GetGlobal (); + + // Create container to hold devices + NetDeviceContainer devices; + + // *********************************************************************** + // Set up the physical/radio layer + // *********************************************************************** + // Set transmission range + Config::SetDefault ("ns3::SimpleWirelessChannel::MaxRange", DoubleValue (100.0)); + + // Create error model and set as default for the device Receive side + // ALWAYS set the error rate to 0 here. The error is handled on the send side + // by the channel model in the simple wireless + Ptr em = CreateObject (); + em->SetAttribute ("ErrorRate", DoubleValue (0.0)); + em->SetAttribute ("ErrorUnit", StringValue ("ERROR_UNIT_PACKET")); + Config::SetDefault ("ns3::SimpleWirelessNetDevice::ReceiveErrorModel", PointerValue (em)); + + // create channel + Ptr phy = CreateObject (); + phy->setErrorRate (0.0); + phy->setErrorModelType (CONSTANT); + + // create simple wireless device on each node + std::string fileStr; + for (it = n.Begin (); it != n.End (); ++it) + { + Ptr node = *it; + + // create device + Ptr simpleWireless = CreateObject (); + simpleWireless->SetChannel (phy); + simpleWireless->SetNode (node); + simpleWireless->SetAddress (Mac48Address::Allocate ()); + simpleWireless->SetDataRate ((DataRate (dataRate))); + + // Set queue type to use. Set nothing if NoQueue + if (queueType == "DropHead") + { + Ptr> queue = CreateObject> (); + queue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + simpleWireless->SetQueue (queue); + } + else if (queueType == "DropTail") + { + Ptr> queue = CreateObject> (); + queue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + simpleWireless->SetQueue (queue); + } + else if (queueType == "PriorityHead") + { + Config::SetDefault ("ns3::PriorityQueue::ControlPacketClassifier", StringValue ("port 698")); + Ptr> controlQueue = CreateObject> (); + controlQueue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + Ptr> dataQueue = CreateObject> (); + dataQueue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + Ptr> queue = CreateObject> (); + queue->Initialize (); + queue->SetControlQueue (controlQueue); + queue->SetDataQueue (dataQueue); + simpleWireless->SetQueue (queue); + } + else if (queueType == "PriorityTail") + { + Config::SetDefault ("ns3::PriorityQueue::ControlPacketClassifier", StringValue ("port 698")); + Ptr> controlQueue = CreateObject> (); + controlQueue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + Ptr> dataQueue = CreateObject> (); + dataQueue->SetMaxSize (QueueSize (QueueSizeUnit::PACKETS, 100)); + Ptr> queue = CreateObject> (); + queue->Initialize (); + queue->SetControlQueue (controlQueue); + queue->SetDataQueue (dataQueue); + simpleWireless->SetQueue (queue); + } + + // Set up trace to pass node id on the RX end + std::ostringstream oss; + oss << node->GetId (); + simpleWireless->TraceConnect ("MacRx", oss.str (), MakeCallback (&MacRxSuccess)); + + node->AddDevice (simpleWireless); + devices.Add (simpleWireless); + + // set up pcap capture + if (collectPcap) + { + std::ostringstream stringStream; + stringStream << "QUEUE_node_" << node->GetId () << ".pcap"; + fileStr = stringStream.str (); + simpleWireless->EnablePcapAll (fileStr); + } + } + + // set up call back for traces + Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/QueueLatency", MakeCallback (&QueueLatencyStats)); + Config::ConnectWithoutContext ("/NodeList/*/DeviceList/*/$ns3::SimpleWirelessNetDevice/PhyTxBegin", MakeCallback (&TransmitStatsSW)); + + // *********************************************************************** + // Define positions. Nodes are 50 apart + MobilityHelper mobility; + Ptr positionAlloc = CreateObject (); + positionAlloc->Add (Vector (0.0, 0.0, 0.0)); + positionAlloc->Add (Vector (50.0, 0.0, 0.0)); + mobility.SetPositionAllocator (positionAlloc); + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); + mobility.Install (NpNodes); + + + // *********************************************************************** + // Set up routing OLSR + // *********************************************************************** + // don't have to use the Ipv4ListRoutingHelper but it prints + // the routing table in a better format than directly installing olsr. + InternetStackHelper stack; + OlsrHelper olsr; + Ipv4ListRoutingHelper list; + + // Add the routing to the route helper + list.Add (olsr, 10); + + // print the olsr routing table to a file every 10 seconds + //Ptr routingStream = Create ("400node_OLSR.routes", std::ios::out); + //olsr.PrintRoutingTableAllEvery (Seconds (10), routingStream); + + // now set the routing and install on all nodes + stack.SetRoutingHelper (list); + stack.Install (NpNodes); + + // set up IP addresses + Ipv4AddressHelper address; + address.SetBase ("10.0.0.0", "255.255.0.0"); + Ipv4InterfaceContainer interfaces = address.Assign (devices); + + // *********************************************************************** + // Set up application + // *********************************************************************** + // start the packet sink on destination node + PacketSinkHelper sink ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (1), 8080)); + ApplicationContainer apps_sink = sink.Install (NpNodes.Get (1)); + apps_sink.Start (Seconds (0.0)); + std::cout << "Node 1 installed sink to receive on " << interfaces.GetAddress (1) << std::endl; + + // set up the sink receive callback on all packet sinks + Config::ConnectWithoutContext ("/NodeList/*/ApplicationList/*/$ns3::PacketSink/Rx", MakeCallback (&SinkReceivedBytes)); + + // Now start the OnOff app on source to destinations + OnOffHelper onoff = OnOffHelper ("ns3::UdpSocketFactory", InetSocketAddress (interfaces.GetAddress (1), 8080)); + onoff.SetAttribute ("PacketSize", StringValue (PktSize)); + onoff.SetAttribute ("DataRate", StringValue ("1000000")); + onoff.SetAttribute ("OnTime", StringValue ("ns3::ConstantRandomVariable[Constant=1]")); + onoff.SetAttribute ("OffTime", StringValue ("ns3::ConstantRandomVariable[Constant=0]")); + + ApplicationContainer apps = onoff.Install (NpNodes.Get (0)); + std::cout << "Node 0 installed app to send to " << interfaces.GetAddress (1) << std::endl; + apps.Get (0)->TraceConnectWithoutContext ("Tx", MakeCallback (&AppSendBytes)); + + apps.Start (Seconds (5.0)); + apps.Stop (Seconds (simtime - 5.0)); + + + // *********************************************************************** + // and finally ... off we go! + // *********************************************************************** + + Simulator::Stop (Seconds (simtime)); + Simulator::Run (); + Simulator::Destroy (); + + // *********************************************************************** + // For OLSR we need to get some stats + // *********************************************************************** + double rcvPercentData = 0.0; + uint32_t dataDropped = app_count_sent - app_count_recv; + if (app_count_sent) + { + rcvPercentData = ((double)app_count_recv / (double)app_count_sent) * 100.0; + } + + double rcvPercentCntrl = 0.0; + uint32_t cntlDropped = pkts_sent_cntl - pkts_rcvd_cntl; + if (pkts_sent_cntl) + { + rcvPercentCntrl = ((double)pkts_rcvd_cntl / (double)pkts_sent_cntl) * 100.0; + } + + std::cout << "App Packets Sent: " << app_count_sent << "\nApp Packets Received: " << app_count_recv + << "\nControl Packets Sent: " << pkts_sent_cntl << "\nControl Bytes Sent: " << bytes_sent_cntl + << "\nData Packets Sent: " << pkts_sent_data << "\nData Bytes Sent: " << bytes_sent_data + << "\nControl Packets Received: " << pkts_rcvd_cntl << "\nData Packets Received: " << pkts_rcvd_data + << "\nData Packets Dropped: " << dataDropped << "\nControl Packets Dropped: " << cntlDropped + << "\n% Data Received: " << std::fixed << std::setprecision (1) << rcvPercentData << std::noshowpoint << std::setprecision (0) + << "\n% Control Received: " << std::fixed << std::setprecision (1) << rcvPercentCntrl << std::noshowpoint << std::setprecision (0) << std::endl; + if ( (queueType == "PriorityHead") || (queueType == "PriorityTail") ) + { + std::cout << "Average Queue Latency Data: " << std::fixed << std::setprecision (6) << avg_queue_latency_data + << "\nAverage Queue Latency Control: " << std::fixed << std::setprecision (6) << avg_queue_latency_cntl << std::noshowpoint << std::setprecision (0) << std::endl; + } + else + { + std::cout << "Average Queue Latency: " << std::fixed << std::setprecision (6) << avg_queue_latency << std::noshowpoint << std::setprecision (0) << std::endl; + } + + NS_LOG_INFO ("Run Completed Successfully"); + + return 0; +} diff --git a/examples/wscript b/examples/wscript index 94c52db..59b1617 100644 --- a/examples/wscript +++ b/examples/wscript @@ -1,48 +1,49 @@ -# -# Copyright (C) 2015 Massachusetts Institute of Technology -# All rights reserved. -# -# 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 - - -## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- - -def build(bld): - if not bld.env['ENABLE_EXAMPLES']: - return; - - obj = bld.create_ns3_program('queue_test', - ['core', 'mobility', 'network', 'internet', 'olsr', 'simple-wireless']) - obj.source = 'queue_test.cc' - - obj = bld.create_ns3_program('directional_test', - ['core', 'mobility', 'network', 'internet', 'olsr', 'simple-wireless']) - obj.source = 'directional_test.cc' - - obj = bld.create_ns3_program('mixed_directional_network', - ['core', 'mobility', 'network', 'internet', 'olsr', 'simple-wireless']) - obj.source = 'mixed_directional_network.cc' - - obj = bld.create_ns3_program('multiple_interface_example', - ['core', 'mobility', 'network', 'internet', 'olsr', 'simple-wireless']) - obj.source = 'multiple_interface_example.cc' - - obj = bld.create_ns3_program('fixed_contention_test', - ['core', 'mobility', 'network', 'internet', 'olsr', 'simple-wireless']) - obj.source = 'fixed_contention_test.cc' - - obj = bld.create_ns3_program('error_model_test', - ['core', 'mobility', 'network', 'internet', 'olsr', 'simple-wireless']) - obj.source = 'error_model_test.cc' - +# +# Copyright (C) 2015 Massachusetts Institute of Technology +# All rights reserved. +# +# 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 + + +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + if not bld.env['ENABLE_EXAMPLES']: + return; + + obj = bld.create_ns3_program('queue_test', + ['core', 'mobility', 'network', 'internet', 'olsr', 'applications', 'simple-wireless']) + obj.source = 'queue_test.cc' + obj.env.append_value("LIB", ["pcap"]) + + obj = bld.create_ns3_program('directional_test', + ['core', 'mobility', 'network', 'internet', 'olsr', 'applications', 'simple-wireless']) + obj.source = 'directional_test.cc' + + obj = bld.create_ns3_program('mixed_directional_network', + ['core', 'mobility', 'network', 'internet', 'olsr', 'applications', 'simple-wireless']) + obj.source = 'mixed_directional_network.cc' + + obj = bld.create_ns3_program('multiple_interface_example', + ['core', 'mobility', 'network', 'internet', 'olsr', 'applications', 'simple-wireless']) + obj.source = 'multiple_interface_example.cc' + + obj = bld.create_ns3_program('fixed_contention_test', + ['core', 'mobility', 'network', 'internet', 'olsr', 'applications', 'simple-wireless']) + obj.source = 'fixed_contention_test.cc' + + obj = bld.create_ns3_program('error_model_test', + ['core', 'mobility', 'network', 'internet', 'olsr', 'applications', 'simple-wireless']) + obj.source = 'error_model_test.cc' + diff --git a/model/drop-head-queue.cc b/model/drop-head-queue.cc index 83792e3..44262a9 100644 --- a/model/drop-head-queue.cc +++ b/model/drop-head-queue.cc @@ -1,159 +1,27 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * Copyright (c) 2007 University of Washington - * - * 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 - */ - -#include "ns3/log.h" -#include "ns3/enum.h" -#include "ns3/uinteger.h" -#include "drop-head-queue.h" - -namespace ns3 { - -NS_LOG_COMPONENT_DEFINE ("DropHeadQueue"); - -NS_OBJECT_ENSURE_REGISTERED (DropHeadQueue); - -TypeId DropHeadQueue::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::DropHeadQueue") - .SetParent () - .AddConstructor () - .AddAttribute ("Mode", - "Whether to use bytes (see MaxBytes) or packets (see MaxPackets) as the maximum queue size metric.", - EnumValue (QUEUE_MODE_PACKETS), - MakeEnumAccessor (&DropHeadQueue::SetMode), - MakeEnumChecker (QUEUE_MODE_BYTES, "QUEUE_MODE_BYTES", - QUEUE_MODE_PACKETS, "QUEUE_MODE_PACKETS")) - .AddAttribute ("MaxPackets", - "The maximum number of packets accepted by this DropHeadQueue.", - UintegerValue (100), - MakeUintegerAccessor (&DropHeadQueue::m_maxPackets), - MakeUintegerChecker ()) - .AddAttribute ("MaxBytes", - "The maximum number of bytes accepted by this DropHeadQueue.", - UintegerValue (100 * 65535), - MakeUintegerAccessor (&DropHeadQueue::m_maxBytes), - MakeUintegerChecker ()) - ; - - return tid; -} - -DropHeadQueue::DropHeadQueue () : - Queue (), - m_packets (), - m_bytesInQueue (0) -{ - NS_LOG_FUNCTION (this); -} - -DropHeadQueue::~DropHeadQueue () -{ - NS_LOG_FUNCTION (this); -} - -void -DropHeadQueue::SetMode (DropHeadQueue::QueueMode mode) -{ - NS_LOG_FUNCTION (this << mode); - m_mode = mode; -} - -DropHeadQueue::QueueMode -DropHeadQueue::GetMode (void) -{ - NS_LOG_FUNCTION (this); - return m_mode; -} - -bool -DropHeadQueue::DoEnqueue (Ptr p) -{ - NS_LOG_FUNCTION (this << p); - - if (m_mode == QUEUE_MODE_PACKETS && (m_packets.size () >= m_maxPackets)) - { - NS_LOG_LOGIC ("Queue full (at max packets) -- droppping pkt"); - Ptr head_packet = Dequeue(); - Drop (head_packet); - } - - if (m_mode == QUEUE_MODE_BYTES) - { - // Drop packets from head of queue until enough bytes is available - while (m_bytesInQueue + p->GetSize () >= m_maxBytes) - { - NS_LOG_LOGIC ("Queue full (packet would exceed max bytes) -- droppping pkt"); - Ptr head_packet = Dequeue(); - Drop (head_packet); - } - } - - m_bytesInQueue += p->GetSize (); - m_packets.push (p); - - NS_LOG_LOGIC ("Number packets " << m_packets.size ()); - NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); - - return true; -} - -Ptr -DropHeadQueue::DoDequeue (void) -{ - NS_LOG_FUNCTION (this); - - if (m_packets.empty ()) - { - NS_LOG_LOGIC ("Queue empty"); - return 0; - } - - Ptr p = m_packets.front (); - m_packets.pop (); - m_bytesInQueue -= p->GetSize (); - - NS_LOG_LOGIC ("Popped " << p); - - NS_LOG_LOGIC ("Number packets " << m_packets.size ()); - NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); - - return p; -} - -Ptr -DropHeadQueue::DoPeek (void) const -{ - NS_LOG_FUNCTION (this); - - if (m_packets.empty ()) - { - NS_LOG_LOGIC ("Queue empty"); - return 0; - } - - Ptr p = m_packets.front (); - - NS_LOG_LOGIC ("Number packets " << m_packets.size ()); - NS_LOG_LOGIC ("Number bytes " << m_bytesInQueue); - - return p; -} - -} // namespace ns3 - +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 University of Washington + * + * 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 + */ + +#include "drop-head-queue.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("DropHeadQueue"); + +NS_OBJECT_TEMPLATE_CLASS_DEFINE (DropHeadQueue,Packet); + +} // namespace ns3 diff --git a/model/drop-head-queue.h b/model/drop-head-queue.h index 3058ccd..08d9ccb 100644 --- a/model/drop-head-queue.h +++ b/model/drop-head-queue.h @@ -1,81 +1,142 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * Copyright (c) 2007 University of Washington - * - * 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 - */ - -#ifndef DROPHEAD_H -#define DROPHEAD_H - -#include -#include "ns3/packet.h" -#include "ns3/queue.h" - -namespace ns3 { - -class TraceContainer; - -/** - * \ingroup queue - * - * \brief A FIFO packet queue that drops head-end packets on overflow - */ -class DropHeadQueue : public Queue { -public: - /** - * \brief Get the type ID. - * \return the object TypeId - */ - static TypeId GetTypeId (void); - /** - * \brief DropHeadQueue Constructor - * - * Creates a drophead queue with a maximum size of 100 packets by default - */ - DropHeadQueue (); - - virtual ~DropHeadQueue(); - - /** - * Set the operating mode of this device. - * - * \param mode The operating mode of this device. - * - */ - void SetMode (DropHeadQueue::QueueMode mode); - - /** - * Get the encapsulation mode of this device. - * - * \returns The encapsulation mode of this device. - */ - DropHeadQueue::QueueMode GetMode (void); - -private: - virtual bool DoEnqueue (Ptr p); - virtual Ptr DoDequeue (void); - virtual Ptr DoPeek (void) const; - - std::queue > m_packets; //!< the packets in the queue - uint32_t m_maxPackets; //!< max packets in the queue - uint32_t m_maxBytes; //!< max bytes in the queue - uint32_t m_bytesInQueue; //!< actual bytes in the queue - QueueMode m_mode; //!< queue mode (packets or bytes limited) -}; - -} // namespace ns3 - -#endif /* DROPHEAD_H */ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (c) 2007 University of Washington + * + * 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 + */ + +#ifndef DROP_HEAD_QUEUE_H +#define DROP_HEAD_QUEUE_H + +#include "ns3/queue.h" + +namespace ns3 { + +/** + * \ingroup queue + * + * \brief A FIFO packet queue that drops packets at the head of the queue on overflow + */ +template +class DropHeadQueue : public Queue +{ +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + /** + * \brief DropHeadQueue Constructor + * + * Creates a droptail queue with a maximum size of 100 packets by default + */ + DropHeadQueue (); + + virtual ~DropHeadQueue (); + + virtual bool Enqueue (Ptr item); + virtual Ptr Dequeue (void); + virtual Ptr Remove (void); + virtual Ptr Peek (void) const; + +private: + using Queue::Head; + using Queue::Tail; + using Queue::DoEnqueue; + using Queue::DoDequeue; + using Queue::DoRemove; + using Queue::DoPeek; + + NS_LOG_TEMPLATE_DECLARE; //!< redefinition of the log component +}; + + +/** + * Implementation of the templates declared above. + */ + +template +TypeId +DropHeadQueue::GetTypeId (void) +{ + static TypeId tid = TypeId (("ns3::DropHeadQueue<" + GetTypeParamName > () + ">").c_str ()) + .SetParent > () + .SetGroupName ("Network") + .template AddConstructor > () + ; + return tid; +} + +template +DropHeadQueue::DropHeadQueue () : + Queue (), + NS_LOG_TEMPLATE_DEFINE ("DropHeadQueue") +{ + NS_LOG_FUNCTION (this); +} + +template +DropHeadQueue::~DropHeadQueue () +{ + NS_LOG_FUNCTION (this); +} + +template +bool +DropHeadQueue::Enqueue (Ptr item) +{ + NS_LOG_FUNCTION (this << item); + + return DoEnqueue (Tail (), item); +} + +template +Ptr +DropHeadQueue::Dequeue (void) +{ + NS_LOG_FUNCTION (this); + + Ptr item = DoDequeue (Head ()); + + NS_LOG_LOGIC ("Popped " << item); + + return item; +} + +template +Ptr +DropHeadQueue::Remove (void) +{ + NS_LOG_FUNCTION (this); + + Ptr item = DoRemove (Head ()); + + NS_LOG_LOGIC ("Removed " << item); + + return item; +} + +template +Ptr +DropHeadQueue::Peek (void) const +{ + NS_LOG_FUNCTION (this); + + return DoPeek (Head ()); +} + +} // namespace ns3 + +#endif /* DROP_HEAD_QUEUE_H */ diff --git a/model/priority-queue.cc b/model/priority-queue.cc index 1f8e88b..0eb6148 100644 --- a/model/priority-queue.cc +++ b/model/priority-queue.cc @@ -1,193 +1,28 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * Copyright (c) 2007 University of Washington - * - * 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 - */ - -#include "ns3/log.h" -#include "ns3/enum.h" -#include "ns3/string.h" -#include "ns3/pointer.h" -#include "ns3/uinteger.h" -#include "priority-queue.h" - -namespace ns3 { - -NS_LOG_COMPONENT_DEFINE ("PriorityQueue"); - -NS_OBJECT_ENSURE_REGISTERED (PriorityQueue); - -TypeId PriorityQueue::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::PriorityQueue") - .SetParent () - .AddConstructor () - - .AddAttribute ("ControlQueue", - "A queue to use as the transmit queue in the device.", - PointerValue (), - MakePointerAccessor (&PriorityQueue::m_controlQueue), - MakePointerChecker ()) - .AddAttribute ("DataQueue", - "A queue to use as the transmit queue in the device.", - PointerValue (), - MakePointerAccessor (&PriorityQueue::m_dataQueue), - MakePointerChecker ()) - .AddAttribute ("ControlPacketClassifier", - "Pcap style filter to classify control packets", - StringValue (), - MakeStringAccessor (&PriorityQueue::m_classifier), - MakeStringChecker ()) - ; - - return tid; -} - -PriorityQueue::PriorityQueue () : - Queue () -{ - NS_LOG_FUNCTION (this); - - m_pcapHandle = pcap_open_dead (DLT_EN10MB, 1500); - NS_ASSERT_MSG (m_pcapHandle, "failed to open pcap handle"); -} - -PriorityQueue::~PriorityQueue () -{ - NS_LOG_FUNCTION (this); - - m_controlQueue = 0; - m_dataQueue = 0; - - pcap_close (m_pcapHandle); -} - -void -PriorityQueue::Initialize () -{ - NS_LOG_FUNCTION (this); - - int ret = pcap_compile (m_pcapHandle, &m_bpf, - m_classifier.c_str (), 1, PCAP_NETMASK_UNKNOWN); - NS_ASSERT_MSG (ret == 0, "failed to compile control packet classifer"); -} - -void -PriorityQueue::SetControlQueue (Ptr q) -{ - NS_LOG_FUNCTION (this << q); - m_controlQueue = q; -} - -void -PriorityQueue::SetDataQueue (Ptr q) -{ - NS_LOG_FUNCTION (this << q); - m_dataQueue = q; -} - -Ptr -PriorityQueue::GetControlQueue (void) const -{ - NS_LOG_FUNCTION_NOARGS (); - return m_controlQueue; -} - -Ptr -PriorityQueue::GetDataQueue (void) const -{ - NS_LOG_FUNCTION_NOARGS (); - return m_dataQueue; -} - -PriorityQueue::PacketClass -PriorityQueue::Classify (Ptr p) -{ - pcap_pkthdr pcapPkthdr; - pcapPkthdr.caplen = p->GetSize (); - pcapPkthdr.len = p->GetSize (); - uint8_t *data = new uint8_t[p->GetSize ()]; - p->CopyData (data, p->GetSize ()); - int ret = pcap_offline_filter (&m_bpf, &pcapPkthdr, data); - delete [] data; - - if (ret == 0) - { - NS_LOG_DEBUG ("Packet is data packet"); - return PACKET_CLASS_DATA; - } - else - { - NS_LOG_DEBUG ("Packet is control packet"); - return PACKET_CLASS_CONTROL; - } -} - -bool -PriorityQueue::DoEnqueue (Ptr p) -{ - NS_LOG_FUNCTION (this << p); - - PacketClass packetClass = Classify (p); - - if (packetClass == PACKET_CLASS_CONTROL) - { - return m_controlQueue->Enqueue (p); - } - else - { - return m_dataQueue->Enqueue (p); - } -} - -Ptr -PriorityQueue::DoDequeue (void) -{ - NS_LOG_FUNCTION (this); - - Ptr p = 0; - if (!m_controlQueue->IsEmpty ()) - { - p = m_controlQueue->Dequeue (); - } - else - { - p = m_dataQueue->Dequeue (); - } - - return p; -} - -Ptr -PriorityQueue::DoPeek (void) const -{ - NS_LOG_FUNCTION (this); - - Ptr p = 0; - if (!m_controlQueue->IsEmpty ()) - { - p = m_controlQueue->Peek (); - } - else - { - p = m_dataQueue->Peek (); - } - - return p; -} - -} // namespace ns3 - +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * Copyright (c) 2007 University of Washington + * + * 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 + */ + +#include "priority-queue.h" + +namespace ns3 { + +NS_LOG_COMPONENT_DEFINE ("PriorityQueue"); + +NS_OBJECT_TEMPLATE_CLASS_DEFINE (PriorityQueue,Packet); + +} // namespace ns3 diff --git a/model/priority-queue.h b/model/priority-queue.h index 9612b8b..31831f5 100644 --- a/model/priority-queue.h +++ b/model/priority-queue.h @@ -1,121 +1,327 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * Copyright (c) 2007 University of Washington - * - * 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 - */ - -#ifndef PRIORITY_H -#define PRIORITY_H - -#include "ns3/packet.h" -#include "ns3/queue.h" - -#include -#undef DLT_IEEE802_11_RADIO // Avoid namespace collision with ns3::YansWifiPhyHelper::DLT_IEEE802_11_RADIO - -namespace ns3 { - -class TraceContainer; - -/** - * \ingroup queue - * - * \brief A strict priority queue with two subqueues, one for control packets and one for data - */ -class PriorityQueue : public Queue { -public: - /** - * \brief Get the type ID. - * \return the object TypeId - */ - static TypeId GetTypeId (void); - /** - * \brief PriorityQueue Constructor - * - * Creates a priority queue with a maximum size of 100 packets by default - */ - PriorityQueue (); - - virtual ~PriorityQueue(); - - /** - * \brief PriorityQueue Constructor - * - * Initializes priority queue - */ - void Initialize (); - - /** - * Attach a queue to hold data packets to the PriorityQueue. - * - * The PriorityQueue "owns" a sub queue that implements a queueing - * method such as DropTailQueue, DropHeadQueue or RedQueue - * - * \param queue Ptr to the new queue. - */ - void SetDataQueue (Ptr q); - - /** - * Attach a queue to hold control packets to the PriorityQueue. - * - * The PriorityQueue "owns" a sub queue that implements a queueing - * method such as DropTailQueue, DropHeadQueue or RedQueue - * - * \param queue Ptr to the new queue. - */ - void SetControlQueue (Ptr q); - - /** - * Get a copy of the attached Queue that holds control packets. - * - * \returns Ptr to the queue. - */ - Ptr GetControlQueue (void) const; - - /** - * Get a copy of the attached Queue that holds data packets. - * - * \returns Ptr to the queue. - */ - Ptr GetDataQueue (void) const; - - /** - * \brief Enumeration of the modes supported in the class. - * - */ - enum PacketClass - { - PACKET_CLASS_CONTROL, /**< Packet classifier matched packet to control type */ - PACKET_CLASS_DATA, /**< Packet classifier matched packet to control type */ - }; - -private: - virtual bool DoEnqueue (Ptr p); - virtual Ptr DoDequeue (void); - virtual Ptr DoPeek (void) const; - PacketClass Classify (Ptr p); - - Ptr m_controlQueue; //!< queue for control traffic - Ptr m_dataQueue; //!< queue for data traffic - - std::string m_classifier; //!< classfier for control packets - pcap_t * m_pcapHandle; //!< handle for libpcap - struct bpf_program m_bpf; //!< compiled classifier for control packets -}; - -} // namespace ns3 - -#endif /* PRIORITY_H */ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * Copyright (c) 2007 University of Washington + * + * 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 + */ + +#ifndef PRIORITY_QUEUE_H +#define PRIORITY_QUEUE_H + +#include "ns3/log.h" +#include "ns3/string.h" +#include "ns3/pointer.h" +#include "ns3/queue.h" +#include "ns3/packet.h" + +#include + +#undef DLT_IEEE802_11_RADIO // Avoid namespace collision with ns3::YansWifiPhyHelper::DLT_IEEE802_11_RADIO + +namespace ns3 { + +/** + * \ingroup queue + * + * \brief A strict priority queue with two subqueues, one for control packets and one for data + */ +template +class PriorityQueue : public Queue +{ +public: + /** + * \brief Get the type ID. + * \return the object TypeId + */ + static TypeId GetTypeId (void); + /** + * \brief PriorityQueue Constructor + * + * Creates a priority queue with a maximum size of 100 packets by default + */ + PriorityQueue (); + + virtual ~PriorityQueue (); + + /** + * \brief PriorityQueue Constructor + * + * Initializes priority queue + */ + void Initialize (); + + /** + * Attach a queue to hold data packets to the PriorityQueue. + * + * The PriorityQueue "owns" a sub queue that implements a queueing + * method such as DropTailQueue, DropHeadQueue or RedQueue + * + * \param queue Ptr to the new queue. + */ + void SetDataQueue (Ptr> q); + + /** + * Attach a queue to hold control packets to the PriorityQueue. + * + * The PriorityQueue "owns" a sub queue that implements a queueing + * method such as DropTailQueue, DropHeadQueue or RedQueue + * + * \param queue Ptr to the new queue. + */ + void SetControlQueue (Ptr> q); + + /** + * Get a copy of the attached Queue that holds control packets. + * + * \returns Ptr to the queue. + */ + Ptr> GetControlQueue (void) const; + + /** + * Get a copy of the attached Queue that holds data packets. + * + * \returns Ptr to the queue. + */ + Ptr> GetDataQueue (void) const; + + /** + * \brief Enumeration of the modes supported in the class. + * + */ + enum PacketClass + { + PACKET_CLASS_CONTROL, /**< Packet classifier matched packet to control type */ + PACKET_CLASS_DATA, /**< Packet classifier matched packet to control type */ + }; + + virtual bool Enqueue (Ptr item); + virtual Ptr Dequeue (void); + virtual Ptr Remove (void); + virtual Ptr Peek (void) const; + +private: + + PacketClass Classify (Ptr p); + + Ptr> m_controlQueue; //!< queue for control traffic + Ptr> m_dataQueue; //!< queue for data traffic + + std::string m_classifier; //!< classfier for control packets + pcap_t * m_pcapHandle; //!< handle for libpcap + struct bpf_program m_bpf; //!< compiled classifier for control packets + + NS_LOG_TEMPLATE_DECLARE; //!< redefinition of the log component +}; + +/** + * Implementation of the templates declared above. + */ + +template +TypeId +PriorityQueue::GetTypeId (void) +{ + static TypeId tid = TypeId (("ns3::PriorityQueue" + GetTypeParamName > () + ">").c_str ()) + .SetParent> () + .template AddConstructor > () + .AddAttribute ("ControlQueue", + "A queue to use as the transmit queue in the device.", + PointerValue (), + MakePointerAccessor (&PriorityQueue::m_controlQueue), + MakePointerChecker> ()) + .AddAttribute ("DataQueue", + "A queue to use as the transmit queue in the device.", + PointerValue (), + MakePointerAccessor (&PriorityQueue::m_dataQueue), + MakePointerChecker> ()) + .AddAttribute ("ControlPacketClassifier", + "Pcap style filter to classify control packets", + StringValue (), + MakeStringAccessor (&PriorityQueue::m_classifier), + MakeStringChecker ()) + ; + return tid; +} + +template +PriorityQueue::PriorityQueue () : + Queue (), + NS_LOG_TEMPLATE_DEFINE ("PriorityQueue") +{ + NS_LOG_FUNCTION (this); + + m_pcapHandle = pcap_open_dead (DLT_EN10MB, 1500); + NS_ASSERT_MSG (m_pcapHandle, "failed to open pcap handle"); +} + +template +PriorityQueue::~PriorityQueue () +{ + NS_LOG_FUNCTION (this); + + m_controlQueue = 0; + m_dataQueue = 0; + + pcap_close (m_pcapHandle); +} + +template +void +PriorityQueue::Initialize () +{ + NS_LOG_FUNCTION (this); + + int ret = pcap_compile (m_pcapHandle, &m_bpf, + m_classifier.c_str (), 1, PCAP_NETMASK_UNKNOWN); + NS_ASSERT_MSG (ret == 0, "failed to compile control packet classifer"); +} + +template +void +PriorityQueue::SetControlQueue (Ptr> q) +{ + NS_LOG_FUNCTION (this << q); + m_controlQueue = q; +} + +template +void +PriorityQueue::SetDataQueue (Ptr> q) +{ + NS_LOG_FUNCTION (this << q); + m_dataQueue = q; +} + +template +Ptr> +PriorityQueue::GetControlQueue (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_controlQueue; +} + +template +Ptr> +PriorityQueue::GetDataQueue (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_dataQueue; +} + +template +typename PriorityQueue::PacketClass +PriorityQueue::Classify (Ptr p) +{ + pcap_pkthdr pcapPkthdr; + pcapPkthdr.caplen = p->GetSize (); + pcapPkthdr.len = p->GetSize (); + uint8_t *data = new uint8_t[p->GetSize ()]; + p->CopyData (data, p->GetSize ()); + int ret = pcap_offline_filter (&m_bpf, &pcapPkthdr, data); + delete [] data; + + if (ret == 0) + { + NS_LOG_DEBUG ("Packet is data packet"); + return PACKET_CLASS_DATA; + } + else + { + NS_LOG_DEBUG ("Packet is control packet"); + return PACKET_CLASS_CONTROL; + } +} + +template +bool +PriorityQueue::Enqueue (Ptr item) +{ + NS_LOG_FUNCTION (this << item); + + Ptr p= DynamicCast (item); + NS_ABORT_MSG_UNLESS (p, "Class defined for Packet type only"); + + PacketClass packetClass = Classify (p); + + if (packetClass == PACKET_CLASS_CONTROL) + { + return m_controlQueue->Enqueue (item); + } + else + { + return m_dataQueue->Enqueue (item); + } +} + +template +Ptr +PriorityQueue::Dequeue (void) +{ + NS_LOG_FUNCTION (this); + + Ptr item = 0; + if (!m_controlQueue->IsEmpty ()) + { + item = m_controlQueue->Dequeue (); + } + else + { + item = m_dataQueue->Dequeue (); + } + + return item; +} + +template +Ptr +PriorityQueue::Remove (void) +{ + NS_LOG_FUNCTION (this); + + Ptr item = 0; + if (!m_controlQueue->IsEmpty ()) + { + item = m_controlQueue->Remove (); + } + else + { + item = m_dataQueue->Remove (); + } + + return item; +} + +template +Ptr +PriorityQueue::Peek (void) const +{ + NS_LOG_FUNCTION (this); + + Ptr item = 0; + if (!m_controlQueue->IsEmpty ()) + { + item = m_controlQueue->Peek (); + } + else + { + item = m_dataQueue->Peek (); + } + + return item; +} + +} // namespace ns3 + +#endif diff --git a/model/simple-wireless-channel.cc b/model/simple-wireless-channel.cc index ce4e27f..9a558db 100644 --- a/model/simple-wireless-channel.cc +++ b/model/simple-wireless-channel.cc @@ -1,448 +1,452 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * Copyright (c) 2010 University of Washington - * - * 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 - * - */ -#include "ns3/simulator.h" -#include "ns3/packet.h" -#include "ns3/node.h" -#include "ns3/log.h" -#include "ns3/double.h" -#include "ns3/uinteger.h" -#include "ns3/ptr.h" -#include "ns3/mobility-model.h" -#include "simple-wireless-channel.h" -#include "simple-wireless-net-device.h" -#include - -NS_LOG_COMPONENT_DEFINE ("SimpleWirelessChannel"); - -namespace ns3 { - -NS_OBJECT_ENSURE_REGISTERED (SimpleWirelessChannel); - -TypeId -SimpleWirelessChannel::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::SimpleWirelessChannel") - .SetParent () - .AddConstructor () - .AddAttribute ("MaxRange", - "Maximum Transmission Range (meters)", - DoubleValue (250), - MakeDoubleAccessor (&SimpleWirelessChannel::m_range), - MakeDoubleChecker ()) - .AddAttribute ("RangeErrorModel", - "Type or range based error model", - EnumValue (CONSTANT), - MakeEnumAccessor (&SimpleWirelessChannel::m_ErrorModel), - MakeEnumChecker (CONSTANT, "Constant", - PER_CURVE, "PER_CURVE", - STOCHASTIC, "STOCHASTIC")) - .AddAttribute ("RangeErrorRate", - "Error rate when using constant Range Error Model", - StringValue("0.0"), - MakeDoubleAccessor (&SimpleWirelessChannel::m_errorRate), - MakeDoubleChecker ()) - .AddAttribute ("EnableFixedContention", - "Enabled or Disabled", - BooleanValue (false), - MakeBooleanAccessor (&SimpleWirelessChannel::m_fixedContentionEnabled), - MakeBooleanChecker ()) - .AddAttribute ("FixedContentionRange", - "Maximum Range (meters) for Fixed Contention", - DoubleValue (0), // default to 0 so we can use the tx range as default if the user does not set this - MakeDoubleAccessor (&SimpleWirelessChannel::m_fixedContentionRange), - MakeDoubleChecker ()) - .AddAttribute ("AvgLinkUpDuration", - "Average time that the link to a neighbor is up for Stochastic Error Model", - TimeValue (MicroSeconds (10000.0)), - MakeTimeAccessor (&SimpleWirelessChannel::m_upDuration), - MakeTimeChecker ()) - .AddAttribute ("AvgLinkDownDuration", - "Average time that the link to a neighbor is down for Stochastic Error Model", - TimeValue (MicroSeconds (100.0)), - MakeTimeAccessor (&SimpleWirelessChannel::m_downDuration), - MakeTimeChecker ()) - ; - return tid; -} - -SimpleWirelessChannel::SimpleWirelessChannel () -{ - // Default to a constant error model with 0 errors - m_random = CreateObject (); - m_ErrorModel = CONSTANT; - m_errorRate = 0.0; - m_fixedContentionEnabled = false; - m_fixedContentionRange = 0; -} - -void -SimpleWirelessChannel::Send (Ptr p, uint16_t protocol, - Mac48Address to, Mac48Address from, - Ptr sender, Time txTime, uint32_t destId) -{ - NS_LOG_FUNCTION (p << protocol << to << from << sender); - - uint32_t senderNodeId = sender->GetNode()->GetId(); - - if (m_fixedContentionEnabled) - { - sender->ClearNbrCount(); - - // if the range has not been set, use the tx range. - // We do this here because we want the value for range that the user selected value. - // If we set the contention range to m_range in other places (like the call to - // EnableFixedContention), at that point the range could still be the default - // value and not the value the user has set. - if (m_fixedContentionRange == 0) - m_fixedContentionRange = m_range; - } - - for (std::vector >::const_iterator i = m_devices.begin (); i != m_devices.end (); ++i) - { - Ptr tmp = *i; - uint32_t destNodeId = tmp->GetNode()->GetId(); - - // don't send to ourselves - if (tmp == sender) - { - NS_LOG_INFO ("Node " << senderNodeId << " NOT sending to node " << destNodeId << ". Node is self"); - continue; - } - - // See if we have directional networking enabled and if so if this is destination node - if ( (destId != NO_DIRECTIONAL_NBR) && (destNodeId != destId) ) - { - NS_LOG_INFO ("Node " << senderNodeId << " NOT sending to node " << destNodeId << ". Directional networking enabled and node is not destination " << destId); - continue; - } - - // See if we are using stochastic. If so see if the sender's link - // to the destination is up or down - if (CheckStochasticError (senderNodeId, destNodeId)) - { - NS_LOG_INFO ("Node " << senderNodeId << " NOT sending to node " << destNodeId << ". Stochastic error enabled and link to node is in OFF state"); - continue; - } - - Ptr a = sender->GetNode ()->GetObject (); - Ptr b = tmp->GetNode ()->GetObject (); - NS_ASSERT_MSG (a && b, "Error: nodes must have mobility models"); - - // Get distance and determine error rate based on that - // and the error model - double distance = a->GetDistanceFrom (b); - - - // if fixed contention is enabled then we need to peg the neighbor count - if ( (m_fixedContentionEnabled) && (distance < m_fixedContentionRange) ) - { - sender->IncrementNbrCount(); - NS_LOG_INFO ("Node " << senderNodeId << " pegging nbr count for contention. distane is " << distance << ". count is now " << sender->GetNbrCount()); - } - - // Is this packet beyond the transmission range? - if (distance > m_range) - { - NS_LOG_INFO ("Node " << senderNodeId << " NOT sending to node " << destNodeId << ". distance of " << distance << " is out of range"); - continue; - } - - // Is this packet in error or can we send it based on the distance? - if (packetInError(distance)) - { - continue; - } - - // propagation delay. speed of light is 3.3 ns/meter - double propDelay = 3.3 * distance; - NS_LOG_INFO ("Node " << senderNodeId << " sending to node " << destNodeId - << " at distance " << distance << " meters; time (ns): "<< Simulator::Now().GetNanoSeconds () - << " txDelay: " << txTime << " propDelay: " << propDelay); - - Simulator::ScheduleWithContext (destNodeId, NanoSeconds (txTime + propDelay), - &SimpleWirelessNetDevice::Receive, tmp, p->Copy (), protocol, to, from); - - } -} - -void -SimpleWirelessChannel::Add (Ptr device) -{ - m_devices.push_back (device); -} - -uint32_t -SimpleWirelessChannel::GetNDevices (void) const -{ - return m_devices.size (); -} - -Ptr -SimpleWirelessChannel::GetDevice (uint32_t i) const -{ - return m_devices[i]; -} - - -//******************************************************************** -// contention functions -void SimpleWirelessChannel::EnableFixedContention(void) -{ - m_fixedContentionEnabled = true; - - // Set up all the devices to support contention. - // IMPORTANT NOTE: There may not be any devices at this point on the channel. - // If there are not any, then the first packet sent by the device will use the - // full data rate and will not use contention. That is, the device will be notified - // by the channel when the channel gets the first packet from the device and that is - // after the data rate has been used to set the tx time. All subsequent packets sent - // by the device will use contention just not the first one. - for (std::vector >::const_iterator i = m_devices.begin (); i != m_devices.end (); ++i) - { - Ptr tmp = *i; - tmp->ClearNbrCount(); - } -} - -void SimpleWirelessChannel::SetFixedContentionRange(double range) -{ - m_fixedContentionRange = range; -} - -//******************************************************************** -// Error Model functions -void SimpleWirelessChannel::setErrorModelType(ErrorModelType type) -{ - m_ErrorModel = type; - - // reset range to 0 if error model is PER CURVE so that - // we can compare to distances added to the curve to - // get the max range - if (m_ErrorModel == PER_CURVE) - { - m_range = 0; - } -} - -void SimpleWirelessChannel::setErrorRate(double error) -{ - m_errorRate = error; -} - -void SimpleWirelessChannel::addToPERmodel(double distance, double error) -{ - // NOTE: distance is in meters - mPERmap.insert(std::pair(distance, error)); - - if (distance > m_range) - { - m_range = distance; - } -} - - -//******************************************************************** -// Stochastic error functions - -void SimpleWirelessChannel::InitStochasticModel() -{ - // Build the map of neighbor links, setting all links to - // ON state and pick a duration for that state. - if (m_ErrorModel == STOCHASTIC) - { - if (m_devices.size() == 0) - { - NS_LOG_ERROR ("InitStochasticModel called but there are no devices on the channel. Be sure to call InitStochasticModel AFTER devices have been added."); - } - - m_randomUp = CreateObject (); - m_randomDown = CreateObject (); - - m_randomUp->SetAttribute ("Mean", DoubleValue (m_upDuration.GetMicroSeconds())); - m_randomDown->SetAttribute ("Mean", DoubleValue (m_downDuration.GetMicroSeconds())); - - Time currTime = Simulator::Now(); - - for (std::vector >::const_iterator i = m_devices.begin (); i != m_devices.end (); ++i) - { - for (std::vector >::const_iterator j = m_devices.begin (); j != m_devices.end (); ++j) - { - int src = (*i)->GetNode()->GetId(); - int dst = (*j)->GetNode()->GetId(); - - if (src == dst) - continue; - - StochasticLink tempLink; - tempLink.linkState = true; - tempLink.stateExpireTime = currTime + MicroSeconds(m_randomUp->GetValue()); - //tempLink.stateExpireTime = Simulator::Now() + Seconds(1.0); - - m_StochasticLinks.insert(std::pair(StochasticKey(src,dst), tempLink)); - NS_LOG_DEBUG("Add link to stochastic map. src: " << src << " dst: " << dst << " expireTime: " - << std::setprecision (9) << tempLink.stateExpireTime.GetSeconds() << " state: " << tempLink.linkState); - } - } - } -} - - -// This returns true if we should NOT send the packet. -// That is, return true == packet fails to send - -bool SimpleWirelessChannel::CheckStochasticError(uint32_t srcId, uint32_t dstId) -{ - if (m_ErrorModel == STOCHASTIC) - { - // get entry from map for this src/dst pair - StochasIt iter = m_StochasticLinks.find(StochasticKey(srcId, dstId)); - NS_ASSERT( iter != m_StochasticLinks.end()); - - Time currTime = Simulator::Now(); - - //std::cout << std::setprecision (9) << currTime.GetSeconds() << " Checking state for link src: " << srcId << " dst: " << dstId << " expireTime: " << iter->second.stateExpireTime << std::endl; - - if (currTime >= iter->second.stateExpireTime) - { - // the time at which the previous state was set to end has already passed. - Time endTime = iter->second.stateExpireTime; - bool tempState = iter->second.linkState; - Time newDuration; - // Pick the new states until we get to one that is at or greater - // than the current time. - while (endTime < currTime) - { - // Now pick duration for the new state - if (!tempState) - { - newDuration = MicroSeconds(m_randomUp->GetValue()); - } - else - { - newDuration = MicroSeconds(m_randomDown->GetValue()); - } - endTime += newDuration; - tempState = !tempState; - - NS_LOG_DEBUG("---> " << std::setprecision (9) << currTime.GetSeconds() << " next state: " << tempState << " for link src: " << srcId << " dst: " << dstId - << " duration of next state: " << std::setprecision (9) << newDuration.GetSeconds() - << " expireTime: " << std::setprecision (9) << endTime.GetSeconds()); - } - - // When we get here, the new state and time are selected - iter->second.linkState = tempState; - iter->second.stateExpireTime = endTime; - - NS_LOG_DEBUG(std::setprecision (9) << currTime.GetSeconds() << " New state " << iter->second.linkState << " for link src: " << srcId << " dst: " << dstId - << " duration of next state: " << std::setprecision (9) << newDuration.GetSeconds() - << " expireTime: " << std::setprecision (9) << iter->second.stateExpireTime.GetSeconds()); - - } - else - { - NS_LOG_DEBUG(std::setprecision (9) << currTime.GetSeconds() << " State " << iter->second.linkState << " for link src: " << srcId << " dst: " << dstId - << " expireTime: " << std::setprecision (9) << iter->second.stateExpireTime.GetSeconds()); - } - - // now return true or false depending on state - // true = packet is in "error" and failes - // false = packet not in error and sends - if (iter->second.linkState) - { - return false; - } - else - { - return true; - } - } - else - { - return false; - } -} - -//******************************************************************** - -bool SimpleWirelessChannel::packetInError(double distance) -{ - std::map::iterator it; - std::map::iterator up_iter; - std::map::iterator low_iter; - - if (m_ErrorModel == CONSTANT) - { - if ( m_random->GetValue () < m_errorRate ) - { - NS_LOG_INFO("Error Model: " << m_ErrorModel << " Checking for error at distance: " << distance << " Too high error. Packet in error."); - return true; - } - } - else if (m_ErrorModel == PER_CURVE) - { - it = mPERmap.find(distance); - if (it != mPERmap.end()) - { - // we found an exact match in the map for this distance - if (m_random->GetValue() < it->second) - { - NS_LOG_INFO("Error Model: " << m_ErrorModel << " Checking for error at distance: " << distance << " Too high error. Packet in error."); - return true; - } - } - else - { - // we did not find an exact match in the map. That's OK - // since it could actually be unlikely to find one. - // Now we just extrapolate between the two entries in the map - - // first get iterator to upper bound - up_iter = mPERmap.upper_bound(distance); - if (up_iter == mPERmap.end()) - { - // We shouldn't hit this situation because we already checked the distance - // relative to the range but go ahead and leave this here - // this distance is beyond the upper bound so error is 100% - NS_LOG_INFO("Error Model: " << m_ErrorModel << " Checking for error at distance: " << distance << " Too high error. Packet in error."); - return true; - } - - // Set low iter to upper then decrement it - low_iter = up_iter; - --low_iter; - - double errorRate = low_iter->second + ( ((distance - low_iter->first)/(up_iter->first - low_iter->first)) * (up_iter->second - low_iter->second)); - NS_LOG_INFO("Error Model: " << m_ErrorModel << " distance: " << distance << " calculated error rate: " << errorRate << " low distance: " << low_iter->first << " low error: " << low_iter->second - << " high distance: " << up_iter->first << " high error: " << up_iter->second); - - if (m_random->GetValue() < errorRate) - { - return true; - } - } - } - - - // if we get here then there were no errors - return false; -} - - -} // namespace ns3 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * Copyright (c) 2010 University of Washington + * + * 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 + * + */ +#include "ns3/simulator.h" +#include "ns3/packet.h" +#include "ns3/node.h" +#include "ns3/log.h" +#include "ns3/double.h" +#include "ns3/uinteger.h" +#include "ns3/ptr.h" +#include "ns3/mobility-model.h" +#include "simple-wireless-channel.h" +#include "simple-wireless-net-device.h" +#include + +NS_LOG_COMPONENT_DEFINE ("SimpleWirelessChannel"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (SimpleWirelessChannel); + +TypeId +SimpleWirelessChannel::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SimpleWirelessChannel") + .SetParent () + .AddConstructor () + .AddAttribute ("MaxRange", + "Maximum Transmission Range (meters)", + DoubleValue (250), + MakeDoubleAccessor (&SimpleWirelessChannel::m_range), + MakeDoubleChecker ()) + .AddAttribute ("RangeErrorModel", + "Type or range based error model", + EnumValue (CONSTANT), + MakeEnumAccessor (&SimpleWirelessChannel::m_ErrorModel), + MakeEnumChecker (CONSTANT, "Constant", + PER_CURVE, "PER_CURVE", + STOCHASTIC, "STOCHASTIC")) + .AddAttribute ("RangeErrorRate", + "Error rate when using constant Range Error Model", + StringValue ("0.0"), + MakeDoubleAccessor (&SimpleWirelessChannel::m_errorRate), + MakeDoubleChecker ()) + .AddAttribute ("EnableFixedContention", + "Enabled or Disabled", + BooleanValue (false), + MakeBooleanAccessor (&SimpleWirelessChannel::m_fixedContentionEnabled), + MakeBooleanChecker ()) + .AddAttribute ("FixedContentionRange", + "Maximum Range (meters) for Fixed Contention", + DoubleValue (0), // default to 0 so we can use the tx range as default if the user does not set this + MakeDoubleAccessor (&SimpleWirelessChannel::m_fixedContentionRange), + MakeDoubleChecker ()) + .AddAttribute ("AvgLinkUpDuration", + "Average time that the link to a neighbor is up for Stochastic Error Model", + TimeValue (MicroSeconds (10000.0)), + MakeTimeAccessor (&SimpleWirelessChannel::m_upDuration), + MakeTimeChecker ()) + .AddAttribute ("AvgLinkDownDuration", + "Average time that the link to a neighbor is down for Stochastic Error Model", + TimeValue (MicroSeconds (100.0)), + MakeTimeAccessor (&SimpleWirelessChannel::m_downDuration), + MakeTimeChecker ()) + ; + return tid; +} + +SimpleWirelessChannel::SimpleWirelessChannel () +{ + // Default to a constant error model with 0 errors + m_random = CreateObject (); + m_ErrorModel = CONSTANT; + m_errorRate = 0.0; + m_fixedContentionEnabled = false; + m_fixedContentionRange = 0; +} + +void +SimpleWirelessChannel::Send (Ptr p, uint16_t protocol, + Mac48Address to, Mac48Address from, + Ptr sender, Time txTime, uint32_t destId) +{ + NS_LOG_FUNCTION (p << protocol << to << from << sender); + + uint32_t senderNodeId = sender->GetNode ()->GetId (); + + if (m_fixedContentionEnabled) + { + sender->ClearNbrCount (); + + // if the range has not been set, use the tx range. + // We do this here because we want the value for range that the user selected value. + // If we set the contention range to m_range in other places (like the call to + // EnableFixedContention), at that point the range could still be the default + // value and not the value the user has set. + if (m_fixedContentionRange == 0) + { + m_fixedContentionRange = m_range; + } + } + + for (std::vector >::const_iterator i = m_devices.begin (); i != m_devices.end (); ++i) + { + Ptr tmp = *i; + uint32_t destNodeId = tmp->GetNode ()->GetId (); + + // don't send to ourselves + if (tmp == sender) + { + NS_LOG_INFO ("Node " << senderNodeId << " NOT sending to node " << destNodeId << ". Node is self"); + continue; + } + + // See if we have directional networking enabled and if so if this is destination node + if ( (destId != NO_DIRECTIONAL_NBR) && (destNodeId != destId) ) + { + NS_LOG_INFO ("Node " << senderNodeId << " NOT sending to node " << destNodeId << ". Directional networking enabled and node is not destination " << destId); + continue; + } + + // See if we are using stochastic. If so see if the sender's link + // to the destination is up or down + if (CheckStochasticError (senderNodeId, destNodeId)) + { + NS_LOG_INFO ("Node " << senderNodeId << " NOT sending to node " << destNodeId << ". Stochastic error enabled and link to node is in OFF state"); + continue; + } + + Ptr a = sender->GetNode ()->GetObject (); + Ptr b = tmp->GetNode ()->GetObject (); + NS_ASSERT_MSG (a && b, "Error: nodes must have mobility models"); + + // Get distance and determine error rate based on that + // and the error model + double distance = a->GetDistanceFrom (b); + + + // if fixed contention is enabled then we need to peg the neighbor count + if ( (m_fixedContentionEnabled) && (distance < m_fixedContentionRange) ) + { + sender->IncrementNbrCount (); + NS_LOG_INFO ("Node " << senderNodeId << " pegging nbr count for contention. distane is " << distance << ". count is now " << sender->GetNbrCount ()); + } + + // Is this packet beyond the transmission range? + if (distance > m_range) + { + NS_LOG_INFO ("Node " << senderNodeId << " NOT sending to node " << destNodeId << ". distance of " << distance << " is out of range"); + continue; + } + + // Is this packet in error or can we send it based on the distance? + if (packetInError (distance)) + { + continue; + } + + // propagation delay. speed of light is 3.3 ns/meter + double propDelay = 3.3 * distance; + NS_LOG_INFO ("Node " << senderNodeId << " sending to node " << destNodeId + << " at distance " << distance << " meters; time (ns): " << Simulator::Now ().GetNanoSeconds () + << " txDelay: " << txTime << " propDelay: " << propDelay); + + Simulator::ScheduleWithContext (destNodeId, NanoSeconds (txTime + propDelay), + &SimpleWirelessNetDevice::Receive, tmp, p->Copy (), protocol, to, from); + + } +} + +void +SimpleWirelessChannel::Add (Ptr device) +{ + m_devices.push_back (device); +} + +std::size_t +SimpleWirelessChannel::GetNDevices (void) const +{ + return m_devices.size (); +} + +Ptr +SimpleWirelessChannel::GetDevice (std::size_t i) const +{ + return m_devices[i]; +} + + +//******************************************************************** +// contention functions +void SimpleWirelessChannel::EnableFixedContention (void) +{ + m_fixedContentionEnabled = true; + + // Set up all the devices to support contention. + // IMPORTANT NOTE: There may not be any devices at this point on the channel. + // If there are not any, then the first packet sent by the device will use the + // full data rate and will not use contention. That is, the device will be notified + // by the channel when the channel gets the first packet from the device and that is + // after the data rate has been used to set the tx time. All subsequent packets sent + // by the device will use contention just not the first one. + for (std::vector >::const_iterator i = m_devices.begin (); i != m_devices.end (); ++i) + { + Ptr tmp = *i; + tmp->ClearNbrCount (); + } +} + +void SimpleWirelessChannel::SetFixedContentionRange (double range) +{ + m_fixedContentionRange = range; +} + +//******************************************************************** +// Error Model functions +void SimpleWirelessChannel::setErrorModelType (ErrorModelType type) +{ + m_ErrorModel = type; + + // reset range to 0 if error model is PER CURVE so that + // we can compare to distances added to the curve to + // get the max range + if (m_ErrorModel == PER_CURVE) + { + m_range = 0; + } +} + +void SimpleWirelessChannel::setErrorRate (double error) +{ + m_errorRate = error; +} + +void SimpleWirelessChannel::addToPERmodel (double distance, double error) +{ + // NOTE: distance is in meters + mPERmap.insert (std::pair (distance, error)); + + if (distance > m_range) + { + m_range = distance; + } +} + + +//******************************************************************** +// Stochastic error functions + +void SimpleWirelessChannel::InitStochasticModel () +{ + // Build the map of neighbor links, setting all links to + // ON state and pick a duration for that state. + if (m_ErrorModel == STOCHASTIC) + { + if (m_devices.size () == 0) + { + NS_LOG_ERROR ("InitStochasticModel called but there are no devices on the channel. Be sure to call InitStochasticModel AFTER devices have been added."); + } + + m_randomUp = CreateObject (); + m_randomDown = CreateObject (); + + m_randomUp->SetAttribute ("Mean", DoubleValue (m_upDuration.GetMicroSeconds ())); + m_randomDown->SetAttribute ("Mean", DoubleValue (m_downDuration.GetMicroSeconds ())); + + Time currTime = Simulator::Now (); + + for (std::vector >::const_iterator i = m_devices.begin (); i != m_devices.end (); ++i) + { + for (std::vector >::const_iterator j = m_devices.begin (); j != m_devices.end (); ++j) + { + int src = (*i)->GetNode ()->GetId (); + int dst = (*j)->GetNode ()->GetId (); + + if (src == dst) + { + continue; + } + + StochasticLink tempLink; + tempLink.linkState = true; + tempLink.stateExpireTime = currTime + MicroSeconds (m_randomUp->GetValue ()); + //tempLink.stateExpireTime = Simulator::Now() + Seconds(1.0); + + m_StochasticLinks.insert (std::pair (StochasticKey (src,dst), tempLink)); + NS_LOG_DEBUG ("Add link to stochastic map. src: " << src << " dst: " << dst << " expireTime: " + << std::setprecision (9) << tempLink.stateExpireTime.GetSeconds () << " state: " << tempLink.linkState); + } + } + } +} + + +// This returns true if we should NOT send the packet. +// That is, return true == packet fails to send + +bool SimpleWirelessChannel::CheckStochasticError (uint32_t srcId, uint32_t dstId) +{ + if (m_ErrorModel == STOCHASTIC) + { + // get entry from map for this src/dst pair + StochasIt iter = m_StochasticLinks.find (StochasticKey (srcId, dstId)); + NS_ASSERT ( iter != m_StochasticLinks.end ()); + + Time currTime = Simulator::Now (); + + //std::cout << std::setprecision (9) << currTime.GetSeconds() << " Checking state for link src: " << srcId << " dst: " << dstId << " expireTime: " << iter->second.stateExpireTime << std::endl; + + if (currTime >= iter->second.stateExpireTime) + { + // the time at which the previous state was set to end has already passed. + Time endTime = iter->second.stateExpireTime; + bool tempState = iter->second.linkState; + Time newDuration; + // Pick the new states until we get to one that is at or greater + // than the current time. + while (endTime < currTime) + { + // Now pick duration for the new state + if (!tempState) + { + newDuration = MicroSeconds (m_randomUp->GetValue ()); + } + else + { + newDuration = MicroSeconds (m_randomDown->GetValue ()); + } + endTime += newDuration; + tempState = !tempState; + + NS_LOG_DEBUG ("---> " << std::setprecision (9) << currTime.GetSeconds () << " next state: " << tempState << " for link src: " << srcId << " dst: " << dstId + << " duration of next state: " << std::setprecision (9) << newDuration.GetSeconds () + << " expireTime: " << std::setprecision (9) << endTime.GetSeconds ()); + } + + // When we get here, the new state and time are selected + iter->second.linkState = tempState; + iter->second.stateExpireTime = endTime; + + NS_LOG_DEBUG (std::setprecision (9) << currTime.GetSeconds () << " New state " << iter->second.linkState << " for link src: " << srcId << " dst: " << dstId + << " duration of next state: " << std::setprecision (9) << newDuration.GetSeconds () + << " expireTime: " << std::setprecision (9) << iter->second.stateExpireTime.GetSeconds ()); + + } + else + { + NS_LOG_DEBUG (std::setprecision (9) << currTime.GetSeconds () << " State " << iter->second.linkState << " for link src: " << srcId << " dst: " << dstId + << " expireTime: " << std::setprecision (9) << iter->second.stateExpireTime.GetSeconds ()); + } + + // now return true or false depending on state + // true = packet is in "error" and failes + // false = packet not in error and sends + if (iter->second.linkState) + { + return false; + } + else + { + return true; + } + } + else + { + return false; + } +} + +//******************************************************************** + +bool SimpleWirelessChannel::packetInError (double distance) +{ + std::map::iterator it; + std::map::iterator up_iter; + std::map::iterator low_iter; + + if (m_ErrorModel == CONSTANT) + { + if ( m_random->GetValue () < m_errorRate ) + { + NS_LOG_INFO ("Error Model: " << m_ErrorModel << " Checking for error at distance: " << distance << " Too high error. Packet in error."); + return true; + } + } + else if (m_ErrorModel == PER_CURVE) + { + it = mPERmap.find (distance); + if (it != mPERmap.end ()) + { + // we found an exact match in the map for this distance + if (m_random->GetValue () < it->second) + { + NS_LOG_INFO ("Error Model: " << m_ErrorModel << " Checking for error at distance: " << distance << " Too high error. Packet in error."); + return true; + } + } + else + { + // we did not find an exact match in the map. That's OK + // since it could actually be unlikely to find one. + // Now we just extrapolate between the two entries in the map + + // first get iterator to upper bound + up_iter = mPERmap.upper_bound (distance); + if (up_iter == mPERmap.end ()) + { + // We shouldn't hit this situation because we already checked the distance + // relative to the range but go ahead and leave this here + // this distance is beyond the upper bound so error is 100% + NS_LOG_INFO ("Error Model: " << m_ErrorModel << " Checking for error at distance: " << distance << " Too high error. Packet in error."); + return true; + } + + // Set low iter to upper then decrement it + low_iter = up_iter; + --low_iter; + + double errorRate = low_iter->second + ( ((distance - low_iter->first) / (up_iter->first - low_iter->first)) * (up_iter->second - low_iter->second)); + NS_LOG_INFO ("Error Model: " << m_ErrorModel << " distance: " << distance << " calculated error rate: " << errorRate << " low distance: " << low_iter->first << " low error: " << low_iter->second + << " high distance: " << up_iter->first << " high error: " << up_iter->second); + + if (m_random->GetValue () < errorRate) + { + return true; + } + } + } + + + // if we get here then there were no errors + return false; +} + + +} // namespace ns3 diff --git a/model/simple-wireless-channel.h b/model/simple-wireless-channel.h index d71cd4a..7ca46b7 100644 --- a/model/simple-wireless-channel.h +++ b/model/simple-wireless-channel.h @@ -1,143 +1,147 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * Copyright (c) 2010 University of Washington - * - * 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 - * - */ -#ifndef SIMPLE_WIRELESS_CHANNEL_H -#define SIMPLE_WIRELESS_CHANNEL_H - -#include -#include "ns3/channel.h" -#include "ns3/mac48-address.h" -#include "ns3/random-variable-stream.h" -#include "ns3/enum.h" -#include "ns3/string.h" - - - -namespace ns3 { - -class SimpleWirelessNetDevice; -class Packet; - -enum ErrorModelType { - /** - * In Constant mode, the packet error rate is constant within the - * specified distance range. - */ - CONSTANT, - /** - * In PER Curve mode, the packet error curves are used to - * determine the error rate. The distance is used to look up the - * error rate. Note that the range value specified is ignored. - * User must build the PER curve by calling addToPERmodel. - */ - PER_CURVE, - /** - * In Stochastic mode, there are no per packet errors. Instead, - * the link to each neighbor is either on or off for randomly - * selected durations. - */ - STOCHASTIC -}; - -//*************************************************************** -// Define key for stochastic error map key -//*************************************************************** -class StochasticKey { - public: - int srcNodeId; - int destNodeId; - - StochasticKey(int k1, int k2) - : srcNodeId(k1), destNodeId(k2){} - - // Ordering is: - // 1. lowest source node id - // 2. lowest destination node id - - bool operator<(const StochasticKey &right) const - { - if (srcNodeId == right.srcNodeId) - { - return(destNodeId < right.destNodeId); - } - else - { - return (srcNodeId < right.srcNodeId); - } - } -}; - -struct StochasticLink -{ - bool linkState; // 1 = ON, 0 = OFF - Time stateExpireTime; -}; - -typedef std::map ::iterator StochasIt; - -/** - * \ingroup channel - * \brief A simple channel, for simple things and testing - */ -class SimpleWirelessChannel : public Channel -{ -public: - static TypeId GetTypeId (void); - SimpleWirelessChannel (); - - void Send (Ptr p, uint16_t protocol, Mac48Address to, Mac48Address from, - Ptr sender, Time txTime, uint32_t destId); - - void Add (Ptr device); - - // inherited from ns3::Channel - virtual uint32_t GetNDevices (void) const; - virtual Ptr GetDevice (uint32_t i) const; - - void setErrorModelType(ErrorModelType type); - void setErrorRate(double error); - void addToPERmodel(double distance, double error); - bool packetInError(double distance); - void EnableFixedContention(void); - void SetFixedContentionRange(double error); - void InitStochasticModel(); - bool CheckStochasticError(uint32_t srcId, uint32_t dstId); - -private: - std::vector > m_devices; - double m_range; - double m_errorRate; - ErrorModelType m_ErrorModel; - Ptr m_random; - std::map mPERmap; - - bool m_fixedContentionEnabled; - double m_fixedContentionRange; - Ptr m_randomUp; - Ptr m_randomDown; - - Time m_upDuration; - Time m_downDuration; - std::map m_StochasticLinks; - -}; - -} // namespace ns3 - -#endif /* SIMPLE_WIRELESS_CHANNEL_H */ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * Copyright (c) 2010 University of Washington + * + * 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 + * + */ +#ifndef SIMPLE_WIRELESS_CHANNEL_H +#define SIMPLE_WIRELESS_CHANNEL_H + +#include +#include "ns3/channel.h" +#include "ns3/mac48-address.h" +#include "ns3/random-variable-stream.h" +#include "ns3/enum.h" +#include "ns3/string.h" + + + +namespace ns3 { + +class SimpleWirelessNetDevice; +class Packet; + +enum ErrorModelType +{ + /** + * In Constant mode, the packet error rate is constant within the + * specified distance range. + */ + CONSTANT, + /** + * In PER Curve mode, the packet error curves are used to + * determine the error rate. The distance is used to look up the + * error rate. Note that the range value specified is ignored. + * User must build the PER curve by calling addToPERmodel. + */ + PER_CURVE, + /** + * In Stochastic mode, there are no per packet errors. Instead, + * the link to each neighbor is either on or off for randomly + * selected durations. + */ + STOCHASTIC +}; + +//*************************************************************** +// Define key for stochastic error map key +//*************************************************************** +class StochasticKey +{ +public: + int srcNodeId; + int destNodeId; + + StochasticKey (int k1, int k2) + : srcNodeId (k1), destNodeId (k2) + { + } + + // Ordering is: + // 1. lowest source node id + // 2. lowest destination node id + + bool operator< (const StochasticKey &right) const + { + if (srcNodeId == right.srcNodeId) + { + return(destNodeId < right.destNodeId); + } + else + { + return (srcNodeId < right.srcNodeId); + } + } +}; + +struct StochasticLink +{ + bool linkState; // 1 = ON, 0 = OFF + Time stateExpireTime; +}; + +typedef std::map ::iterator StochasIt; + +/** + * \ingroup channel + * \brief A simple channel, for simple things and testing + */ +class SimpleWirelessChannel : public Channel +{ +public: + static TypeId GetTypeId (void); + SimpleWirelessChannel (); + + void Send (Ptr p, uint16_t protocol, Mac48Address to, Mac48Address from, + Ptr sender, Time txTime, uint32_t destId); + + void Add (Ptr device); + + // inherited from ns3::Channel + virtual std::size_t GetNDevices (void) const; + virtual Ptr GetDevice (std::size_t i) const; + + void setErrorModelType (ErrorModelType type); + void setErrorRate (double error); + void addToPERmodel (double distance, double error); + bool packetInError (double distance); + void EnableFixedContention (void); + void SetFixedContentionRange (double error); + void InitStochasticModel (); + bool CheckStochasticError (uint32_t srcId, uint32_t dstId); + +private: + std::vector > m_devices; + double m_range; + double m_errorRate; + ErrorModelType m_ErrorModel; + Ptr m_random; + std::map mPERmap; + + bool m_fixedContentionEnabled; + double m_fixedContentionRange; + Ptr m_randomUp; + Ptr m_randomDown; + + Time m_upDuration; + Time m_downDuration; + std::map m_StochasticLinks; + +}; + +} // namespace ns3 + +#endif /* SIMPLE_WIRELESS_CHANNEL_H */ diff --git a/model/simple-wireless-net-device.cc b/model/simple-wireless-net-device.cc index 8a5803d..d115a0d 100644 --- a/model/simple-wireless-net-device.cc +++ b/model/simple-wireless-net-device.cc @@ -1,877 +1,891 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * Copyright (c) 2010 University of Washington - * - * 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 - * - */ -#include "ns3/node.h" -#include "ns3/packet.h" -#include "ns3/log.h" -#include "ns3/pointer.h" -#include "ns3/error-model.h" -#include "ns3/trace-source-accessor.h" -#include "simple-wireless-net-device.h" -#include "simple-wireless-channel.h" - -#include // needed for noth for protocol # in sniffer - -NS_LOG_COMPONENT_DEFINE ("SimpleWirelessNetDevice"); - -namespace ns3 { - -NS_OBJECT_ENSURE_REGISTERED (SimpleWirelessNetDevice); - -//******************************************************** -// TimestampTag used to store a timestamp with a packet -// when they are placed in the queue -//******************************************************** -TypeId TimestampTag::GetTypeId (void) -{ - static TypeId tid = TypeId ("TimestampTag") - .SetParent () - .AddConstructor () - .AddAttribute ("Timestamp", - "Some momentous point in time!", - EmptyAttributeValue (), - MakeTimeAccessor (&TimestampTag::GetTimestamp), - MakeTimeChecker ()) - ; - return tid; -} - -TypeId TimestampTag::GetInstanceTypeId (void) const -{ - return GetTypeId (); -} - -uint32_t TimestampTag::GetSerializedSize (void) const -{ - return 8; -} - -void TimestampTag::Serialize (TagBuffer i) const -{ - int64_t t = m_timestamp.GetNanoSeconds (); - i.Write ((const uint8_t *)&t, 8); -} - -void TimestampTag::Deserialize (TagBuffer i) -{ - int64_t t; - i.Read ((uint8_t *)&t, 8); - m_timestamp = NanoSeconds (t); -} - -void TimestampTag::SetTimestamp (Time time) -{ - m_timestamp = time; -} - -Time TimestampTag::GetTimestamp (void) const -{ - return m_timestamp; -} - -void TimestampTag::Print (std::ostream &os) const -{ - os << "t=" << m_timestamp; -} - -//******************************************************** - -//******************************************************** -// DestinationIdTag used to store a destination node id -// with a packet when they are placed in the queue. -// This is used by directional networks. -//******************************************************** -TypeId DestinationIdTag::GetTypeId (void) -{ - static TypeId tid = TypeId ("DestinationIdTag") - .SetParent () - .AddConstructor () - ; - return tid; -} - -TypeId DestinationIdTag::GetInstanceTypeId (void) const -{ - return GetTypeId (); -} - -DestinationIdTag::DestinationIdTag () -{ -} - -DestinationIdTag::DestinationIdTag (uint32_t destId) - : m_destnodeid (destId) -{ -} - -uint32_t DestinationIdTag::GetSerializedSize (void) const -{ - return 4; -} - -void DestinationIdTag::Serialize (TagBuffer i) const -{ - i.WriteU32 (m_destnodeid); -} - -void DestinationIdTag::Deserialize (TagBuffer i) -{ - m_destnodeid = i.ReadU32 (); -} - -void DestinationIdTag::SetDestinationId (uint32_t id) -{ - m_destnodeid = id; -} - -uint32_t DestinationIdTag::GetDestinationId (void) const -{ - return m_destnodeid; -} - -void DestinationIdTag::Print (std::ostream &os) const -{ - os << "t=" << m_destnodeid; -} - -//******************************************************** - -TypeId -SimpleWirelessNetDevice::GetTypeId (void) -{ - static TypeId tid = TypeId ("ns3::SimpleWirelessNetDevice") - .SetParent () - .AddConstructor () - .AddAttribute ("ReceiveErrorModel", - "The receiver error model used to simulate packet loss", - PointerValue (), - MakePointerAccessor (&SimpleWirelessNetDevice::m_receiveErrorModel), - MakePointerChecker ()) - .AddAttribute ("DataRate", - "The default data rate for point to point links", - DataRateValue (DataRate ("1000000b/s")), - MakeDataRateAccessor (&SimpleWirelessNetDevice::m_bps), - MakeDataRateChecker ()) - // Transmit queueing discipline for the device which includes its own set - // of trace hooks. - .AddAttribute ("TxQueue", - "A queue to use as the transmit queue in the device.", - PointerValue (), - MakePointerAccessor (&SimpleWirelessNetDevice::m_queue), - MakePointerChecker ()) - .AddAttribute ("FixedNeighborListEnabled", - "Enabled or Disabled", - BooleanValue (false), - MakeBooleanAccessor (&SimpleWirelessNetDevice::m_fixedNbrListEnabled), - MakeBooleanChecker ()) - .AddTraceSource ("PhyTxBegin", - "Trace source indicating a packet has begun transmitting", - MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_TxBeginTrace)) - .AddTraceSource ("PhyRxDrop", - "Trace source indicating a packet has been dropped by the device during reception", - MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_phyRxDropTrace)) - .AddTraceSource ("PhyRxBegin", - "Trace source indicating a packet " - "has begun being received from the channel medium " - "by the device", - MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_phyRxBeginTrace)) - .AddTraceSource ("PhyRxEnd", - "Trace source indicating a packet " - "has been completely received from the channel medium " - "by the device", - MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_phyRxEndTrace)) - // Trace sources designed to simulate a packet sniffer facility (tcpdump). - .AddTraceSource ("PromiscSniffer", - "Trace source simulating a promiscuous packet sniffer attached to the device", - MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_promiscSnifferTrace)) - .AddTraceSource ("QueueLatency", - "Trace source to report the latency of a packet in the queue. Datatype returned is Time.", - MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_QueueLatencyTrace)) - .AddTraceSource ("MacTx", - "A packet has been received from higher layers and is being processed in preparation for " - "queueing for transmission.", - MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_macTxTrace)) - .AddTraceSource ("MacRx", - "A packet has been received by this device, has been passed up from the physical layer " - "and is being forwarded up the local protocol stack. This is a non-promiscuous trace,", - MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_macRxTrace)) - ; - return tid; -} - -SimpleWirelessNetDevice::SimpleWirelessNetDevice () - : m_channel (0), - m_node (0), - m_mtu (0xffff), - m_ifIndex (0), - m_txMachineState (READY), - m_queue(NULL), - m_pktRcvTotal(0), - m_pktRcvDrop(0), - m_pcapEnabled(false), - m_fixedNbrListEnabled(false), - m_nbrCount(0) - -{} - -void -SimpleWirelessNetDevice::Receive (Ptr packet, uint16_t protocol, - Mac48Address to, Mac48Address from) -{ - NS_LOG_FUNCTION (packet << protocol << to << from); - NetDevice::PacketType packetType; - - m_phyRxBeginTrace (packet, from, to, protocol); - m_pktRcvTotal++; - - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " receiving packet " << packet->GetUid () << " from " << from << " to " << to ); - - if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) ) - { - m_phyRxDropTrace (packet, from, to, protocol); - m_pktRcvDrop++; - return; - } - - if (m_pcapEnabled) - { - // Add the ethernet header to the packet for sniffer - // For some reason the Ethernet header is STRIPPED from the packet - // by the time we get here so we need to reconstruct it for the - // sniffer. - // allocate buffer for packet and mac addresses - uint8_t buffer[8192]; - uint8_t macBuffer[6]; - // get the dest and src addresses and copy into the buffer - to.CopyTo(macBuffer); - memcpy(&buffer[0], macBuffer, 6); - from.CopyTo(macBuffer); - memcpy(&buffer[6], macBuffer, 6); - //copy the protocol and the actual packet data in the the buffer - uint16_t tempProt = ntohs(protocol); - memcpy(&buffer[12], &tempProt, 2); - packet->CopyData(&buffer[14], packet->GetSize()); - // Now make a new temp packet to write to the sniffer - Ptr tempPacket = Create (buffer, packet->GetSize() + 14); - m_promiscSnifferTrace (tempPacket); - } - - if (to == m_address) - { - packetType = NetDevice::PACKET_HOST; - } - else if (to.IsBroadcast ()) - { - packetType = NetDevice::PACKET_BROADCAST; - } - else if (to.IsGroup ()) - { - packetType = NetDevice::PACKET_MULTICAST; - } - else - { - packetType = NetDevice::PACKET_OTHERHOST; - } - - m_phyRxEndTrace (packet, from, to, protocol); - - if (packetType != NetDevice::PACKET_OTHERHOST) - { - m_macRxTrace (packet); - m_rxCallback (this, packet, protocol, from); - } - - - if (!m_promiscCallback.IsNull ()) - { - m_promiscCallback (this, packet, protocol, from, to, packetType); - } - NS_LOG_DEBUG ("Total Rcvd: " << m_pktRcvTotal << " Total Dropped: " << m_pktRcvDrop); -} - -void -SimpleWirelessNetDevice::SetChannel (Ptr channel) -{ - m_channel = channel; - m_channel->Add (this); -} - -void -SimpleWirelessNetDevice::SetReceiveErrorModel (Ptr em) -{ - m_receiveErrorModel = em; -} - -void -SimpleWirelessNetDevice::SetIfIndex(const uint32_t index) -{ - m_ifIndex = index; -} -uint32_t -SimpleWirelessNetDevice::GetIfIndex(void) const -{ - return m_ifIndex; -} -Ptr -SimpleWirelessNetDevice::GetChannel (void) const -{ - return m_channel; -} -void -SimpleWirelessNetDevice::SetAddress (Address address) -{ - m_address = Mac48Address::ConvertFrom(address); -} -Address -SimpleWirelessNetDevice::GetAddress (void) const -{ - // - // Implicit conversion from Mac48Address to Address - // - return m_address; -} -bool -SimpleWirelessNetDevice::SetMtu (const uint16_t mtu) -{ - m_mtu = mtu; - return true; -} -uint16_t -SimpleWirelessNetDevice::GetMtu (void) const -{ - return m_mtu; -} -bool -SimpleWirelessNetDevice::IsLinkUp (void) const -{ - return true; -} -void -SimpleWirelessNetDevice::AddLinkChangeCallback (Callback callback) -{} -bool -SimpleWirelessNetDevice::IsBroadcast (void) const -{ - return true; -} -Address -SimpleWirelessNetDevice::GetBroadcast (void) const -{ - return Mac48Address ("ff:ff:ff:ff:ff:ff"); -} -bool -SimpleWirelessNetDevice::IsMulticast (void) const -{ - return false; -} -Address -SimpleWirelessNetDevice::GetMulticast (Ipv4Address multicastGroup) const -{ - return Mac48Address::GetMulticast (multicastGroup); -} - -Address SimpleWirelessNetDevice::GetMulticast (Ipv6Address addr) const -{ - return Mac48Address::GetMulticast (addr); -} - -bool -SimpleWirelessNetDevice::IsPointToPoint (void) const -{ - return false; -} - -bool -SimpleWirelessNetDevice::IsBridge (void) const -{ - return false; -} - -//******************************************************************** -// Directional Neighbor functions -bool SimpleWirelessNetDevice::AddDirectionalNeighbors(std::map nodesToAdd) -{ - // is directional neighbor feature enabled? - // If not return false so caller knows there is a problem - if (!m_fixedNbrListEnabled) - return false; - - for ( std::map ::iterator it = nodesToAdd.begin(); it != nodesToAdd.end(); ++it) - { - mDirectionalNbrs.insert(std::pair(it->first, it->second)); - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " added directional neighbor " << it->first << " mac Address " << it->second); - } - return true; -} - -bool SimpleWirelessNetDevice::AddDirectionalNeighbor(uint32_t nodeid, Mac48Address macAddr) -{ - // is directional neighbor feature enabled? - // If not return false so caller knows there is a problem - if (!m_fixedNbrListEnabled) - return false; - - mDirectionalNbrs.insert(std::pair(nodeid, macAddr)); - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " added directional neighbor " << nodeid << " mac Address " << macAddr); - return true; -} - -void SimpleWirelessNetDevice::DeleteDirectionalNeighbors(std::set nodeids) -{ - for ( std::set::iterator it = nodeids.begin(); it != nodeids.end(); ++it) - { - std::map::iterator it2 = mDirectionalNbrs.find(*it); - if (it2 != mDirectionalNbrs.end()) - { - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " deleted directional neighbor " << it2->first << " mac Address " << it2->second); - mDirectionalNbrs.erase(it2); - } - } -} - -void SimpleWirelessNetDevice::DeleteDirectionalNeighbor(uint32_t nodeid) -{ - std::map::iterator it = mDirectionalNbrs.find(nodeid); - if (it != mDirectionalNbrs.end()) - { - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " deleted directional neighbor " << nodeid << " mac Address " << it->second); - mDirectionalNbrs.erase(it); - } -} - -//******************************************************************** -// Fixed Contention functions -void SimpleWirelessNetDevice::ClearNbrCount(void) -{ - // When we clear the neighbor count, we actually set it to 1 and not 0 - // because we always have to count ourselves. - m_nbrCount = 1; -} - -void SimpleWirelessNetDevice::IncrementNbrCount(void) -{ - m_nbrCount++; -} - -int SimpleWirelessNetDevice::GetNbrCount(void) -{ - return m_nbrCount; -} - - -//******************************************************************** - -void -SimpleWirelessNetDevice::TransmitStart (Ptr p) -{ - NS_LOG_FUNCTION (this << p); - - // This function is called to start the process of transmitting a packet. - // We need to tell the channel that we've started wiggling the wire and - // schedule an event that will be executed when the transmission is complete. - NS_ASSERT_MSG (m_txMachineState == READY, "Must be READY to transmit"); - m_txMachineState = BUSY; - m_currentPkt = p; - - if (m_pcapEnabled) - { - m_promiscSnifferTrace (p); - } - - // Remove the timestamp tag. calculate queue latency and peg trace - TimestampTag timeEnqueued; - p->RemovePacketTag (timeEnqueued); - Time latency = Simulator::Now() - timeEnqueued.GetTimestamp(); - m_QueueLatencyTrace(p, latency); - NS_LOG_DEBUG (Simulator::Now() << " Getting packet with timestamp: " << timeEnqueued.GetTimestamp() ); - - // Remove ethernet header since it is not sent over the air - // To this AFTER the queue latency trace in case the trace wants - // to use anything in the Ethernet header - EthernetHeader ethHeader; - p->RemoveHeader(ethHeader); - Mac48Address to = ethHeader.GetDestination (); - Mac48Address from = ethHeader.GetSource (); - uint16_t protocol = ethHeader.GetLengthType (); - - - // Get dest Id tag. This could be the default NO_DIRECTIONAL_NBR - DestinationIdTag destIdTag; - p->RemovePacketTag (destIdTag); - uint32_t destId = destIdTag.GetDestinationId(); - - Time txTime = Seconds (m_bps.CalculateTxTime (p->GetSize ())); - - // If we have a non-zero neighbor count then that means we are using contention and - // the data rate changes. Note that when using contention, we will always have at least - // a value of 1 for neighbor count because we count ourselves. - // If this device is omni then data rate changes to data rate/# neighbors. - // Thus multiply the tx time by the number of neighbors (which is the same as dividing the - // data rate by # neighbors) - // If this device is directional then the data rate is rate/2. Thus multiply the tx time by 2. - - // IMPORTANT NOTE: If we are using contention, the first packet we send may not "know" - // that there is contention. This is a chicken and egg situation. - // The device keeps the neighbor count (which is init'd to 0) but the channel is - // the one that has contention. When contention is enabled on the channel, there may not be - // any devices to initial with the contention (i.e., set nbr count to 1). The function in the - // channel that sets contention enabled also notifies all the devices on the channel but if - // there are not devices yet when the function is called then the first packet sent on the - // channel by the device is what will cause the device to get init'd for contention. That is - // after the device set the txTime so that first packet will be sent at full data rate. - if (m_nbrCount) - { - if (m_fixedNbrListEnabled) - { - txTime = txTime * 2; - NS_LOG_DEBUG ("Node " << m_node->GetId() << " txTime was increased to " << txTime << " because we have directonal neighbors. packet size is " << p->GetSize ()); - } - else - { - txTime = txTime * m_nbrCount; - NS_LOG_DEBUG ("Node " << m_node->GetId() << " txTime was increased to " << txTime << " because we have " << m_nbrCount << " neighbors. packet size is " << p->GetSize ()); - } - } - // TO DO: do we need interframe gap?? - //Time txCompleteTime = txTime + m_tInterframeGap; - Time txCompleteTime = txTime; - - NS_LOG_DEBUG ("Schedule TransmitCompleteEvent in " << txCompleteTime.GetMicroSeconds () << "usec"); - Simulator::Schedule (txCompleteTime, &SimpleWirelessNetDevice::TransmitComplete, this); - - m_TxBeginTrace (p, from, to, protocol); - - m_channel->Send (p, protocol, to, from, this, txTime, destId); -} - -void -SimpleWirelessNetDevice::TransmitComplete (void) -{ - NS_LOG_FUNCTION_NOARGS (); - - // This function is called to when we're all done transmitting a packet. - // We try and pull another packet off of the transmit queue. If the queue - // is empty, we are done, otherwise we need to start transmitting the - // next packet. - NS_ASSERT_MSG (m_txMachineState == BUSY, "Must be BUSY if transmitting"); - m_txMachineState = READY; - - NS_ASSERT_MSG (m_currentPkt != 0, "SimpleWirelessNetDevice::TransmitComplete(): m_currentPkt zero"); - m_currentPkt = 0; - - NS_LOG_DEBUG (Simulator::Now() << " Tx complete. Packets in queue: " << m_queue->GetNPackets() << " Bytes in queue: " << m_queue->GetNBytes()); - - - Ptr p = m_queue->Dequeue (); - if (p == 0) - { - // No packet was on the queue, so we just exit. - return; - } - - // Got another packet off of the queue, so start the transmit process agin. - TransmitStart (p); -} - - -bool -SimpleWirelessNetDevice::Send(Ptr packet, const Address& dest, uint16_t protocolNumber) -{ - NS_LOG_FUNCTION (packet << dest << protocolNumber); - Mac48Address to = Mac48Address::ConvertFrom (dest); - - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " sending packet " << packet->GetUid () << " to " << to ); - - // For some reason the Ethernet header is STRIPPED from the packet - // by the time we get here so we need to reconstruct it for for two reasons. - // If queuing, add ethernet header to the packet in the queue so we can - // retrieve the to, from and protocol. Also Ethernet header is - // needed so we can apply a pcap filter in priority queues - EthernetHeader ethHeader; - ethHeader.SetSource (m_address); - ethHeader.SetDestination (to); - ethHeader.SetLengthType (protocolNumber); - packet->AddHeader (ethHeader); - - m_macTxTrace (packet); - - // If directional networking is enabled, then we have to make a copy - // of this packet and enqueue it for each destination. - if (m_fixedNbrListEnabled) - { - std::map::iterator it; - - // Look up the dest address in the eth header of the packet. - // This is necessary because in directional networks, the dest - // could have been changed by the trace - packet->PeekHeader(ethHeader); - to = ethHeader.GetDestination(); - - if (to.IsBroadcast()) - { - NS_LOG_INFO ("Address " << to << " is broadcast"); - // broadcast packet. Enqueue for all of our directional neighbors - for ( it = mDirectionalNbrs.begin(); it != mDirectionalNbrs.end(); ++it) - { - EnqueuePacket(packet->Copy(),m_address,to,protocolNumber,it->first); - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " queueing packet to directional neighbor to node " << it->first); - } - } - else - { - NS_LOG_INFO ("Address " << to << " is NOT broadcast"); - // unicast packet. Find the directional neighbor with matching MAC address. (There might not be one) - for ( it = mDirectionalNbrs.begin(); it != mDirectionalNbrs.end(); ++it) - { - if (it->second == to) - { - EnqueuePacket(packet->Copy(),m_address,to,protocolNumber, it->first); - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " found node " << it->first << " with matching Mac Address " << to); - break; - } - } - } - } - else - { - EnqueuePacket(packet,m_address,to,protocolNumber, NO_DIRECTIONAL_NBR); - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " queueing packet"); - } - - return true; - -} - - -bool -SimpleWirelessNetDevice::SendFrom(Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) -{ - NS_LOG_FUNCTION (packet << dest << protocolNumber); - Mac48Address to = Mac48Address::ConvertFrom (dest); - Mac48Address from = Mac48Address::ConvertFrom (source); - - // For some reason the Ethernet header is STRIPPED from the packet - // by the time we get here so we need to reconstruct it for for two reasons. - // If queuing, add ethernet header to the packet in the queue so we can - // retrieve the to, from and protocol. Also Ethernet header is - // needed so we can apply a pcap filter in priority queues - EthernetHeader ethHeader; - ethHeader.SetSource (from); - ethHeader.SetDestination (to); - ethHeader.SetLengthType (protocolNumber); - packet->AddHeader (ethHeader); - - m_macTxTrace (packet); - - - // If directional networking is enabled, then we have to make a copy - // of this packet and enqueue it for each destination. - if (m_fixedNbrListEnabled) - { - std::map::iterator it; - - // Look up the dest address in the eth header of the packet. - // This is necessary because in directional networks, the dest - // could have been changed by the trace - packet->PeekHeader(ethHeader); - to = ethHeader.GetDestination(); - - if (to.IsBroadcast()) - { - NS_LOG_INFO ("Address " << to << " is broadcast"); - // broadcast packet. Enqueue for all of our directional neighbors - for ( it = mDirectionalNbrs.begin(); it != mDirectionalNbrs.end(); ++it) - { - // Note that we do not alter the to (mac address) here but instead specify - // the node id as the destination. This gets carried with the packet - // as a destination tag and passed to the channel. At the channel it still - // appears as a broadcast packet but the channel only uses the dest id so it - // will know how to handle it from the perspective of directional networking. - EnqueuePacket(packet->Copy(),from,to,protocolNumber,it->first); - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " queueing packet to directional neighbor to node " << it->first); - } - } - else - { - NS_LOG_INFO ("Address " << to << " is NOT broadcast"); - // unicast packet. Find the directional neighbor with matching MAC address. (There might not be one) - for ( it = mDirectionalNbrs.begin(); it != mDirectionalNbrs.end(); ++it) - { - if (it->second == to) - { - EnqueuePacket(packet->Copy(),from,to,protocolNumber, it->first); - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " found node " << it->first << " with matching Mac Address " << to); - break; - } - } - } - } - else - { - EnqueuePacket(packet,from,to,protocolNumber, NO_DIRECTIONAL_NBR); - NS_LOG_INFO ("Node " << this->GetNode()->GetId() << " queueing packet"); - } - - return true; - -} - -bool -SimpleWirelessNetDevice::EnqueuePacket (Ptr packet, Mac48Address from, Mac48Address to, uint16_t protocolNumber, uint32_t destId) -{ - - if (m_queue) - { - // We are using queueing. - - // Add a timestamp tag for latency - TimestampTag timestamp; - timestamp.SetTimestamp (Simulator::Now ()); - packet->AddPacketTag (timestamp); - - // add destination tag - DestinationIdTag idTag(destId); - packet->AddPacketTag (idTag); - - NS_LOG_DEBUG ("Queueing packet for destination " << destId << ". Protocol "<< protocolNumber << " Current state is: " << m_txMachineState); - - // We should enqueue and dequeue the packet to hit the tracing hooks. - if (m_queue->Enqueue (packet)) - { - // If the channel is ready for transition we send the packet right now - if (m_txMachineState == READY) - { - packet = m_queue->Dequeue (); - TransmitStart (packet); - } - return true; - } - - // TO DO: do we return true or false here?? - return true; - } - else - { - // No queuing is being used. Just send the packet. - if (m_pcapEnabled) - { - m_promiscSnifferTrace (packet); - } - EthernetHeader ethHeader; - packet->RemoveHeader(ethHeader); - - m_TxBeginTrace (packet, m_address, to, protocolNumber); - Time txTime = Seconds (m_bps.CalculateTxTime (packet->GetSize ())); - // If we have a non-zero neighbor count then that means we are using contention and - // the data rate changes. - if (m_nbrCount) - { - if (m_fixedNbrListEnabled) - { - txTime = txTime * 2; - NS_LOG_DEBUG ("Node " << m_node->GetId() << " txTime was increased to " << txTime << " because we have directonal neighbors. packet size is " << packet->GetSize ()); - } - else - { - txTime = txTime * m_nbrCount; - NS_LOG_DEBUG ("Node " << m_node->GetId() << " txTime was increased to " << txTime << " because we have " << m_nbrCount << " neighbors. packet size is " << packet->GetSize ()); - } - } - m_channel->Send (packet, protocolNumber, to, from, this, txTime, destId); - return true; - } -} - - - - -Ptr -SimpleWirelessNetDevice::GetNode (void) const -{ - return m_node; -} -void -SimpleWirelessNetDevice::SetNode (Ptr node) -{ - m_node = node; -} -bool -SimpleWirelessNetDevice::NeedsArp (void) const -{ - return true; -} -void -SimpleWirelessNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb) -{ - m_rxCallback = cb; -} - -void -SimpleWirelessNetDevice::DoDispose (void) -{ - m_channel = 0; - m_node = 0; - m_receiveErrorModel = 0; - NetDevice::DoDispose (); -} - - -void -SimpleWirelessNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb) -{ - m_promiscCallback = cb; -} - -bool -SimpleWirelessNetDevice::SupportsSendFrom (void) const -{ - return true; -} - -void -SimpleWirelessNetDevice::SetDataRate (DataRate bps) -{ - NS_LOG_FUNCTION_NOARGS (); - m_bps = bps; -} - -void -SimpleWirelessNetDevice::SetQueue (Ptr q) -{ - NS_LOG_FUNCTION (this << q); - m_queue = q; -} - -Ptr -SimpleWirelessNetDevice::GetQueue (void) const -{ - NS_LOG_FUNCTION_NOARGS (); - return m_queue; -} - - -void SimpleWirelessNetDevice::EnablePcapAll (std::string filename) -{ - PcapHelper pcapHelper; - Ptr file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_EN10MB); - pcapHelper.HookDefaultSink (this, "PromiscSniffer", file); - m_pcapEnabled = true; -} - -} // namespace ns3 +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * Copyright (c) 2010 University of Washington + * + * 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 + * + */ +#include "ns3/node.h" +#include "ns3/packet.h" +#include "ns3/log.h" +#include "ns3/pointer.h" +#include "ns3/error-model.h" +#include "ns3/trace-source-accessor.h" +#include "simple-wireless-net-device.h" +#include "simple-wireless-channel.h" + +#include // needed for noth for protocol # in sniffer + +NS_LOG_COMPONENT_DEFINE ("SimpleWirelessNetDevice"); + +namespace ns3 { + +NS_OBJECT_ENSURE_REGISTERED (SimpleWirelessNetDevice); + +//******************************************************** +// TimestampTag used to store a timestamp with a packet +// when they are placed in the queue +//******************************************************** +TypeId TimestampTag::GetTypeId (void) +{ + static TypeId tid = TypeId ("TimestampTag") + .SetParent () + .AddConstructor () + .AddAttribute ("Timestamp", + "Some momentous point in time!", + EmptyAttributeValue (), + MakeTimeAccessor (&TimestampTag::GetTimestamp), + MakeTimeChecker ()) + ; + return tid; +} + +TypeId TimestampTag::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +uint32_t TimestampTag::GetSerializedSize (void) const +{ + return 8; +} + +void TimestampTag::Serialize (TagBuffer i) const +{ + int64_t t = m_timestamp.GetNanoSeconds (); + i.Write ((const uint8_t *)&t, 8); +} + +void TimestampTag::Deserialize (TagBuffer i) +{ + int64_t t; + i.Read ((uint8_t *)&t, 8); + m_timestamp = NanoSeconds (t); +} + +void TimestampTag::SetTimestamp (Time time) +{ + m_timestamp = time; +} + +Time TimestampTag::GetTimestamp (void) const +{ + return m_timestamp; +} + +void TimestampTag::Print (std::ostream &os) const +{ + os << "t=" << m_timestamp; +} + +//******************************************************** + +//******************************************************** +// DestinationIdTag used to store a destination node id +// with a packet when they are placed in the queue. +// This is used by directional networks. +//******************************************************** +TypeId DestinationIdTag::GetTypeId (void) +{ + static TypeId tid = TypeId ("DestinationIdTag") + .SetParent () + .AddConstructor () + ; + return tid; +} + +TypeId DestinationIdTag::GetInstanceTypeId (void) const +{ + return GetTypeId (); +} + +DestinationIdTag::DestinationIdTag () +{ +} + +DestinationIdTag::DestinationIdTag (uint32_t destId) + : m_destnodeid (destId) +{ +} + +uint32_t DestinationIdTag::GetSerializedSize (void) const +{ + return 4; +} + +void DestinationIdTag::Serialize (TagBuffer i) const +{ + i.WriteU32 (m_destnodeid); +} + +void DestinationIdTag::Deserialize (TagBuffer i) +{ + m_destnodeid = i.ReadU32 (); +} + +void DestinationIdTag::SetDestinationId (uint32_t id) +{ + m_destnodeid = id; +} + +uint32_t DestinationIdTag::GetDestinationId (void) const +{ + return m_destnodeid; +} + +void DestinationIdTag::Print (std::ostream &os) const +{ + os << "t=" << m_destnodeid; +} + +//******************************************************** + +TypeId +SimpleWirelessNetDevice::GetTypeId (void) +{ + static TypeId tid = TypeId ("ns3::SimpleWirelessNetDevice") + .SetParent () + .AddConstructor () + .AddAttribute ("ReceiveErrorModel", + "The receiver error model used to simulate packet loss", + PointerValue (), + MakePointerAccessor (&SimpleWirelessNetDevice::m_receiveErrorModel), + MakePointerChecker ()) + .AddAttribute ("DataRate", + "The default data rate for point to point links", + DataRateValue (DataRate ("1000000b/s")), + MakeDataRateAccessor (&SimpleWirelessNetDevice::m_bps), + MakeDataRateChecker ()) + // Transmit queueing discipline for the device which includes its own set + // of trace hooks. + .AddAttribute ("TxQueue", + "A queue to use as the transmit queue in the device.", + PointerValue (), + MakePointerAccessor (&SimpleWirelessNetDevice::m_queue), + MakePointerChecker > ()) + .AddAttribute ("FixedNeighborListEnabled", + "Enabled or Disabled", + BooleanValue (false), + MakeBooleanAccessor (&SimpleWirelessNetDevice::m_fixedNbrListEnabled), + MakeBooleanChecker ()) + .AddTraceSource ("PhyTxBegin", + "Trace source indicating a packet has begun transmitting", + MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_TxBeginTrace), + "ns3::SimpleWirelessNetDevice::PacketEventTracedCallback") + .AddTraceSource ("PhyRxDrop", + "Trace source indicating a packet has been dropped by the device during reception", + MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_phyRxDropTrace), + "ns3::SimpleWirelessNetDevice::PacketEventTracedCallback") + .AddTraceSource ("PhyRxBegin", + "Trace source indicating a packet " + "has begun being received from the channel medium " + "by the device", + MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_phyRxBeginTrace), + "ns3::SimpleWirelessNetDevice::PacketEventTracedCallback") + .AddTraceSource ("PhyRxEnd", + "Trace source indicating a packet " + "has been completely received from the channel medium " + "by the device", + MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_phyRxEndTrace), + "ns3::SimpleWirelessNetDevice::PacketEventTracedCallback") + // Trace sources designed to simulate a packet sniffer facility (tcpdump). + .AddTraceSource ("PromiscSniffer", + "Trace source simulating a promiscuous packet sniffer attached to the device", + MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_promiscSnifferTrace), + "ns3::Packet::TracedCallback") + .AddTraceSource ("QueueLatency", + "Trace source to report the latency of a packet in the queue. Datatype returned is Time.", + MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_QueueLatencyTrace), + "ns3::SimpleWirelessNetDevice::QueueLatencyTracedCallback") + .AddTraceSource ("MacTx", + "A packet has been received from higher layers and is being processed in preparation for " + "queueing for transmission.", + MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_macTxTrace), + "ns3::Packet::TracedCallback") + .AddTraceSource ("MacRx", + "A packet has been received by this device, has been passed up from the physical layer " + "and is being forwarded up the local protocol stack. This is a non-promiscuous trace,", + MakeTraceSourceAccessor (&SimpleWirelessNetDevice::m_macRxTrace), + "ns3::Packet::TracedCallback") + ; + return tid; +} + +SimpleWirelessNetDevice::SimpleWirelessNetDevice () + : m_channel (0), + m_node (0), + m_mtu (0xffff), + m_ifIndex (0), + m_txMachineState (READY), + m_queue (NULL), + m_pktRcvTotal (0), + m_pktRcvDrop (0), + m_pcapEnabled (false), + m_fixedNbrListEnabled (false), + m_nbrCount (0) + +{ +} + +void +SimpleWirelessNetDevice::Receive (Ptr packet, uint16_t protocol, + Mac48Address to, Mac48Address from) +{ + NS_LOG_FUNCTION (packet << protocol << to << from); + NetDevice::PacketType packetType; + + m_phyRxBeginTrace (packet, from, to, protocol); + m_pktRcvTotal++; + + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " receiving packet " << packet->GetUid () << " from " << from << " to " << to ); + + if (m_receiveErrorModel && m_receiveErrorModel->IsCorrupt (packet) ) + { + m_phyRxDropTrace (packet, from, to, protocol); + m_pktRcvDrop++; + return; + } + + if (m_pcapEnabled) + { + // Add the ethernet header to the packet for sniffer + // For some reason the Ethernet header is STRIPPED from the packet + // by the time we get here so we need to reconstruct it for the + // sniffer. + // allocate buffer for packet and mac addresses + uint8_t buffer[8192]; + uint8_t macBuffer[6]; + // get the dest and src addresses and copy into the buffer + to.CopyTo (macBuffer); + memcpy (&buffer[0], macBuffer, 6); + from.CopyTo (macBuffer); + memcpy (&buffer[6], macBuffer, 6); + //copy the protocol and the actual packet data in the the buffer + uint16_t tempProt = ntohs (protocol); + memcpy (&buffer[12], &tempProt, 2); + packet->CopyData (&buffer[14], packet->GetSize ()); + // Now make a new temp packet to write to the sniffer + Ptr tempPacket = Create (buffer, packet->GetSize () + 14); + m_promiscSnifferTrace (tempPacket); + } + + if (to == m_address) + { + packetType = NetDevice::PACKET_HOST; + } + else if (to.IsBroadcast ()) + { + packetType = NetDevice::PACKET_BROADCAST; + } + else if (to.IsGroup ()) + { + packetType = NetDevice::PACKET_MULTICAST; + } + else + { + packetType = NetDevice::PACKET_OTHERHOST; + } + + m_phyRxEndTrace (packet, from, to, protocol); + + if (packetType != NetDevice::PACKET_OTHERHOST) + { + m_macRxTrace (packet); + m_rxCallback (this, packet, protocol, from); + } + + + if (!m_promiscCallback.IsNull ()) + { + m_promiscCallback (this, packet, protocol, from, to, packetType); + } + NS_LOG_DEBUG ("Total Rcvd: " << m_pktRcvTotal << " Total Dropped: " << m_pktRcvDrop); +} + +void +SimpleWirelessNetDevice::SetChannel (Ptr channel) +{ + m_channel = channel; + m_channel->Add (this); +} + +void +SimpleWirelessNetDevice::SetReceiveErrorModel (Ptr em) +{ + m_receiveErrorModel = em; +} + +void +SimpleWirelessNetDevice::SetIfIndex (const uint32_t index) +{ + m_ifIndex = index; +} +uint32_t +SimpleWirelessNetDevice::GetIfIndex (void) const +{ + return m_ifIndex; +} +Ptr +SimpleWirelessNetDevice::GetChannel (void) const +{ + return m_channel; +} +void +SimpleWirelessNetDevice::SetAddress (Address address) +{ + m_address = Mac48Address::ConvertFrom (address); +} +Address +SimpleWirelessNetDevice::GetAddress (void) const +{ + // + // Implicit conversion from Mac48Address to Address + // + return m_address; +} +bool +SimpleWirelessNetDevice::SetMtu (const uint16_t mtu) +{ + m_mtu = mtu; + return true; +} +uint16_t +SimpleWirelessNetDevice::GetMtu (void) const +{ + return m_mtu; +} +bool +SimpleWirelessNetDevice::IsLinkUp (void) const +{ + return true; +} +void +SimpleWirelessNetDevice::AddLinkChangeCallback (Callback callback) +{ +} +bool +SimpleWirelessNetDevice::IsBroadcast (void) const +{ + return true; +} +Address +SimpleWirelessNetDevice::GetBroadcast (void) const +{ + return Mac48Address ("ff:ff:ff:ff:ff:ff"); +} +bool +SimpleWirelessNetDevice::IsMulticast (void) const +{ + return false; +} +Address +SimpleWirelessNetDevice::GetMulticast (Ipv4Address multicastGroup) const +{ + return Mac48Address::GetMulticast (multicastGroup); +} + +Address SimpleWirelessNetDevice::GetMulticast (Ipv6Address addr) const +{ + return Mac48Address::GetMulticast (addr); +} + +bool +SimpleWirelessNetDevice::IsPointToPoint (void) const +{ + return false; +} + +bool +SimpleWirelessNetDevice::IsBridge (void) const +{ + return false; +} + +//******************************************************************** +// Directional Neighbor functions +bool SimpleWirelessNetDevice::AddDirectionalNeighbors (std::map nodesToAdd) +{ + // is directional neighbor feature enabled? + // If not return false so caller knows there is a problem + if (!m_fixedNbrListEnabled) + { + return false; + } + + for ( std::map ::iterator it = nodesToAdd.begin (); it != nodesToAdd.end (); ++it) + { + mDirectionalNbrs.insert (std::pair (it->first, it->second)); + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " added directional neighbor " << it->first << " mac Address " << it->second); + } + return true; +} + +bool SimpleWirelessNetDevice::AddDirectionalNeighbor (uint32_t nodeid, Mac48Address macAddr) +{ + // is directional neighbor feature enabled? + // If not return false so caller knows there is a problem + if (!m_fixedNbrListEnabled) + { + return false; + } + + mDirectionalNbrs.insert (std::pair (nodeid, macAddr)); + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " added directional neighbor " << nodeid << " mac Address " << macAddr); + return true; +} + +void SimpleWirelessNetDevice::DeleteDirectionalNeighbors (std::set nodeids) +{ + for ( std::set::iterator it = nodeids.begin (); it != nodeids.end (); ++it) + { + std::map::iterator it2 = mDirectionalNbrs.find (*it); + if (it2 != mDirectionalNbrs.end ()) + { + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " deleted directional neighbor " << it2->first << " mac Address " << it2->second); + mDirectionalNbrs.erase (it2); + } + } +} + +void SimpleWirelessNetDevice::DeleteDirectionalNeighbor (uint32_t nodeid) +{ + std::map::iterator it = mDirectionalNbrs.find (nodeid); + if (it != mDirectionalNbrs.end ()) + { + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " deleted directional neighbor " << nodeid << " mac Address " << it->second); + mDirectionalNbrs.erase (it); + } +} + +//******************************************************************** +// Fixed Contention functions +void SimpleWirelessNetDevice::ClearNbrCount (void) +{ + // When we clear the neighbor count, we actually set it to 1 and not 0 + // because we always have to count ourselves. + m_nbrCount = 1; +} + +void SimpleWirelessNetDevice::IncrementNbrCount (void) +{ + m_nbrCount++; +} + +int SimpleWirelessNetDevice::GetNbrCount (void) +{ + return m_nbrCount; +} + + +//******************************************************************** + +void +SimpleWirelessNetDevice::TransmitStart (Ptr p) +{ + NS_LOG_FUNCTION (this << p); + + // This function is called to start the process of transmitting a packet. + // We need to tell the channel that we've started wiggling the wire and + // schedule an event that will be executed when the transmission is complete. + NS_ASSERT_MSG (m_txMachineState == READY, "Must be READY to transmit"); + m_txMachineState = BUSY; + m_currentPkt = p; + + if (m_pcapEnabled) + { + m_promiscSnifferTrace (p); + } + + // Remove the timestamp tag. calculate queue latency and peg trace + TimestampTag timeEnqueued; + p->RemovePacketTag (timeEnqueued); + Time latency = Simulator::Now () - timeEnqueued.GetTimestamp (); + m_QueueLatencyTrace (p, latency); + NS_LOG_DEBUG (Simulator::Now () << " Getting packet with timestamp: " << timeEnqueued.GetTimestamp () ); + + // Remove ethernet header since it is not sent over the air + // To this AFTER the queue latency trace in case the trace wants + // to use anything in the Ethernet header + EthernetHeader ethHeader; + p->RemoveHeader (ethHeader); + Mac48Address to = ethHeader.GetDestination (); + Mac48Address from = ethHeader.GetSource (); + uint16_t protocol = ethHeader.GetLengthType (); + + + // Get dest Id tag. This could be the default NO_DIRECTIONAL_NBR + DestinationIdTag destIdTag; + p->RemovePacketTag (destIdTag); + uint32_t destId = destIdTag.GetDestinationId (); + + Time txTime = m_bps.CalculateBytesTxTime (p->GetSize ()); + + // If we have a non-zero neighbor count then that means we are using contention and + // the data rate changes. Note that when using contention, we will always have at least + // a value of 1 for neighbor count because we count ourselves. + // If this device is omni then data rate changes to data rate/# neighbors. + // Thus multiply the tx time by the number of neighbors (which is the same as dividing the + // data rate by # neighbors) + // If this device is directional then the data rate is rate/2. Thus multiply the tx time by 2. + + // IMPORTANT NOTE: If we are using contention, the first packet we send may not "know" + // that there is contention. This is a chicken and egg situation. + // The device keeps the neighbor count (which is init'd to 0) but the channel is + // the one that has contention. When contention is enabled on the channel, there may not be + // any devices to initial with the contention (i.e., set nbr count to 1). The function in the + // channel that sets contention enabled also notifies all the devices on the channel but if + // there are not devices yet when the function is called then the first packet sent on the + // channel by the device is what will cause the device to get init'd for contention. That is + // after the device set the txTime so that first packet will be sent at full data rate. + if (m_nbrCount) + { + if (m_fixedNbrListEnabled) + { + txTime = txTime * 2; + NS_LOG_DEBUG ("Node " << m_node->GetId () << " txTime was increased to " << txTime << " because we have directonal neighbors. packet size is " << p->GetSize ()); + } + else + { + txTime = txTime * m_nbrCount; + NS_LOG_DEBUG ("Node " << m_node->GetId () << " txTime was increased to " << txTime << " because we have " << m_nbrCount << " neighbors. packet size is " << p->GetSize ()); + } + } + // TO DO: do we need interframe gap?? + //Time txCompleteTime = txTime + m_tInterframeGap; + Time txCompleteTime = txTime; + + NS_LOG_DEBUG ("Schedule TransmitCompleteEvent in " << txCompleteTime.GetMicroSeconds () << "usec"); + Simulator::Schedule (txCompleteTime, &SimpleWirelessNetDevice::TransmitComplete, this); + + m_TxBeginTrace (p, from, to, protocol); + + m_channel->Send (p, protocol, to, from, this, txTime, destId); +} + +void +SimpleWirelessNetDevice::TransmitComplete (void) +{ + NS_LOG_FUNCTION_NOARGS (); + + // This function is called to when we're all done transmitting a packet. + // We try and pull another packet off of the transmit queue. If the queue + // is empty, we are done, otherwise we need to start transmitting the + // next packet. + NS_ASSERT_MSG (m_txMachineState == BUSY, "Must be BUSY if transmitting"); + m_txMachineState = READY; + + NS_ASSERT_MSG (m_currentPkt != 0, "SimpleWirelessNetDevice::TransmitComplete(): m_currentPkt zero"); + m_currentPkt = 0; + + NS_LOG_DEBUG (Simulator::Now () << " Tx complete. Packets in queue: " << m_queue->GetNPackets () << " Bytes in queue: " << m_queue->GetNBytes ()); + + + Ptr p = m_queue->Dequeue (); + if (p == 0) + { + // No packet was on the queue, so we just exit. + return; + } + + // Got another packet off of the queue, so start the transmit process agin. + TransmitStart (p); +} + + +bool +SimpleWirelessNetDevice::Send (Ptr packet, const Address& dest, uint16_t protocolNumber) +{ + NS_LOG_FUNCTION (packet << dest << protocolNumber); + Mac48Address to = Mac48Address::ConvertFrom (dest); + + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " sending packet " << packet->GetUid () << " to " << to ); + + // For some reason the Ethernet header is STRIPPED from the packet + // by the time we get here so we need to reconstruct it for for two reasons. + // If queuing, add ethernet header to the packet in the queue so we can + // retrieve the to, from and protocol. Also Ethernet header is + // needed so we can apply a pcap filter in priority queues + EthernetHeader ethHeader; + ethHeader.SetSource (m_address); + ethHeader.SetDestination (to); + ethHeader.SetLengthType (protocolNumber); + packet->AddHeader (ethHeader); + + m_macTxTrace (packet); + + // If directional networking is enabled, then we have to make a copy + // of this packet and enqueue it for each destination. + if (m_fixedNbrListEnabled) + { + std::map::iterator it; + + // Look up the dest address in the eth header of the packet. + // This is necessary because in directional networks, the dest + // could have been changed by the trace + packet->PeekHeader (ethHeader); + to = ethHeader.GetDestination (); + + if (to.IsBroadcast ()) + { + NS_LOG_INFO ("Address " << to << " is broadcast"); + // broadcast packet. Enqueue for all of our directional neighbors + for ( it = mDirectionalNbrs.begin (); it != mDirectionalNbrs.end (); ++it) + { + EnqueuePacket (packet->Copy (),m_address,to,protocolNumber,it->first); + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " queueing packet to directional neighbor to node " << it->first); + } + } + else + { + NS_LOG_INFO ("Address " << to << " is NOT broadcast"); + // unicast packet. Find the directional neighbor with matching MAC address. (There might not be one) + for ( it = mDirectionalNbrs.begin (); it != mDirectionalNbrs.end (); ++it) + { + if (it->second == to) + { + EnqueuePacket (packet->Copy (),m_address,to,protocolNumber, it->first); + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " found node " << it->first << " with matching Mac Address " << to); + break; + } + } + } + } + else + { + EnqueuePacket (packet,m_address,to,protocolNumber, NO_DIRECTIONAL_NBR); + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " queueing packet"); + } + + return true; + +} + + +bool +SimpleWirelessNetDevice::SendFrom (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber) +{ + NS_LOG_FUNCTION (packet << dest << protocolNumber); + Mac48Address to = Mac48Address::ConvertFrom (dest); + Mac48Address from = Mac48Address::ConvertFrom (source); + + // For some reason the Ethernet header is STRIPPED from the packet + // by the time we get here so we need to reconstruct it for for two reasons. + // If queuing, add ethernet header to the packet in the queue so we can + // retrieve the to, from and protocol. Also Ethernet header is + // needed so we can apply a pcap filter in priority queues + EthernetHeader ethHeader; + ethHeader.SetSource (from); + ethHeader.SetDestination (to); + ethHeader.SetLengthType (protocolNumber); + packet->AddHeader (ethHeader); + + m_macTxTrace (packet); + + + // If directional networking is enabled, then we have to make a copy + // of this packet and enqueue it for each destination. + if (m_fixedNbrListEnabled) + { + std::map::iterator it; + + // Look up the dest address in the eth header of the packet. + // This is necessary because in directional networks, the dest + // could have been changed by the trace + packet->PeekHeader (ethHeader); + to = ethHeader.GetDestination (); + + if (to.IsBroadcast ()) + { + NS_LOG_INFO ("Address " << to << " is broadcast"); + // broadcast packet. Enqueue for all of our directional neighbors + for ( it = mDirectionalNbrs.begin (); it != mDirectionalNbrs.end (); ++it) + { + // Note that we do not alter the to (mac address) here but instead specify + // the node id as the destination. This gets carried with the packet + // as a destination tag and passed to the channel. At the channel it still + // appears as a broadcast packet but the channel only uses the dest id so it + // will know how to handle it from the perspective of directional networking. + EnqueuePacket (packet->Copy (),from,to,protocolNumber,it->first); + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " queueing packet to directional neighbor to node " << it->first); + } + } + else + { + NS_LOG_INFO ("Address " << to << " is NOT broadcast"); + // unicast packet. Find the directional neighbor with matching MAC address. (There might not be one) + for ( it = mDirectionalNbrs.begin (); it != mDirectionalNbrs.end (); ++it) + { + if (it->second == to) + { + EnqueuePacket (packet->Copy (),from,to,protocolNumber, it->first); + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " found node " << it->first << " with matching Mac Address " << to); + break; + } + } + } + } + else + { + EnqueuePacket (packet,from,to,protocolNumber, NO_DIRECTIONAL_NBR); + NS_LOG_INFO ("Node " << this->GetNode ()->GetId () << " queueing packet"); + } + + return true; + +} + +bool +SimpleWirelessNetDevice::EnqueuePacket (Ptr packet, Mac48Address from, Mac48Address to, uint16_t protocolNumber, uint32_t destId) +{ + + if (m_queue) + { + // We are using queueing. + + // Add a timestamp tag for latency + TimestampTag timestamp; + timestamp.SetTimestamp (Simulator::Now ()); + packet->AddPacketTag (timestamp); + + // add destination tag + DestinationIdTag idTag (destId); + packet->AddPacketTag (idTag); + + NS_LOG_DEBUG ("Queueing packet for destination " << destId << ". Protocol " << protocolNumber << " Current state is: " << m_txMachineState); + + // We should enqueue and dequeue the packet to hit the tracing hooks. + if (m_queue->Enqueue (packet)) + { + // If the channel is ready for transition we send the packet right now + if (m_txMachineState == READY) + { + packet = m_queue->Dequeue (); + TransmitStart (packet); + } + return true; + } + + // TO DO: do we return true or false here?? + return true; + } + else + { + // No queuing is being used. Just send the packet. + if (m_pcapEnabled) + { + m_promiscSnifferTrace (packet); + } + EthernetHeader ethHeader; + packet->RemoveHeader (ethHeader); + + m_TxBeginTrace (packet, m_address, to, protocolNumber); + Time txTime = m_bps.CalculateBytesTxTime (packet->GetSize ()); + // If we have a non-zero neighbor count then that means we are using contention and + // the data rate changes. + if (m_nbrCount) + { + if (m_fixedNbrListEnabled) + { + txTime = txTime * 2; + NS_LOG_DEBUG ("Node " << m_node->GetId () << " txTime was increased to " << txTime << " because we have directonal neighbors. packet size is " << packet->GetSize ()); + } + else + { + txTime = txTime * m_nbrCount; + NS_LOG_DEBUG ("Node " << m_node->GetId () << " txTime was increased to " << txTime << " because we have " << m_nbrCount << " neighbors. packet size is " << packet->GetSize ()); + } + } + m_channel->Send (packet, protocolNumber, to, from, this, txTime, destId); + return true; + } +} + + + + +Ptr +SimpleWirelessNetDevice::GetNode (void) const +{ + return m_node; +} +void +SimpleWirelessNetDevice::SetNode (Ptr node) +{ + m_node = node; +} +bool +SimpleWirelessNetDevice::NeedsArp (void) const +{ + return true; +} +void +SimpleWirelessNetDevice::SetReceiveCallback (NetDevice::ReceiveCallback cb) +{ + m_rxCallback = cb; +} + +void +SimpleWirelessNetDevice::DoDispose (void) +{ + m_channel = 0; + m_node = 0; + m_receiveErrorModel = 0; + NetDevice::DoDispose (); +} + + +void +SimpleWirelessNetDevice::SetPromiscReceiveCallback (PromiscReceiveCallback cb) +{ + m_promiscCallback = cb; +} + +bool +SimpleWirelessNetDevice::SupportsSendFrom (void) const +{ + return true; +} + +void +SimpleWirelessNetDevice::SetDataRate (DataRate bps) +{ + NS_LOG_FUNCTION_NOARGS (); + m_bps = bps; +} + +void +SimpleWirelessNetDevice::SetQueue (Ptr > q) +{ + NS_LOG_FUNCTION (this << q); + m_queue = q; +} + +Ptr > +SimpleWirelessNetDevice::GetQueue (void) const +{ + NS_LOG_FUNCTION_NOARGS (); + return m_queue; +} + + +void SimpleWirelessNetDevice::EnablePcapAll (std::string filename) +{ + PcapHelper pcapHelper; + Ptr file = pcapHelper.CreateFile (filename, std::ios::out, PcapHelper::DLT_EN10MB); + pcapHelper.HookDefaultSink (this, "PromiscSniffer", file); + m_pcapEnabled = true; +} + +} // namespace ns3 diff --git a/model/simple-wireless-net-device.h b/model/simple-wireless-net-device.h index 2a6563a..b53a036 100644 --- a/model/simple-wireless-net-device.h +++ b/model/simple-wireless-net-device.h @@ -1,362 +1,382 @@ -/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ -/* - * Copyright (C) 2015 Massachusetts Institute of Technology - * Copyright (c) 2010 University of Washington - * - * 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 - * - */ -#ifndef SIMPLE_WIRELESS_NET_DEVICE_H -#define SIMPLE_WIRELESS_NET_DEVICE_H - -#include -#include -#include "ns3/traced-callback.h" -#include "ns3/net-device.h" -#include "ns3/mac48-address.h" -#include "ns3/trace-helper.h" -#include "ns3/data-rate.h" -#include "ns3/queue.h" -#include "ns3/ethernet-header.h" -#include "ns3/double.h" -#include "ns3/boolean.h" - -#include -#include - -namespace ns3 { - -class SimpleWirelessChannel; -class Node; -class ErrorModel; - -#define NO_DIRECTIONAL_NBR 0xFFFFFFFF - - -//******************************************************** -// TimestampTag used to store a timestamp with a packet -// when they are placed in the queue -//******************************************************** -class TimestampTag : public Tag { -public: - static TypeId GetTypeId (void); - virtual TypeId GetInstanceTypeId (void) const; - - virtual uint32_t GetSerializedSize (void) const; - virtual void Serialize (TagBuffer i) const; - virtual void Deserialize (TagBuffer i); - - // these are our accessors to our tag structure - void SetTimestamp (Time time); - Time GetTimestamp (void) const; - - void Print (std::ostream &os) const; - -private: - Time m_timestamp; - - // end class TimestampTag -}; - - -//******************************************************** -// DestinationIdTag used to store a destination node id -// with a packet when they are placed in the queue. -// This is used by directional networks. -//******************************************************** -class DestinationIdTag : public Tag { -public: - static TypeId GetTypeId (void); - virtual TypeId GetInstanceTypeId (void) const; - - virtual uint32_t GetSerializedSize (void) const; - virtual void Serialize (TagBuffer i) const; - virtual void Deserialize (TagBuffer i); - DestinationIdTag(); - - /** - * Constructs a DestinationIdTag with the given node id - * - * \param destId Id to use for the tag - */ - DestinationIdTag (uint32_t destId); - - // these are our accessors to our tag structure - void SetDestinationId (uint32_t destId); - uint32_t GetDestinationId (void) const; - - void Print (std::ostream &os) const; - -private: - uint32_t m_destnodeid; - - // end class DestinationIdTag -}; - - - -/** - * \ingroup netdevice - * - * This device does not have a helper and assumes 48-bit mac addressing; - * the default address assigned to each device is zero, so you must - * assign a real address to use it. There is also the possibility to - * add an ErrorModel if you want to force losses on the device. - * - * \brief simple net device for simple things and testing - */ -class SimpleWirelessNetDevice : public NetDevice -{ -public: - static TypeId GetTypeId (void); - SimpleWirelessNetDevice (); - - void Receive (Ptr packet, uint16_t protocol, Mac48Address to, Mac48Address from); - void SetChannel (Ptr channel); - - /** - * Attach a receive ErrorModel to the SimpleWirelessNetDevice. - * - * The SimpleWirelessNetDevice may optionally include an ErrorModel in - * the packet receive chain. - * - * \see ErrorModel - * \param em Ptr to the ErrorModel. - */ - void SetReceiveErrorModel(Ptr em); - - /** - * Set the Data Rate used for transmission of packets. The data rate is - * set in the Attach () method from the corresponding field in the channel - * to which the device is attached. It can be overridden using this method. - * - * @see Attach () - * @param bps the data rate at which this object operates - */ - void SetDataRate (DataRate bps); - - /** - * Attach a queue to the PointToPointNetDevice. - * - * The PointToPointNetDevice "owns" a queue that implements a queueing - * method such as DropTail or RED. - * - * @see Queue - * @see DropTailQueue - * @param queue Ptr to the new queue. - */ - void SetQueue (Ptr queue); - - /** - * Get a copy of the attached Queue. - * - * @returns Ptr to the queue. - */ - Ptr GetQueue (void) const; - - //****************************************** - // Directional Neighbor functions - bool AddDirectionalNeighbors(std::map nodesToAdd); - bool AddDirectionalNeighbor(uint32_t nodeid, Mac48Address macAddr); - void DeleteDirectionalNeighbors(std::set nodeids); - void DeleteDirectionalNeighbor(uint32_t nodeid); - - //****************************************** - // Fixed Contention functions - void ClearNbrCount(void); - void IncrementNbrCount(void); - int GetNbrCount(void); - - - void EnablePcapAll(std::string filename); - - // inherited from NetDevice base class. - virtual void SetIfIndex(const uint32_t index); - virtual uint32_t GetIfIndex(void) const; - virtual Ptr GetChannel (void) const; - virtual void SetAddress (Address address); - virtual Address GetAddress (void) const; - virtual bool SetMtu (const uint16_t mtu); - virtual uint16_t GetMtu (void) const; - virtual bool IsLinkUp (void) const; - virtual void AddLinkChangeCallback (Callback callback); - virtual bool IsBroadcast (void) const; - virtual Address GetBroadcast (void) const; - virtual bool IsMulticast (void) const; - virtual Address GetMulticast (Ipv4Address multicastGroup) const; - virtual bool IsPointToPoint (void) const; - virtual bool IsBridge (void) const; - virtual bool Send(Ptr packet, const Address& dest, uint16_t protocolNumber); - virtual bool SendFrom(Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); - virtual Ptr GetNode (void) const; - virtual void SetNode (Ptr node); - virtual bool NeedsArp (void) const; - virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); - virtual bool EnqueuePacket(Ptr packet, Mac48Address from, Mac48Address to, uint16_t protocolNumber, uint32_t destId); - - virtual Address GetMulticast (Ipv6Address addr) const; - - virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb); - virtual bool SupportsSendFrom (void) const; - -protected: - virtual void DoDispose (void); -private: - Ptr m_channel; - NetDevice::ReceiveCallback m_rxCallback; - NetDevice::PromiscReceiveCallback m_promiscCallback; - Ptr m_node; - uint16_t m_mtu; - uint32_t m_ifIndex; - Mac48Address m_address; - Ptr m_receiveErrorModel; - - Ptr m_currentPkt; - - /** - * Start Sending a Packet Down the Wire. - * - * The TransmitStart method is the method that is used internally in the - * NetDevice to begin the process of sending a packet out on - * the channel. The corresponding method is called on the channel to let - * it know that the physical device this class represents has virtually - * started sending signals. An event is scheduled for the time at which - * the bits have been completely transmitted. - */ - void TransmitStart (Ptr); - - /** - * Stop Sending a Packet Down the Wire and Begin the Interframe Gap. - * - * The TransmitComplete method is used internally to finish the process - * of sending a packet out on the channel. - */ - void TransmitComplete (void); - - /** - * Enumeration of the states of the transmit machine of the net device. - */ - enum TxMachineState - { - READY, /**< The transmitter is ready to begin transmission of a packet */ - BUSY /**< The transmitter is busy transmitting a packet */ - }; - /** - * The state of the Net Device transmit state machine. - * @see TxMachineState - */ - TxMachineState m_txMachineState; - - - /** - * The data rate that the Net Device uses to simulate packet transmission - * timing. - * @see class DataRate - */ - DataRate m_bps; - - /** - * The Queue which this device uses as a packet source. - * Management of this Queue has been delegated to the device - * and it has the responsibility for deletion. - * @see class Queue - * @see class DropTailQueue - */ - Ptr m_queue; - - /** - * The trace source fired when a packet begins the reception process from - * the medium. - * - * \see class CallBackTraceSource - */ - TracedCallback, Mac48Address, Mac48Address, uint16_t > m_phyRxBeginTrace; - - /** - * The trace source fired when a packet ends the reception process from - * the medium. - * - * \see class CallBackTraceSource - */ - TracedCallback, Mac48Address, Mac48Address, uint16_t > m_phyRxEndTrace; - - /** - * The trace source fired when the phy layer drops a packet it has received - * due to the error model being active. Although SimpleWirelessNetDevice doesn't - * really have a Phy model, we choose this trace source name for alignment - * with other trace sources. - * - * \see class CallBackTraceSource - */ - TracedCallback, Mac48Address, Mac48Address, uint16_t > m_phyRxDropTrace; - - /** - * A trace source that emulates a promiscuous mode protocol sniffer connected - * to the device. This trace source fire on packets destined for any host - * just like your average everyday packet sniffer. - * - * The trace is captured on send and receive. - * - * \see class CallBackTraceSource - */ - TracedCallback > m_promiscSnifferTrace; - - /** - * The trace source fired when a packet begins the transmission process on - * the medium. - * - * \see class CallBackTraceSource - */ - TracedCallback, Mac48Address, Mac48Address, uint16_t > m_TxBeginTrace; - - /** - * The trace source fired when a packet is dequeued to be sent. - * It does NOT track queue latency for packets that get dropped - * in the queue only that that are actually sent from the queue - * - * \see class CallBackTraceSource - */ - TracedCallback, Time> m_QueueLatencyTrace; - - /** - * The trace source fired when packets come into the "top" of the device - * at the L3/L2 transition, before being queued for transmission. - * - * \see class CallBackTraceSource - */ - TracedCallback > m_macTxTrace; - - /** - * The trace source fired for packets successfully received by the device - * immediately before being forwarded up to higher layers (at the L2/L3 - * transition). This is a non- promiscuous trace. - * - * \see class CallBackTraceSource - */ - TracedCallback > m_macRxTrace; - - - uint32_t m_pktRcvTotal; - uint32_t m_pktRcvDrop; - bool m_pcapEnabled; - - bool m_fixedNbrListEnabled; - std::map mDirectionalNbrs; - - int m_nbrCount; -}; - -} // namespace ns3 - -#endif /* SIMPLE_WIRELESS_NET_DEVICE_H */ +/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ +/* + * Copyright (C) 2015 Massachusetts Institute of Technology + * Copyright (c) 2010 University of Washington + * + * 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 + * + */ +#ifndef SIMPLE_WIRELESS_NET_DEVICE_H +#define SIMPLE_WIRELESS_NET_DEVICE_H + +#include +#include +#include "ns3/traced-callback.h" +#include "ns3/net-device.h" +#include "ns3/mac48-address.h" +#include "ns3/trace-helper.h" +#include "ns3/data-rate.h" +#include "ns3/queue.h" +#include "ns3/ethernet-header.h" +#include "ns3/double.h" +#include "ns3/boolean.h" + +#include +#include + +namespace ns3 { + +class SimpleWirelessChannel; +class Node; +class ErrorModel; + +#define NO_DIRECTIONAL_NBR 0xFFFFFFFF + + +//******************************************************** +// TimestampTag used to store a timestamp with a packet +// when they are placed in the queue +//******************************************************** +class TimestampTag : public Tag +{ +public: + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); + + // these are our accessors to our tag structure + void SetTimestamp (Time time); + Time GetTimestamp (void) const; + + void Print (std::ostream &os) const; + +private: + Time m_timestamp; + + // end class TimestampTag +}; + + +//******************************************************** +// DestinationIdTag used to store a destination node id +// with a packet when they are placed in the queue. +// This is used by directional networks. +//******************************************************** +class DestinationIdTag : public Tag +{ +public: + static TypeId GetTypeId (void); + virtual TypeId GetInstanceTypeId (void) const; + + virtual uint32_t GetSerializedSize (void) const; + virtual void Serialize (TagBuffer i) const; + virtual void Deserialize (TagBuffer i); + DestinationIdTag (); + + /** + * Constructs a DestinationIdTag with the given node id + * + * \param destId Id to use for the tag + */ + DestinationIdTag (uint32_t destId); + + // these are our accessors to our tag structure + void SetDestinationId (uint32_t destId); + uint32_t GetDestinationId (void) const; + + void Print (std::ostream &os) const; + +private: + uint32_t m_destnodeid; + + // end class DestinationIdTag +}; + + + +/** + * \ingroup netdevice + * + * This device does not have a helper and assumes 48-bit mac addressing; + * the default address assigned to each device is zero, so you must + * assign a real address to use it. There is also the possibility to + * add an ErrorModel if you want to force losses on the device. + * + * \brief simple net device for simple things and testing + */ +class SimpleWirelessNetDevice : public NetDevice +{ +public: + static TypeId GetTypeId (void); + SimpleWirelessNetDevice (); + + void Receive (Ptr packet, uint16_t protocol, Mac48Address to, Mac48Address from); + void SetChannel (Ptr channel); + + /** + * Attach a receive ErrorModel to the SimpleWirelessNetDevice. + * + * The SimpleWirelessNetDevice may optionally include an ErrorModel in + * the packet receive chain. + * + * \see ErrorModel + * \param em Ptr to the ErrorModel. + */ + void SetReceiveErrorModel (Ptr em); + + /** + * Set the Data Rate used for transmission of packets. The data rate is + * set in the Attach () method from the corresponding field in the channel + * to which the device is attached. It can be overridden using this method. + * + * @see Attach () + * @param bps the data rate at which this object operates + */ + void SetDataRate (DataRate bps); + + /** + * Attach a queue to the PointToPointNetDevice. + * + * The PointToPointNetDevice "owns" a queue that implements a queueing + * method such as DropTail or RED. + * + * @see Queue + * @see DropTailQueue + * @param queue Ptr to the new queue. + */ + void SetQueue (Ptr > queue); + + /** + * Get a copy of the attached Queue. + * + * @returns Ptr to the queue. + */ + Ptr > GetQueue (void) const; + + //****************************************** + // Directional Neighbor functions + bool AddDirectionalNeighbors (std::map nodesToAdd); + bool AddDirectionalNeighbor (uint32_t nodeid, Mac48Address macAddr); + void DeleteDirectionalNeighbors (std::set nodeids); + void DeleteDirectionalNeighbor (uint32_t nodeid); + + //****************************************** + // Fixed Contention functions + void ClearNbrCount (void); + void IncrementNbrCount (void); + int GetNbrCount (void); + + + void EnablePcapAll (std::string filename); + + // inherited from NetDevice base class. + virtual void SetIfIndex (const uint32_t index); + virtual uint32_t GetIfIndex (void) const; + virtual Ptr GetChannel (void) const; + virtual void SetAddress (Address address); + virtual Address GetAddress (void) const; + virtual bool SetMtu (const uint16_t mtu); + virtual uint16_t GetMtu (void) const; + virtual bool IsLinkUp (void) const; + virtual void AddLinkChangeCallback (Callback callback); + virtual bool IsBroadcast (void) const; + virtual Address GetBroadcast (void) const; + virtual bool IsMulticast (void) const; + virtual Address GetMulticast (Ipv4Address multicastGroup) const; + virtual bool IsPointToPoint (void) const; + virtual bool IsBridge (void) const; + virtual bool Send (Ptr packet, const Address& dest, uint16_t protocolNumber); + virtual bool SendFrom (Ptr packet, const Address& source, const Address& dest, uint16_t protocolNumber); + virtual Ptr GetNode (void) const; + virtual void SetNode (Ptr node); + virtual bool NeedsArp (void) const; + virtual void SetReceiveCallback (NetDevice::ReceiveCallback cb); + virtual bool EnqueuePacket (Ptr packet, Mac48Address from, Mac48Address to, uint16_t protocolNumber, uint32_t destId); + + virtual Address GetMulticast (Ipv6Address addr) const; + + virtual void SetPromiscReceiveCallback (PromiscReceiveCallback cb); + virtual bool SupportsSendFrom (void) const; + + /** + * TracedCallback signature for packet events + * + * \param [in] p Packet pointer + * \param [in] from The sender address + * \param [in] to The receiver address + * \param [in] proto The protocol number + */ + typedef void (*PacketEventTracedCallback)(Ptr p, Mac48Address from, Mac48Address to, uint16_t proto); + + /** + * TracedCallback signature for queue latency reports + * + * \param [in] p Packet pointer + * \param [in] latency The observed latency + */ + typedef void (*QueueLatencyTracedCallback)(Ptr p, Time latency); + +protected: + virtual void DoDispose (void); +private: + Ptr m_channel; + NetDevice::ReceiveCallback m_rxCallback; + NetDevice::PromiscReceiveCallback m_promiscCallback; + Ptr m_node; + uint16_t m_mtu; + uint32_t m_ifIndex; + Mac48Address m_address; + Ptr m_receiveErrorModel; + + Ptr m_currentPkt; + + /** + * Start Sending a Packet Down the Wire. + * + * The TransmitStart method is the method that is used internally in the + * NetDevice to begin the process of sending a packet out on + * the channel. The corresponding method is called on the channel to let + * it know that the physical device this class represents has virtually + * started sending signals. An event is scheduled for the time at which + * the bits have been completely transmitted. + */ + void TransmitStart (Ptr); + + /** + * Stop Sending a Packet Down the Wire and Begin the Interframe Gap. + * + * The TransmitComplete method is used internally to finish the process + * of sending a packet out on the channel. + */ + void TransmitComplete (void); + + /** + * Enumeration of the states of the transmit machine of the net device. + */ + enum TxMachineState + { + READY, /**< The transmitter is ready to begin transmission of a packet */ + BUSY /**< The transmitter is busy transmitting a packet */ + }; + /** + * The state of the Net Device transmit state machine. + * @see TxMachineState + */ + TxMachineState m_txMachineState; + + + /** + * The data rate that the Net Device uses to simulate packet transmission + * timing. + * @see class DataRate + */ + DataRate m_bps; + + /** + * The Queue which this device uses as a packet source. + * Management of this Queue has been delegated to the device + * and it has the responsibility for deletion. + * @see class Queue + * @see class DropTailQueue + */ + Ptr > m_queue; + + /** + * The trace source fired when a packet begins the reception process from + * the medium. + * + * \see class CallBackTraceSource + */ + TracedCallback, Mac48Address, Mac48Address, uint16_t > m_phyRxBeginTrace; + + /** + * The trace source fired when a packet ends the reception process from + * the medium. + * + * \see class CallBackTraceSource + */ + TracedCallback, Mac48Address, Mac48Address, uint16_t > m_phyRxEndTrace; + + /** + * The trace source fired when the phy layer drops a packet it has received + * due to the error model being active. Although SimpleWirelessNetDevice doesn't + * really have a Phy model, we choose this trace source name for alignment + * with other trace sources. + * + * \see class CallBackTraceSource + */ + TracedCallback, Mac48Address, Mac48Address, uint16_t > m_phyRxDropTrace; + + /** + * A trace source that emulates a promiscuous mode protocol sniffer connected + * to the device. This trace source fire on packets destined for any host + * just like your average everyday packet sniffer. + * + * The trace is captured on send and receive. + * + * \see class CallBackTraceSource + */ + TracedCallback > m_promiscSnifferTrace; + + /** + * The trace source fired when a packet begins the transmission process on + * the medium. + * + * \see class CallBackTraceSource + */ + TracedCallback, Mac48Address, Mac48Address, uint16_t > m_TxBeginTrace; + + /** + * The trace source fired when a packet is dequeued to be sent. + * It does NOT track queue latency for packets that get dropped + * in the queue only that that are actually sent from the queue + * + * \see class CallBackTraceSource + */ + TracedCallback, Time> m_QueueLatencyTrace; + + /** + * The trace source fired when packets come into the "top" of the device + * at the L3/L2 transition, before being queued for transmission. + * + * \see class CallBackTraceSource + */ + TracedCallback > m_macTxTrace; + + /** + * The trace source fired for packets successfully received by the device + * immediately before being forwarded up to higher layers (at the L2/L3 + * transition). This is a non- promiscuous trace. + * + * \see class CallBackTraceSource + */ + TracedCallback > m_macRxTrace; + + + uint32_t m_pktRcvTotal; + uint32_t m_pktRcvDrop; + bool m_pcapEnabled; + + bool m_fixedNbrListEnabled; + std::map mDirectionalNbrs; + + int m_nbrCount; +}; + +} // namespace ns3 + +#endif /* SIMPLE_WIRELESS_NET_DEVICE_H */ diff --git a/wscript b/wscript index 31126db..09ae499 100644 --- a/wscript +++ b/wscript @@ -1,23 +1,23 @@ -## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- - -def build(bld): - obj = bld.create_ns3_module('simple-wireless', ['network']) - obj.source = [ - 'model/simple-wireless-net-device.cc', - 'model/simple-wireless-channel.cc', - 'model/drop-head-queue.cc', - 'model/priority-queue.cc', - ] - headers = bld(features='ns3header') - headers.module = 'simple-wireless' - headers.source = [ - 'model/simple-wireless-net-device.h', - 'model/simple-wireless-channel.h', - 'model/drop-head-queue.h', - 'model/priority-queue.h', - ] - obj.env.append_value("LIB", ["pcap"]) - - if (bld.env['ENABLE_EXAMPLES']): - bld.recurse('examples') - +## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*- + +def build(bld): + obj = bld.create_ns3_module('simple-wireless', ['network']) + obj.source = [ + 'model/simple-wireless-net-device.cc', + 'model/simple-wireless-channel.cc', + 'model/drop-head-queue.cc', + 'model/priority-queue.cc', + ] + headers = bld(features='ns3header') + headers.module = 'simple-wireless' + headers.source = [ + 'model/simple-wireless-net-device.h', + 'model/simple-wireless-channel.h', + 'model/drop-head-queue.h', + 'model/priority-queue.h', + ] + obj.env.append_value("LIB", ["pcap"]) + + if (bld.env['ENABLE_EXAMPLES']): + bld.recurse('examples') +