14Python port of tcp-bbr-example.cc
16Simulates the following topology:
18 Sender ---- R1 ---- R2 ---- Receiver
19 1000Mbps 10Mbps 1000Mbps
23- cwnd.dat (congestion window)
24- throughput.dat (throughput)
25- queueSize.dat (queue length)
34except ModuleNotFoundError:
36 "Error: ns3 Python module not found. "
37 "Bindings may not be enabled or PYTHONPATH is incorrect."
50 """Throughput trace callback."""
51 global prev_tx, prev_time, throughput_file
53 stats = ns.cppyy.gbl.monitor_ptr.GetFlowStats()
54 if stats
and not stats.empty():
55 flow_stats = stats.begin().__deref__().second
58 bits = 8 * (flow_stats.txBytes - prev_tx)
59 us = (cur_time - prev_time).ToDouble(ns.Time.US)
62 throughput_file.write(f
"{cur_time.GetSeconds():.6g}s {bits / us:.6g} Mbps\n")
63 throughput_file.flush()
66 prev_tx = flow_stats.txBytes
70 """Queue length tracer."""
73 q = ns.cppyy.gbl.qdisc_ptr.GetCurrentSize().GetValue()
74 queue_file.write(f
"{ns.Simulator.Now().GetSeconds():.6g} {q}\n")
79 """Congestion window tracer."""
82 cwnd_file.write(f
"{ns.Simulator.Now().GetSeconds():.6g} {newval / 1448.0:.6g}\n")
88#include "ns3/simulator.h"
89#include "ns3/flow-monitor-helper.h"
90#include "ns3/queue-disc.h"
92#include "ns3/config.h"
96Ptr<FlowMonitor> monitor_ptr;
97Ptr<QueueDisc> qdisc_ptr;
99// Helper to create event from Python callback without parameters
100EventImpl* pythonMakeEvent(void (*f)())
105// Helper to connect cwnd callback and create event
106EventImpl* pythonConnectCwndTrace(void (*f)(uint32_t, uint32_t))
108 Config::ConnectWithoutContext(
109 "/NodeList/0/$ns3::TcpL4Protocol/SocketList/0/CongestionWindow",
117 global throughput_file, queue_file, cwnd_file, outdir, prev_time
120 parser = argparse.ArgumentParser(description=
"tcp-bbr-example (Python)")
124 help=
"Transport protocol: TcpNewReno, TcpBbr",
126 parser.add_argument(
"--delAckCount", type=int, default=2, help=
"Delayed ACK count")
127 parser.add_argument(
"--enablePcap", action=
"store_true", help=
"Enable pcap traces")
128 parser.add_argument(
"--stopTime", type=float, default=100.0, help=
"Simulation stop time")
129 args = parser.parse_args()
131 ts = time.strftime(
"%d-%m-%Y-%I-%M-%S")
132 outdir = f
"bbr-results/{ts}/"
133 os.makedirs(outdir, exist_ok=
True)
135 tcpType = args.tcpTypeId
136 queueDisc =
"ns3::FifoQueueDisc"
137 delAck = args.delAckCount
138 enablePcap = args.enablePcap
139 stopTime = ns.Seconds(args.stopTime)
141 ns.Config.SetDefault(
142 "ns3::TcpL4Protocol::SocketType",
143 ns.StringValue(
"ns3::" + tcpType),
145 ns.Config.SetDefault(
"ns3::TcpSocket::SndBufSize", ns.UintegerValue(4194304))
146 ns.Config.SetDefault(
"ns3::TcpSocket::RcvBufSize", ns.UintegerValue(6291456))
147 ns.Config.SetDefault(
"ns3::TcpSocket::InitialCwnd", ns.UintegerValue(10))
148 ns.Config.SetDefault(
"ns3::TcpSocket::DelAckCount", ns.UintegerValue(delAck))
149 ns.Config.SetDefault(
"ns3::TcpSocket::SegmentSize", ns.UintegerValue(1448))
150 ns.Config.SetDefault(
151 "ns3::DropTailQueue<Packet>::MaxSize", ns.QueueSizeValue(ns.QueueSize(
"1p"))
153 ns.Config.SetDefault(
154 queueDisc +
"::MaxSize",
155 ns.QueueSizeValue(ns.QueueSize(
"100p")),
158 sender = ns.NodeContainer()
159 receiver = ns.NodeContainer()
160 routers = ns.NodeContainer()
165 bottleneck = ns.PointToPointHelper()
166 bottleneck.SetDeviceAttribute(
"DataRate", ns.StringValue(
"10Mbps"))
167 bottleneck.SetChannelAttribute(
"Delay", ns.StringValue(
"10ms"))
169 edge = ns.PointToPointHelper()
170 edge.SetDeviceAttribute(
"DataRate", ns.StringValue(
"1000Mbps"))
171 edge.SetChannelAttribute(
"Delay", ns.StringValue(
"5ms"))
173 senderEdge = edge.Install(sender.Get(0), routers.Get(0))
174 r1r2 = bottleneck.Install(routers.Get(0), routers.Get(1))
175 receiverEdge = edge.Install(routers.Get(1), receiver.Get(0))
177 inet = ns.InternetStackHelper()
179 inet.Install(receiver)
180 inet.Install(routers)
182 tch = ns.TrafficControlHelper()
183 tch.SetRootQueueDisc(queueDisc)
184 tch.SetQueueLimits(
"ns3::DynamicQueueLimits",
"HoldTime", ns.StringValue(
"1000ms"))
185 tch.Install(senderEdge)
186 tch.Install(receiverEdge)
188 ipv4 = ns.Ipv4AddressHelper()
189 ipv4.SetBase(ns.Ipv4Address(
"10.0.0.0"), ns.Ipv4Mask(
"255.255.255.0"))
191 _ = ipv4.Assign(r1r2)
194 ipv4.Assign(senderEdge)
197 ir1 = ipv4.Assign(receiverEdge)
199 ns.Ipv4GlobalRoutingHelper.PopulateRoutingTables()
203 source = ns.BulkSendHelper(
204 "ns3::TcpSocketFactory",
205 ns.InetSocketAddress(ir1.GetAddress(1), port).ConvertTo(),
207 source.SetAttribute(
"MaxBytes", ns.UintegerValue(0))
208 sourceApps = source.Install(sender.Get(0))
209 sourceApps.Start(ns.Seconds(0.1))
210 sourceApps.Stop(stopTime)
212 sink = ns.PacketSinkHelper(
213 "ns3::TcpSocketFactory",
214 ns.InetSocketAddress(ns.Ipv4Address.GetAny(), port).ConvertTo(),
216 sinkApps = sink.Install(receiver.Get(0))
217 sinkApps.Start(ns.Seconds(0))
218 sinkApps.Stop(stopTime)
221 os.makedirs(os.path.join(outdir,
"pcap"), exist_ok=
True)
223 throughput_file = open(os.path.join(outdir,
"throughput.dat"),
"w")
224 queue_file = open(os.path.join(outdir,
"queueSize.dat"),
"w")
225 cwnd_file = open(os.path.join(outdir,
"cwnd.dat"),
"w")
228 bottleneck.EnablePcapAll(os.path.join(outdir,
"pcap",
"bbr"),
True)
230 flowmon = ns.FlowMonitorHelper()
231 monitor = flowmon.InstallAll()
233 tch.Uninstall(routers.Get(0).GetDevice(1))
234 qdc = tch.Install(routers.Get(0).GetDevice(1))
239 ns.cppyy.gbl.monitor_ptr = monitor
240 ns.cppyy.gbl.qdisc_ptr = qdc.Get(0)
243 def throughput_tracer():
244 """Periodic throughput tracer that reschedules itself."""
246 event = ns.cppyy.gbl.pythonMakeEvent(throughput_tracer)
247 ns.Simulator.Schedule(ns.Seconds(0.2), event)
249 def queue_size_tracer():
250 """Periodic queue size tracer that reschedules itself."""
252 event = ns.cppyy.gbl.pythonMakeEvent(queue_size_tracer)
253 ns.Simulator.Schedule(ns.Seconds(0.2), event)
256 event = ns.cppyy.gbl.pythonMakeEvent(throughput_tracer)
257 ns.Simulator.Schedule(ns.Seconds(0.000001), event)
259 event = ns.cppyy.gbl.pythonMakeEvent(queue_size_tracer)
260 ns.Simulator.ScheduleNow(event)
263 def connect_cwnd_trace():
264 """Connect the cwnd trace callback."""
265 ns.cppyy.gbl.pythonConnectCwndTrace(trace_cwnd_callback)
267 event = ns.cppyy.gbl.pythonMakeEvent(connect_cwnd_trace)
268 ns.Simulator.Schedule(ns.Seconds(0.1) + ns.MilliSeconds(1), event)
270 ns.Simulator.Stop(stopTime + ns.TimeStep(1))
272 ns.Simulator.Destroy()
274 throughput_file.close()
279if __name__ ==
"__main__":
check_queue_size_callback()
trace_throughput_callback()
trace_cwnd_callback(oldval, newval)