Created
July 17, 2020 13:32
-
-
Save buihaduong/78a515c09d77f3d226cd833c855466d3 to your computer and use it in GitHub Desktop.
Simple wireless LAN network simulation using ns-3. Based on wifi-simple-adhoc-grid.cc example.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- Mode: Python; -*- | |
# /* | |
# * Copyright (c) 2009 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 | |
# * | |
# * Based on wifi-simple-adhoc-grid.cc example | |
# * Ported to Python by Bui Ha Duong | |
# */ | |
''' | |
// This program configures a wireless network of n nodes (default 3 nodes) on an | |
// 802.11b physical layer, with | |
// 802.11b NICs in adhoc mode, and by default, sends one packet of 1000 | |
// (application) bytes to node 0. | |
// | |
// The default layout is like this | |
// | |
// n0 n1 n2 | |
// | |
// the layout is affected by the parameters given to GridPositionAllocator; | |
// by default, numNodes is 3 and GridWidth is set equal to numNodes. | |
// | |
// There are a number of command-line options available to control | |
// the default behavior. The list of available command-line options | |
// can be listed with the following command: | |
// ./waf --pyrun "wifi-simple-adhoc.py --help" | |
// | |
// Note that all ns-3 attributes (not just the ones exposed in the below | |
// script) can be changed at command line; see the ns-3 documentation. | |
// | |
// For instance, for this configuration, the physical layer will | |
// stop successfully receiving packets when distance increases beyond | |
// 650m. | |
// To see this effect, try running: | |
// | |
// ./waf --pyrun "wifi-simple-adhoc.py --distance=650" | |
// ./waf --pyrun "wifi-simple-adhoc.py --distance=1000" | |
// ./waf --pyrun "wifi-simple-adhoc.py --distance=1500" | |
// | |
// The source node and sink node can be changed like this: | |
// | |
// ./waf --pyrun "wifi-simple-adhoc.py --sourceNode=20 --sinkNode=10" | |
// | |
// This script can also be helpful to put the Wifi layer into verbose | |
// logging mode; this command will turn on all wifi logging: | |
// | |
// ./waf --pyrun "wifi-simple-adhoc.py --verbose=1" | |
// | |
// By default, trace file writing is off-- to enable it, try: | |
// ./waf --pyrun "wifi-simple-adhoc.py --tracing=1" | |
// | |
// When you are done tracing, you will notice many pcap trace files | |
// in your directory. If you have tcpdump installed, you can try this: | |
// | |
// tcpdump -r wifi-simple-adhoc-0-0.pcap -nn -tt | |
// | |
// grep Udp wifi-simple-adhoc.tr | grep -v olsr | |
''' | |
from __future__ import print_function | |
import ns.core | |
import ns.network | |
import ns.mobility | |
import ns.config_store | |
import ns.wifi | |
import ns.internet | |
import ns.applications | |
import ns.olsr | |
import ns.flow_monitor | |
import sys | |
def ReceivePacket(socket): | |
while socket.Recv(): | |
print ("Received one packet!") | |
def GenerateTraffic(socket, pktSize, pktCount, pktInterval): | |
if pktCount > 0: | |
socket.Send(ns.network.Packet(pktSize)) | |
ns.core.Simulator.Schedule(pktInterval, GenerateTraffic, socket, pktSize, pktCount-1, pktInterval) | |
print ("Sending one packet!") | |
else: | |
socket.Close() | |
def print_stats(os, st): | |
print (" Tx Bytes: ", st.txBytes, file=os) | |
print (" Rx Bytes: ", st.rxBytes, file=os) | |
print (" Tx Packets: ", st.txPackets, file=os) | |
print (" Rx Packets: ", st.rxPackets, file=os) | |
print (" Lost Packets: ", st.lostPackets, file=os) | |
if st.rxPackets > 0: | |
print (" Mean{Delay}: ", (st.delaySum.GetSeconds() / st.rxPackets), file=os) | |
# print (" Mean{Jitter}: ", (st.jitterSum.GetSeconds() / (st.rxPackets-1)), file=os) | |
print (" Mean{Hop Count}: ", float(st.timesForwarded) / st.rxPackets + 1, file=os) | |
def main(argv): | |
cmd = ns.core.CommandLine() | |
cmd.phyMode = "DsssRate1Mbps" | |
cmd.distance = 500 # m | |
cmd.packetSize = 1000 # bytes | |
cmd.numPackets = 1 | |
cmd.numNodes = 3 # by default, 3 nodes | |
cmd.sinkNode = 0 | |
cmd.sourceNode = cmd.numNodes - 1 | |
cmd.interval = 1.0 # seconds | |
cmd.verbose = False | |
cmd.tracing = False | |
cmd.AddValue ("phyMode", "Wifi Phy mode") | |
cmd.AddValue ("distance", "distance (m)") | |
cmd.AddValue ("packetSize", "size of application packet sent") | |
cmd.AddValue ("numPackets", "number of packets generated") | |
cmd.AddValue ("interval", "interval (seconds) between packets") | |
cmd.AddValue ("verbose", "turn on all WifiNetDevice log components") | |
cmd.AddValue ("tracing", "turn on ascii and pcap tracing") | |
cmd.AddValue ("numNodes", "number of nodes") | |
cmd.AddValue ("sinkNode", "Receiver node number") | |
cmd.AddValue ("sourceNode", "Sender node number") | |
cmd.Parse(sys.argv) | |
phyMode = cmd.phyMode | |
distance = int (cmd.distance) | |
packetSize = int (cmd.packetSize) | |
numPackets = int (cmd.numPackets) | |
numNodes = int (cmd.numNodes) | |
sinkNode = int (cmd.sinkNode) | |
sourceNode = numNodes - 1 | |
interval = float (cmd.interval) | |
verbose = cmd.verbose | |
tracing = cmd.tracing | |
# Convert to time object | |
interPacketInterval = ns.core.Seconds(interval) | |
# disable fragmentation for frames below 2200 bytes | |
ns.core.Config.SetDefault ("ns3::WifiRemoteStationManager::FragmentationThreshold", ns.core.StringValue ("2200")) | |
# turn off RTS/CTS for frames below 2200 bytes | |
ns.core.Config.SetDefault ("ns3::WifiRemoteStationManager::RtsCtsThreshold", ns.core.StringValue ("2200")) | |
# Fix non-unicast data rate to be the same as that of unicast | |
ns.core.Config.SetDefault ("ns3::WifiRemoteStationManager::NonUnicastMode", ns.core.StringValue (phyMode)) | |
# 1. Create nodes | |
nodes = ns.network.NodeContainer() | |
nodes.Create (numNodes) | |
# 2. Set position for nodes | |
mobility = ns.mobility.MobilityHelper() | |
mobility.SetPositionAllocator("ns3::GridPositionAllocator", | |
"MinX", ns.core.DoubleValue (0.0), | |
"MinY", ns.core.DoubleValue (0.0), | |
"DeltaX", ns.core.DoubleValue (distance), | |
"DeltaY", ns.core.DoubleValue (distance), | |
"GridWidth", ns.core.UintegerValue (numNodes), | |
"LayoutType", ns.core.StringValue ("RowFirst")) | |
mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel") | |
mobility.Install (nodes) | |
# 3. Create & setup wifi channel | |
wifiChannel = ns.wifi.YansWifiChannelHelper() | |
wifiChannel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel") | |
wifiChannel.AddPropagationLoss ("ns3::FriisPropagationLossModel") | |
# 4. Install wireless devices | |
wifi = ns.wifi.WifiHelper() | |
wifi.SetStandard(ns.wifi.WIFI_PHY_STANDARD_80211b) | |
wifi.SetRemoteStationManager ("ns3::ConstantRateWifiManager", | |
"DataMode", ns.core.StringValue (phyMode), | |
"ControlMode", ns.core.StringValue (phyMode)) | |
if verbose: | |
wifi.EnableLogComponents() | |
wifiPhy = ns.wifi.YansWifiPhyHelper.Default() | |
wifiPhy.SetChannel (wifiChannel.Create()) | |
# set it to zero; otherwise, gain will be added | |
wifiPhy.Set ("RxGain", ns.core.DoubleValue(-10)) | |
# ns-3 supports RadioTap and Prism tracing extensions for 802.11b | |
wifiPhy.SetPcapDataLinkType (ns.wifi.YansWifiPhyHelper.DLT_IEEE802_11_RADIO) | |
wifiMac = ns.wifi.WifiMacHelper() | |
# use ad-hoc MAC | |
wifiMac.SetType("ns3::AdhocWifiMac") | |
devices = wifi.Install (wifiPhy, wifiMac, nodes) | |
# Enable OLSR | |
olsr = ns.olsr.OlsrHelper() | |
staticRouting = ns.internet.Ipv4StaticRoutingHelper() | |
listRouting = ns.internet.Ipv4ListRoutingHelper() | |
listRouting.Add (staticRouting, 0) | |
listRouting.Add (olsr, 10) | |
# 6. Install TCP/IP stack & assign IP addresses | |
internet = ns.internet.InternetStackHelper() | |
internet.SetRoutingHelper(listRouting) | |
internet.Install(nodes) | |
internet.Reset() | |
ipv4 = ns.internet.Ipv4AddressHelper() | |
ipv4.SetBase(ns.network.Ipv4Address("10.1.1.0"), ns.network.Ipv4Mask("255.255.255.0")) | |
interfaces = ipv4.Assign (devices) | |
# 7. Install applications | |
appSource = ns.network.NodeList.GetNode(sourceNode) | |
appSink = ns.network.NodeList.GetNode(sinkNode) | |
sink = ns.network.Socket.CreateSocket(appSink, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")) | |
sink.Bind(ns.network.InetSocketAddress(ns.network.Ipv4Address.GetAny(), 4477)) | |
sink.SetRecvCallback(ReceivePacket) | |
source = ns.network.Socket.CreateSocket(appSource, ns.core.TypeId.LookupByName("ns3::UdpSocketFactory")) | |
source.Connect(ns.network.InetSocketAddress(interfaces.GetAddress(sinkNode), 4477)) | |
if tracing: | |
ascii = ns.network.AsciiTraceHelper() | |
wifiPhy.EnableAsciiAll(ascii.CreateFileStream ("wifi-simple-adhoc.tr")) | |
wifiPhy.EnablePcap ("wifi-simple-adhoc", devices) | |
# Give OLSR time to converge-- 30 seconds perhaps | |
ns.core.Simulator.Schedule(ns.core.Seconds(30), | |
GenerateTraffic, source, packetSize, numPackets, interPacketInterval) | |
# 8. Install FlowMonitor on all nodes | |
flowmon_helper = ns.flow_monitor.FlowMonitorHelper() | |
monitor = flowmon_helper.InstallAll() | |
monitor = flowmon_helper.GetMonitor() | |
monitor.SetAttribute("DelayBinWidth", ns.core.DoubleValue(0.001)) | |
monitor.SetAttribute("JitterBinWidth", ns.core.DoubleValue(0.001)) | |
monitor.SetAttribute("PacketSizeBinWidth", ns.core.DoubleValue(20)) | |
# 9. Run simulation for 44 seconds | |
ns.core.Simulator.Stop(ns.core.Seconds(44.0)) | |
ns.core.Simulator.Run() | |
# 10. Print per flow statistics | |
monitor.CheckForLostPackets() | |
classifier = flowmon_helper.GetClassifier() | |
for flow_id, flow_stats in monitor.GetFlowStats(): | |
t = classifier.FindFlow(flow_id) | |
proto = {6: 'TCP', 17: 'UDP'} [t.protocol] | |
print ("FlowID: %i (%s %s/%s --> %s/%i)" % \ | |
(flow_id, proto, t.sourceAddress, t.sourcePort, t.destinationAddress, t.destinationPort)) | |
print_stats(sys.stdout, flow_stats) | |
# 11. Cleanup | |
ns.core.Simulator.Destroy() | |
if __name__ == "__main__": | |
main(sys.argv) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment